diff --git a/src/calibre/ebooks/fb2/fb2ml.py b/src/calibre/ebooks/fb2/fb2ml.py
index 51bfaa7293..5efc360f1f 100644
--- a/src/calibre/ebooks/fb2/fb2ml.py
+++ b/src/calibre/ebooks/fb2/fb2ml.py
@@ -73,6 +73,10 @@ class FB2MLizer(object):
text = re.sub(r'(?miu)
\s*
', '', text)
text = re.sub(r'(?miu)\s+', '', text)
text = re.sub(r'(?miu)', '
\n\n', text)
+
+ if self.opts.insert_blank_line:
+ text = re.sub(r'(?miu)
', '', text)
+
return text
def fb2_header(self):
@@ -293,6 +297,18 @@ class FB2MLizer(object):
s_out, s_tags = self.handle_simple_tag('emphasis', tag_stack+tags)
fb2_out += s_out
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.
if style['font-style'] == 'italic':
@@ -303,6 +319,10 @@ class FB2MLizer(object):
s_out, s_tags = self.handle_simple_tag('strong', tag_stack+tags)
fb2_out += s_out
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.
if hasattr(elem_tree, 'text') and elem_tree.text:
diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py
index 57ca2a1880..f96c64080d 100644
--- a/src/calibre/gui2/__init__.py
+++ b/src/calibre/gui2/__init__.py
@@ -9,7 +9,7 @@ from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, \
QByteArray, QTranslator, QCoreApplication, QThread, \
QEvent, QTimer, pyqtSignal, QDate, QDesktopServices, \
QFileDialog, QMessageBox, QPixmap, QFileIconProvider, \
- QIcon, QApplication, QDialog, QPushButton, QUrl
+ QIcon, QApplication, QDialog, QPushButton, QUrl, QFont
ORG_NAME = 'KovidsBrain'
APP_UID = 'libprs500'
@@ -52,6 +52,7 @@ gprefs.defaults['show_splash_screen'] = True
gprefs.defaults['toolbar_icon_size'] = 'medium'
gprefs.defaults['toolbar_text'] = 'auto'
gprefs.defaults['show_child_bar'] = False
+gprefs.defaults['font'] = None
# }}}
@@ -613,6 +614,10 @@ class Application(QApplication):
qt_app = self
self._file_open_paths = []
self._file_open_lock = RLock()
+ self.original_font = QFont(QApplication.font())
+ fi = gprefs['font']
+ if fi is not None:
+ QApplication.setFont(QFont(*fi))
def _send_file_open_events(self):
with self._file_open_lock:
diff --git a/src/calibre/gui2/actions/edit_metadata.py b/src/calibre/gui2/actions/edit_metadata.py
index 60a943ccb9..11949632e9 100644
--- a/src/calibre/gui2/actions/edit_metadata.py
+++ b/src/calibre/gui2/actions/edit_metadata.py
@@ -154,15 +154,17 @@ class EditMetadataAction(InterfaceAction):
d.view_format.connect(lambda
fmt:self.gui.iactions['View'].view_format(row_list[current_row],
fmt))
- if d.exec_() != d.Accepted:
- d.view_format.disconnect()
+ ret = d.exec_()
+ d.break_cycles()
+ if ret != d.Accepted:
break
- d.view_format.disconnect()
+
changed.add(d.id)
if d.row_delta == 0:
break
current_row += d.row_delta
+
if changed:
self.gui.library_view.model().refresh_ids(list(changed))
current = self.gui.library_view.currentIndex()
diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py
index 30c964ca49..55c147ddd4 100644
--- a/src/calibre/gui2/dialogs/metadata_single.py
+++ b/src/calibre/gui2/dialogs/metadata_single.py
@@ -293,7 +293,8 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
finally:
self.fetch_cover_button.setEnabled(True)
self.unsetCursor()
- self.pi.stop()
+ if self.pi is not None:
+ self.pi.stop()
# }}}
@@ -442,7 +443,6 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
ResizableDialog.__init__(self, window)
self.cover_fetcher = None
self.bc_box.layout().setAlignment(self.cover, Qt.AlignCenter|Qt.AlignHCenter)
- self.cancel_all = False
base = unicode(self.author_sort.toolTip())
self.ok_aus_tooltip = '' + textwrap.fill(base+'
'+
_(' 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)
self.series.lineEdit().editingFinished.connect(self.increment_series_index)
- self.show()
pm = QPixmap()
if cover:
pm.loadFromData(cover)
@@ -593,6 +592,8 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
self.original_author = unicode(self.authors.text()).strip()
self.original_title = unicode(self.title.text()).strip()
+ self.show()
+
def create_custom_column_editors(self):
w = self.central_widget.widget(1)
layout = w.layout()
@@ -907,3 +908,48 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
dynamic.set('metasingle_window_geometry', bytes(self.saveGeometry()))
dynamic.set('metasingle_splitter_state',
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'
+
+
diff --git a/src/calibre/gui2/preferences/look_feel.py b/src/calibre/gui2/preferences/look_feel.py
index 10c2fcfe95..b2ba87d1e0 100644
--- a/src/calibre/gui2/preferences/look_feel.py
+++ b/src/calibre/gui2/preferences/look_feel.py
@@ -5,10 +5,11 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal '
__docformat__ = 'restructuredtext en'
+from PyQt4.Qt import QApplication, QFont, QFontInfo, QFontDialog
from calibre.gui2.preferences import ConfigWidgetBase, test_widget
from calibre.gui2.preferences.look_feel_ui import Ui_Form
-from calibre.gui2 import config, gprefs
+from calibre.gui2 import config, gprefs, qt_app
from calibre.utils.localization import available_translations, \
get_language, get_lang
from calibre.utils.config import prefs
@@ -56,12 +57,64 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
(_('Never'), 'never')]
r('toolbar_text', gprefs, choices=choices)
+ self.current_font = None
+ self.change_font_button.clicked.connect(self.change_font)
+
+
+ def initialize(self):
+ ConfigWidgetBase.initialize(self)
+ self.current_font = gprefs['font']
+ self.update_font_display()
+
+ def restore_defaults(self):
+ ConfigWidgetBase.restore_defaults(self)
+ ofont = self.current_font
+ self.current_font = None
+ if ofont is not None:
+ self.changed_signal.emit()
+ self.update_font_display()
+
+ def build_font_obj(self):
+ font_info = self.current_font
+ if font_info is not None:
+ font = QFont(*font_info)
+ else:
+ font = qt_app.original_font
+ return font
+
+ def update_font_display(self):
+ font = self.build_font_obj()
+ fi = QFontInfo(font)
+ name = unicode(fi.family())
+
+ self.font_display.setFont(font)
+ self.font_display.setText(_('Current font:') + ' ' + name +
+ ' [%dpt]'%fi.pointSize())
+
+ def change_font(self, *args):
+ fd = QFontDialog(self.build_font_obj(), self)
+ if fd.exec_() == fd.Accepted:
+ font = fd.selectedFont()
+ fi = QFontInfo(font)
+ self.current_font = (unicode(fi.family()), fi.pointSize(),
+ fi.weight(), fi.italic())
+ self.update_font_display()
+ self.changed_signal.emit()
+
+ def commit(self, *args):
+ rr = ConfigWidgetBase.commit(self, *args)
+ if self.current_font != gprefs['font']:
+ gprefs['font'] = self.current_font
+ QApplication.setFont(self.font_display.font())
+ rr = True
+ return rr
+
+
def refresh_gui(self, gui):
gui.search.search_as_you_type(config['search_as_you_type'])
-
+ self.update_font_display()
if __name__ == '__main__':
- from PyQt4.Qt import QApplication
app = QApplication([])
test_widget('Interface', 'Look & Feel')
diff --git a/src/calibre/gui2/preferences/look_feel.ui b/src/calibre/gui2/preferences/look_feel.ui
index 1de55d51ef..91f45a155f 100644
--- a/src/calibre/gui2/preferences/look_feel.ui
+++ b/src/calibre/gui2/preferences/look_feel.ui
@@ -183,7 +183,7 @@
- -
+
-
Qt::Vertical
@@ -196,6 +196,20 @@
+ -
+
+
+ true
+
+
+
+ -
+
+
+ Change &font (needs restart)
+
+
+
diff --git a/src/calibre/library/__init__.py b/src/calibre/library/__init__.py
index 8ff23c0a0a..177c5063ac 100644
--- a/src/calibre/library/__init__.py
+++ b/src/calibre/library/__init__.py
@@ -19,12 +19,15 @@ def generate_test_db(library_path,
max_tags=10
):
import random, string, os, sys, time
+ from calibre.constants import preferred_encoding
if not os.path.exists(library_path):
os.makedirs(library_path)
+ letters = string.letters.decode(preferred_encoding)
+
def randstr(length):
- return ''.join(random.choice(string.letters) for i in
+ return ''.join(random.choice(letters) for i in
xrange(length))
all_tags = [randstr(tag_length) for j in xrange(num_of_tags)]
diff --git a/src/calibre/utils/mem.py b/src/calibre/utils/mem.py
new file mode 100644
index 0000000000..f48aec34c6
--- /dev/null
+++ b/src/calibre/utils/mem.py
@@ -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 '
+__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//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/ }}}
+
+
+