Merge from trunk

This commit is contained in:
Charles Haley 2010-12-14 02:54:48 +00:00
commit f1911aa270
7 changed files with 190 additions and 9 deletions

View File

@ -73,6 +73,10 @@ class FB2MLizer(object):
text = re.sub(r'(?miu)<p>\s*</p>', '', text) text = re.sub(r'(?miu)<p>\s*</p>', '', text)
text = re.sub(r'(?miu)\s+</p>', '</p>', text) text = re.sub(r'(?miu)\s+</p>', '</p>', text)
text = re.sub(r'(?miu)</p><p>', '</p>\n\n<p>', text) text = re.sub(r'(?miu)</p><p>', '</p>\n\n<p>', text)
if self.opts.insert_blank_line:
text = re.sub(r'(?miu)</p>', '</p><empty-line />', text)
return text return text
def fb2_header(self): def fb2_header(self):
@ -293,6 +297,18 @@ class FB2MLizer(object):
s_out, s_tags = self.handle_simple_tag('emphasis', tag_stack+tags) s_out, s_tags = self.handle_simple_tag('emphasis', tag_stack+tags)
fb2_out += s_out fb2_out += s_out
tags += s_tags tags += s_tags
elif tag in ('del', 'strike'):
s_out, s_tags = self.handle_simple_tag('strikethrough', tag_stack+tags)
fb2_out += s_out
tags += s_tags
elif tag == 'sub':
s_out, s_tags = self.handle_simple_tag('sub', tag_stack+tags)
fb2_out += s_out
tags += s_tags
elif tag == 'sup':
s_out, s_tags = self.handle_simple_tag('sup', tag_stack+tags)
fb2_out += s_out
tags += s_tags
# Processes style information. # Processes style information.
if style['font-style'] == 'italic': if style['font-style'] == 'italic':
@ -303,6 +319,10 @@ class FB2MLizer(object):
s_out, s_tags = self.handle_simple_tag('strong', tag_stack+tags) s_out, s_tags = self.handle_simple_tag('strong', tag_stack+tags)
fb2_out += s_out fb2_out += s_out
tags += s_tags tags += s_tags
elif style['text-decoration'] == 'line-through':
s_out, s_tags = self.handle_simple_tag('strikethrough', tag_stack+tags)
fb2_out += s_out
tags += s_tags
# Process element text. # Process element text.
if hasattr(elem_tree, 'text') and elem_tree.text: if hasattr(elem_tree, 'text') and elem_tree.text:

View File

@ -154,15 +154,17 @@ class EditMetadataAction(InterfaceAction):
d.view_format.connect(lambda d.view_format.connect(lambda
fmt:self.gui.iactions['View'].view_format(row_list[current_row], fmt:self.gui.iactions['View'].view_format(row_list[current_row],
fmt)) fmt))
if d.exec_() != d.Accepted: ret = d.exec_()
d.view_format.disconnect() d.break_cycles()
if ret != d.Accepted:
break break
d.view_format.disconnect()
changed.add(d.id) changed.add(d.id)
if d.row_delta == 0: if d.row_delta == 0:
break break
current_row += d.row_delta current_row += d.row_delta
if changed: if changed:
self.gui.library_view.model().refresh_ids(list(changed)) self.gui.library_view.model().refresh_ids(list(changed))
current = self.gui.library_view.currentIndex() current = self.gui.library_view.currentIndex()

View File

