From b64092f881e15d2cddb4370576558273344b101f Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 5 May 2010 12:17:58 -0600 Subject: [PATCH 1/3] Move update check into its own thread --- src/calibre/gui2/ui.py | 8 +++---- src/calibre/gui2/update.py | 46 +++++++++++++++++--------------------- 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index b35270f963..ccbe04db9f 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -258,9 +258,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.device_info = ' ' if not opts.no_update_check: self.update_checker = CheckForUpdates(self) - QObject.connect(self.update_checker, - SIGNAL('update_found(PyQt_PyObject)'), self.update_found) - self.update_checker.start(2000) + self.update_checker.update_found.connect(self.update_found, + type=Qt.QueuedConnection) + self.update_checker.start() ####################### Status Bar ##################### self.status_bar.initialize(self.system_tray_icon) self.status_bar.show_book_info.connect(self.show_book_info) @@ -2493,7 +2493,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): if write_settings: self.write_settings() self.check_messages_timer.stop() - self.update_checker.stop() + self.update_checker.terminate() self.listener.close() self.job_manager.server.close() while self.spare_servers: diff --git a/src/calibre/gui2/update.py b/src/calibre/gui2/update.py index 69337bb494..92e9db1cf2 100644 --- a/src/calibre/gui2/update.py +++ b/src/calibre/gui2/update.py @@ -3,7 +3,7 @@ __copyright__ = '2008, Kovid Goyal ' import traceback -from PyQt4.QtCore import QObject, SIGNAL, QTimer +from PyQt4.QtCore import QThread, pyqtSignal import mechanize from calibre.constants import __version__, iswindows, isosx @@ -12,31 +12,27 @@ from calibre.utils.config import prefs URL = 'http://status.calibre-ebook.com/latest' -class CheckForUpdates(QObject): +class CheckForUpdates(QThread): + + update_found = pyqtSignal(object) + INTERVAL = 24*60*60 def __init__(self, parent): - QObject.__init__(self, parent) - self.timer = QTimer(self) - self.first = True - self.connect(self.timer, SIGNAL('timeout()'), self) - self.start = self.timer.start - self.stop = self.timer.stop + QThread.__init__(self, parent) - def __call__(self): - if self.first: - self.timer.setInterval(1000*24*60*60) - self.first = False - - try: - br = browser() - req = mechanize.Request(URL) - req.add_header('CALIBRE_VERSION', __version__) - req.add_header('CALIBRE_OS', - 'win' if iswindows else 'osx' if isosx else 'oth') - req.add_header('CALIBRE_INSTALL_UUID', prefs['installation_uuid']) - version = br.open(req).read().strip() - if version and version != __version__: - self.emit(SIGNAL('update_found(PyQt_PyObject)'), version) - except: - traceback.print_exc() + def run(self): + while True: + try: + br = browser() + req = mechanize.Request(URL) + req.add_header('CALIBRE_VERSION', __version__) + req.add_header('CALIBRE_OS', + 'win' if iswindows else 'osx' if isosx else 'oth') + req.add_header('CALIBRE_INSTALL_UUID', prefs['installation_uuid']) + version = br.open(req).read().strip() + if version and version != __version__: + self.update_found.emit(version) + except: + traceback.print_exc() + self.sleep(self.INTERVAL) From 9e8d7a365349999d0294d81503746d36b6e2c3ec Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 5 May 2010 12:35:59 -0600 Subject: [PATCH 2/3] Framework for bulk metadata edits of custom columns --- src/calibre/gui2/custom_column_widgets.py | 129 ++++++++++++++++++---- src/calibre/gui2/dialogs/metadata_bulk.py | 15 ++- 2 files changed, 118 insertions(+), 26 deletions(-) diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index 79faff3bb9..2c5b274d26 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -6,6 +6,7 @@ __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' import sys +from functools import partial from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \ QDate, QGroupBox, QVBoxLayout, QPlainTextEdit, QSizePolicy, \ @@ -18,10 +19,11 @@ from calibre.utils.config import tweaks class Base(object): - def __init__(self, db, col_id): + def __init__(self, db, col_id, parent=None): self.db, self.col_id = db, col_id self.col_metadata = db.custom_column_num_map[col_id] self.initial_val = None + self.setup_ui(parent) def initialize(self, book_id): val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True) @@ -43,8 +45,7 @@ class Base(object): class Bool(Base): - def __init__(self, db, col_id, parent=None): - Base.__init__(self, db, col_id) + def setup_ui(self, parent): self.widgets = [QLabel('&'+self.col_metadata['name'], parent), QComboBox(parent)] w = self.widgets[1] @@ -69,8 +70,7 @@ class Bool(Base): class Int(Base): - def __init__(self, db, col_id, parent=None): - Base.__init__(self, db, col_id) + def setup_ui(self, parent): self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), QSpinBox(parent)] w = self.widgets[1] @@ -93,8 +93,7 @@ class Int(Base): class Float(Int): - def __init__(self, db, col_id, parent=None): - Base.__init__(self, db, col_id) + def setup_ui(self, parent): self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), QDoubleSpinBox(parent)] w = self.widgets[1] @@ -103,8 +102,8 @@ class Float(Int): class Rating(Int): - def __init__(self, db, col_id, parent=None): - Int.__init__(self, db, col_id) + def setup_ui(self, parent): + Int.setup_ui(self, parent) w = self.widgets[1] w.setRange(0, 5) w.setSuffix(' '+_('stars')) @@ -125,8 +124,7 @@ class Rating(Int): class DateTime(Base): - def __init__(self, db, col_id, parent=None): - Base.__init__(self, db, col_id) + def setup_ui(self, parent): self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), QDateEdit(parent)] w = self.widgets[1] @@ -153,8 +151,7 @@ class DateTime(Base): class Comments(Base): - def __init__(self, db, col_id, parent=None): - Base.__init__(self, db, col_id) + def setup_ui(self, parent): self._box = QGroupBox(parent) self._box.setTitle('&'+self.col_metadata['name']) self._layout = QVBoxLayout() @@ -178,9 +175,8 @@ class Comments(Base): class Text(Base): - def __init__(self, db, col_id, parent=None): - Base.__init__(self, db, col_id) - values = self.all_values = list(self.db.all_custom(num=col_id)) + def setup_ui(self, parent): + values = self.all_values = list(self.db.all_custom(num=self.col_id)) values.sort(cmp = lambda x,y: cmp(x.lower(), y.lower())) if self.col_metadata['is_multiple']: w = TagsLineEdit(parent, values) @@ -238,16 +234,16 @@ widgets = { 'comments': Comments, } +def field_sort(y, z, x=None): + m1, m2 = x[y], x[z] + n1 = 'zzzzz' if m1['datatype'] == 'comments' else m1['name'] + n2 = 'zzzzz' if m2['datatype'] == 'comments' else m2['name'] + return cmp(n1.lower(), n2.lower()) + def populate_single_metadata_page(left, right, db, book_id, parent=None): x = db.custom_column_num_map cols = list(x) - def field_sort(y, z): - m1, m2 = x[y], x[z] - n1 = 'zzzzz' if m1['datatype'] == 'comments' else m1['name'] - n2 = 'zzzzz' if m2['datatype'] == 'comments' else m2['name'] - return cmp(n1.lower(), n2.lower()) - - cols.sort(cmp=field_sort) + cols.sort(cmp=partial(field_sort, x=x)) ans = [] for i, col in enumerate(cols): w = widgets[x[col]['datatype']](db, col, parent) @@ -275,6 +271,91 @@ def populate_single_metadata_page(left, right, db, book_id, parent=None): return ans, items -def populate_bulk_metadata_page(left, right, db, book_id, parent=None): +class BulkBase(Base): + + def get_initial_value(self, book_ids): + values = set([]) + for book_id in book_ids: + val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True) + if isinstance(val, list): + val = frozenset(val) + values.add(val) + if len(values) > 1: + break + ans = None + if len(values) == 1: + ans = iter(values).next() + if isinstance(ans, frozenset): + ans = list(ans) + return ans + + def initialize(self, book_ids): + self.initial_val = val = self.get_initial_value(book_ids) + val = self.normalize_db_val(val) + self.setter(val) + + def commit(self, book_ids, notify=False): + val = self.getter() + val = self.normalize_ui_val(val) + if val != self.initial_val: + for book_id in book_ids: + self.db.set_custom(book_id, val, num=self.col_id, notify=notify) + +class BulkBool(BulkBase, Bool): pass +class BulkRating(BulkBase, Rating): + pass + +class BulkInt(BulkBase, Int): + pass + +class BulkFloat(BulkBase, Float): + pass + +class BulkRating(BulkBase, Rating): + pass + +class BulkDateTime(BulkBase, DateTime): + pass + +class BulkText(BulkBase, Text): + pass + +bulk_widgets = { + 'bool' : BulkBool, + 'rating' : BulkRating, + 'int': BulkInt, + 'float': BulkFloat, + 'datetime': BulkDateTime, + 'text' : BulkText, +} + +def populate_bulk_metadata_page(layout, db, book_ids, parent=None): + x = db.custom_column_num_map + cols = list(x) + cols.sort(cmp=partial(field_sort, x=x)) + ans = [] + for i, col in enumerate(cols): + dt = x[col]['datatype'] + if dt == 'comments': + continue + w = bulk_widgets[dt](db, col, parent) + ans.append(w) + w.initialize(book_ids) + row = layout.rowCount() + if len(w.widgets) == 1: + layout.addWidget(w.widgets[0], row, 0, 1, -1) + else: + w.widgets[0].setBuddy(w.widgets[1]) + for c, widget in enumerate(w.widgets): + layout.addWidget(widget, row, c) + items = [] + if len(ans) > 0: + items.append(QSpacerItem(10, 10, QSizePolicy.Minimum, + QSizePolicy.Expanding)) + layout.addItem(items[-1], layout.rowCount(), 0, 1, 1) + layout.setRowStretch(layout.rowCount()-1, 100) + + return ans, items + diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index 3e2f98af71..10c7387423 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -3,8 +3,9 @@ __copyright__ = '2008, Kovid Goyal ' '''Dialog to edit metadata in bulk''' +import sip from PyQt4.QtCore import SIGNAL, QObject -from PyQt4.QtGui import QDialog +from PyQt4.QtGui import QDialog, QGridLayout from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog from calibre.gui2.dialogs.tag_editor import TagEditor @@ -48,7 +49,17 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): self.exec_() def create_custom_column_editors(self): - pass + w = self.central_widget.widget(1) + layout = QGridLayout() + + self.custom_column_widgets, self.__cc_spacers = populate_bulk_metadata_page( + layout, self.db, self.ids, w) + #sip.delete(w.layout()) + w.setLayout(layout) + self.__custom_col_layouts = [layout] + ans = self.custom_column_widgets + for i in range(len(ans)-1): + w.setTabOrder(ans[i].widgets[-1], ans[i+1].widgets[-1]) def initialize_combos(self): self.initalize_authors() From 58b59eb7e41a37ded0beab4567488a422dcf70dc Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 5 May 2010 14:45:48 -0600 Subject: [PATCH 3/3] ... --- src/calibre/gui2/custom_column_widgets.py | 18 +++++++++++++++++- src/calibre/gui2/dialogs/metadata_bulk.py | 5 +++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index 2c5b274d26..35d9f04e1f 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -320,7 +320,23 @@ class BulkDateTime(BulkBase, DateTime): pass class BulkText(BulkBase, Text): - pass + + def initialize(self, book_ids): + val = self.get_initial_value(book_ids) + self.initial_val = val = self.normalize_db_val(val) + if self.col_metadata['is_multiple']: + self.setter(val) + self.widgets[1].update_tags_cache(self.all_values) + else: + idx = None + for i, c in enumerate(self.all_values): + if c == val: + idx = i + self.widgets[1].addItem(c) + self.widgets[1].setEditText('') + if idx is not None: + self.widgets[1].setCurrentIndex(idx) + bulk_widgets = { 'bool' : BulkBool, diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index 10c7387423..788c8681a6 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -3,7 +3,6 @@ __copyright__ = '2008, Kovid Goyal ' '''Dialog to edit metadata in bulk''' -import sip from PyQt4.QtCore import SIGNAL, QObject from PyQt4.QtGui import QDialog, QGridLayout @@ -54,7 +53,6 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): self.custom_column_widgets, self.__cc_spacers = populate_bulk_metadata_page( layout, self.db, self.ids, w) - #sip.delete(w.layout()) w.setLayout(layout) self.__custom_col_layouts = [layout] ans = self.custom_column_widgets @@ -154,6 +152,9 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): self.db.set_authors(id, new_authors, notify=False) self.changed = True + for w in getattr(self, 'custom_column_widgets', []): + w.commit(self.ids) + def series_changed(self): self.write_series = True