mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
f1911aa270
@ -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:
|
||||||
|
@ -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()
|
||||||
|
@ -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,
|
||||||
|
@ -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 &cover</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="cover_no_change">
|
||||||
|
<property name="text">
|
||||||
|
<string>&No change</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="cover_remove">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Remove cover</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="cover_generate">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Generate default cover</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="tab">
|
<widget class="QWidget" name="tab">
|
||||||
|
@ -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'
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
55
src/calibre/utils/mem.py
Normal 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/ }}}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user