@ -102,7 +102,7 @@ class MyBlockingBusy(QDialog):
remove_all, remove, add, au, aus, do_aus, rating, pub, do_series, \ remove_all, remove, add, au, aus, do_aus, rating, pub, do_series, \
do_autonumber, do_remove_format, remove_format, do_swap_ta, \ do_autonumber, do_remove_format, remove_format, do_swap_ta, \
do_remove_conv, do_auto_author, series, do_series_restart, \ do_remove_conv, do_auto_author, series, do_series_restart, \
series_start_value, do_title_case, clear_series = self.args series_start_value, do_title_case, cover_action, clear_series = self.args
# first loop: do author and title. These will commit at the end of each # first loop: do author and title. These will commit at the end of each
@ -129,6 +129,23 @@ class MyBlockingBusy(QDialog):
self.db.set_title(id, titlecase(title), notify=False) self.db.set_title(id, titlecase(title), notify=False)
if au: if au:
self.db.set_authors(id, string_to_authors(au), notify=False) self.db.set_authors(id, string_to_authors(au), notify=False)
if cover_action == 'remove':
self.db.remove_cover(id)
elif cover_action == 'generate':
from calibre.ebooks import calibre_cover
from calibre.ebooks.metadata import fmt_sidx
from calibre.gui2 import config
mi = self.db.get_metadata(id, index_is_id=True)
series_string = None
if mi.series:
series_string = _('Book %s of %s')%(
fmt_sidx(mi.series_index,
use_roman=config['use_roman_numerals_for_series_number']),
mi.series)
cdata = calibre_cover(mi.title, mi.format_field('authors')[-1],
series_string=series_string)
self.db.set_cover(id, cdata)
elif self.current_phase == 2: elif self.current_phase == 2:
# All of these just affect the DB, so we can tolerate a total rollback # All of these just affect the DB, so we can tolerate a total rollback
if do_auto_author: if do_auto_author:
@ -678,11 +695,16 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
do_remove_conv = self.remove_conversion_settings.isChecked() do_remove_conv = self.remove_conversion_settings.isChecked()
do_auto_author = self.auto_author_sort.isChecked() do_auto_author = self.auto_author_sort.isChecked()
do_title_case = self.change_title_to_title_case.isChecked() do_title_case = self.change_title_to_title_case.isChecked()
cover_action = None
if self.cover_remove.isChecked():
cover_action = 'remove'
elif self.cover_generate.isChecked():
cover_action = 'generate'
args = (remove_all, remove, add, au, aus, do_aus, rating, pub, do_series, args = (remove_all, remove, add, au, aus, do_aus, rating, pub, do_series,
do_autonumber, do_remove_format, remove_format, do_swap_ta, do_autonumber, do_remove_format, remove_format, do_swap_ta,
do_remove_conv, do_auto_author, series, do_series_restart, do_remove_conv, do_auto_author, series, do_series_restart,
series_start_value, do_title_case, clear_series) series_start_value, do_title_case, cover_action, clear_series)
bb = MyBlockingBusy(_('Applying changes to %d books.\nPhase {0} {1}%%.') bb = MyBlockingBusy(_('Applying changes to %d books.\nPhase {0} {1}%%.')
%len(self.ids), args, self.db, self.ids, %len(self.ids), args, self.db, self.ids,

View File

@ -381,7 +381,7 @@ Future conversion of these books will use the default settings.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="15" column="0" colspan="3"> <item row="14" column="0" colspan="3">
<spacer name="verticalSpacer_2"> <spacer name="verticalSpacer_2">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
@ -394,6 +394,39 @@ Future conversion of these books will use the default settings.</string>
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="13" column="0" colspan="3">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Change &amp;cover</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QRadioButton" name="cover_no_change">
<property name="text">
<string>&amp;No change</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="cover_remove">
<property name="text">
<string>&amp;Remove cover</string>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="cover_generate">
<property name="text">
<string>&amp;Generate default cover</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab"> <widget class="QWidget" name="tab">

View File

@ -293,6 +293,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
finally: finally:
self.fetch_cover_button.setEnabled(True) self.fetch_cover_button.setEnabled(True)
self.unsetCursor() self.unsetCursor()
if self.pi is not None:
self.pi.stop() self.pi.stop()
@ -442,7 +443,6 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
ResizableDialog.__init__(self, window) ResizableDialog.__init__(self, window)
self.cover_fetcher = None self.cover_fetcher = None
self.bc_box.layout().setAlignment(self.cover, Qt.AlignCenter|Qt.AlignHCenter) self.bc_box.layout().setAlignment(self.cover, Qt.AlignCenter|Qt.AlignHCenter)
self.cancel_all = False
base = unicode(self.author_sort.toolTip()) base = unicode(self.author_sort.toolTip())
self.ok_aus_tooltip = '<p>' + textwrap.fill(base+'<br><br>'+ self.ok_aus_tooltip = '<p>' + textwrap.fill(base+'<br><br>'+
_(' The green color indicates that the current ' _(' The green color indicates that the current '
@ -573,7 +573,6 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
QObject.connect(self.series, SIGNAL('editTextChanged(QString)'), self.enable_series_index) QObject.connect(self.series, SIGNAL('editTextChanged(QString)'), self.enable_series_index)
self.series.lineEdit().editingFinished.connect(self.increment_series_index) self.series.lineEdit().editingFinished.connect(self.increment_series_index)
self.show()
pm = QPixmap() pm = QPixmap()
if cover: if cover:
pm.loadFromData(cover) pm.loadFromData(cover)
@ -593,6 +592,8 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
self.original_author = unicode(self.authors.text()).strip() self.original_author = unicode(self.authors.text()).strip()
self.original_title = unicode(self.title.text()).strip() self.original_title = unicode(self.title.text()).strip()
self.show()
def create_custom_column_editors(self): def create_custom_column_editors(self):
w = self.central_widget.widget(1) w = self.central_widget.widget(1)
layout = w.layout() layout = w.layout()
@ -907,3 +908,48 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
dynamic.set('metasingle_window_geometry', bytes(self.saveGeometry())) dynamic.set('metasingle_window_geometry', bytes(self.saveGeometry()))
dynamic.set('metasingle_splitter_state', dynamic.set('metasingle_splitter_state',
bytes(self.splitter.saveState())) bytes(self.splitter.saveState()))
def break_cycles(self):
# Break any reference cycles that could prevent python
# from garbage collecting this dialog
def disconnect(signal):
try:
signal.disconnect()
except:
pass # Fails if view format was never connected
disconnect(self.view_format)
for b in ('next_button', 'prev_button'):
x = getattr(self, b, None)
if x is not None:
disconnect(x.clicked)
if __name__ == '__main__':
from calibre.library import db
from PyQt4.Qt import QApplication
from calibre.utils.mem import memory
import gc
app = QApplication([])
db = db()
# Initialize all Qt Objects once
d = MetadataSingleDialog(None, 4, db)
d.break_cycles()
d.reject()
del d
for i in range(5):
gc.collect()
before = memory()
d = MetadataSingleDialog(None, 4, db)
d.reject()
d.break_cycles()
del d
for i in range(5):
gc.collect()
print 'Used memory:', memory(before)/1024.**2, 'MB'

View File

@ -253,6 +253,7 @@ def do_save_book_to_disk(id_, mi, cover, plugboards,
if not os.path.exists(dirpath): if not os.path.exists(dirpath):
raise raise
ocover = mi.cover
if opts.save_cover and cover and os.access(cover, os.R_OK): if opts.save_cover and cover and os.access(cover, os.R_OK):
with open(base_path+'.jpg', 'wb') as f: with open(base_path+'.jpg', 'wb') as f:
with open(cover, 'rb') as s: with open(cover, 'rb') as s:
@ -266,6 +267,8 @@ def do_save_book_to_disk(id_, mi, cover, plugboards,
with open(base_path+'.opf', 'wb') as f: with open(base_path+'.opf', 'wb') as f:
f.write(opf) f.write(opf)
mi.cover = ocover
written = False written = False
for fmt in formats: for fmt in formats:
global plugboard_save_to_disk_value, plugboard_any_format_value global plugboard_save_to_disk_value, plugboard_any_format_value

55
src/calibre/utils/mem.py Normal file
View File

@ -0,0 +1,55 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
## {{{ http://code.activestate.com/recipes/286222/ (r1)
import os
_proc_status = '/proc/%d/status' % os.getpid()
_scale = {'kB': 1024.0, 'mB': 1024.0*1024.0,
'KB': 1024.0, 'MB': 1024.0*1024.0}
def _VmB(VmKey):
'''Private.
'''
global _proc_status, _scale
# get pseudo file /proc/<pid>/status
try:
t = open(_proc_status)
v = t.read()
t.close()
except:
return 0.0 # non-Linux?
# get VmKey line e.g. 'VmRSS: 9999 kB\n ...'
i = v.index(VmKey)
v = v[i:].split(None, 3) # whitespace
if len(v) < 3:
return 0.0 # invalid format?
# convert Vm value to bytes
return float(v[1]) * _scale[v[2]]
def memory(since=0.0):
'''Return memory usage in bytes.
'''
return _VmB('VmSize:') - since
def resident(since=0.0):
'''Return resident memory usage in bytes.
'''
return _VmB('VmRSS:') - since
def stacksize(since=0.0):
'''Return stack size in bytes.
'''
return _VmB('VmStk:') - since
## end of http://code.activestate.com/recipes/286222/ }}}