diff --git a/setup/qt5-migrate.py b/setup/qt5-migrate.py index 5693e56695..c5bb637113 100644 --- a/setup/qt5-migrate.py +++ b/setup/qt5-migrate.py @@ -51,6 +51,8 @@ def detect_qvariant(): pat = re.compile(b'|'.join(br'QVariant NONE toDateTime toDate toInt toBool toString\(\) toPyObject canConvert toBitArray toByteArray toHash toFloat toMap toLine toPoint toReal toRect toTime toUInt toUrl'.split())) # noqa exclusions = { 'src/calibre/gui2/viewer/gestures.py': {'toPoint'}, + 'src/calibre/utils/serve_coffee.py': {'toString()'}, + 'src/calibre/gui2/job_indicator.py': {'toPoint'}, } for path in all_py_files(): if os.path.basename(path) in { diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 74c319039d..2265bc5e7d 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -146,7 +146,7 @@ def _config(): # {{{ c.add_opt('confirm_delete', default=False, help=_('Confirm before deleting')) c.add_opt('main_window_geometry', default=None, - help=_('Main window geometry')) # value QVariant.toByteArray + help=_('Main window geometry')) c.add_opt('new_version_notification', default=True, help=_('Notify when a new version is available')) c.add_opt('use_roman_numerals_for_series_number', default=True, diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index 46a36f05a8..87f7cdebc0 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -325,7 +325,7 @@ class BookInfo(QWebView): self._link_clicked = True if unicode(link.scheme()) in ('http', 'https'): return open_url(link) - link = unicode(link.toString()) + link = unicode(link.toString(QUrl.None)) self.link_clicked.emit(link) def turnoff_scrollbar(self, *args): @@ -349,7 +349,7 @@ class BookInfo(QWebView): p = self.page() mf = p.mainFrame() r = mf.hitTestContent(ev.pos()) - url = unicode(r.linkUrl().toString()).strip() + url = unicode(r.linkUrl().toString(QUrl.None)).strip() menu = p.createStandardContextMenu() ca = self.pageAction(p.Copy) for action in list(menu.actions()): diff --git a/src/calibre/gui2/comments_editor.py b/src/calibre/gui2/comments_editor.py index 4f989da7de..6307bdf6ad 100644 --- a/src/calibre/gui2/comments_editor.py +++ b/src/calibre/gui2/comments_editor.py @@ -211,7 +211,7 @@ class EditorWidget(QWebView): # {{{ return url = self.parse_link(link) if url.isValid(): - url = unicode(url.toString()) + url = unicode(url.toString(QUrl.None)) self.setFocus(Qt.OtherFocusReason) if is_image: self.exec_command('insertHTML', diff --git a/src/calibre/gui2/complete.py b/src/calibre/gui2/complete.py deleted file mode 100644 index 96b997d4a2..0000000000 --- a/src/calibre/gui2/complete.py +++ /dev/null @@ -1,213 +0,0 @@ -#!/usr/bin/env python -# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai - -__license__ = 'GPL v3' -__copyright__ = '2011, Kovid Goyal ' -__docformat__ = 'restructuredtext en' - -''' -WARNING: The code in this module is deprecated. Use complete2.py instead. This -code remains here for legacy plugin support. -''' - -from PyQt5.Qt import (QLineEdit, QAbstractListModel, Qt, - QApplication, QCompleter) - -from calibre.utils.icu import sort_key -from calibre.gui2 import NONE -from calibre.gui2.widgets import EnComboBox, LineEditECM - -class CompleteModel(QAbstractListModel): - - def __init__(self, parent=None): - QAbstractListModel.__init__(self, parent) - self.items = [] - self.sorting = QCompleter.UnsortedModel - - def set_items(self, items): - items = [unicode(x.strip()) for x in items] - self.beginResetModel() - if len(items) < 2500: - self.items = sorted(items, key=sort_key) - self.sorting = QCompleter.UnsortedModel - else: - self.items = sorted(items, key=lambda x:x.lower()) - self.sorting = QCompleter.CaseInsensitivelySortedModel - self.endResetModel() - - def rowCount(self, *args): - return len(self.items) - - def data(self, index, role): - if role == Qt.DisplayRole: - r = index.row() - try: - return self.items[r] - except IndexError: - pass - return NONE - - -class MultiCompleteLineEdit(QLineEdit, LineEditECM): - ''' - A line edit that completes on multiple items separated by a - separator. Use the :meth:`update_items_cache` to set the list of - all possible completions. Separator can be controlled with the - :meth:`set_separator` and :meth:`set_space_before_sep` methods. - - A call to self.set_separator(None) will allow this widget to be used - to complete non multiple fields as well. - ''' - - def __init__(self, parent=None, completer_widget=None): - QLineEdit.__init__(self, parent) - - self.sep = ',' - self.space_before_sep = False - self.add_separator = True - self.original_cursor_pos = None - - self._model = CompleteModel(parent=self) - self._completer = c = QCompleter(self._model, self) - c.setWidget(self if completer_widget is None else completer_widget) - c.setCompletionMode(QCompleter.PopupCompletion) - c.setCaseSensitivity(Qt.CaseInsensitive) - c.setModelSorting(self._model.sorting) - c.setCompletionRole(Qt.DisplayRole) - p = c.popup() - p.setMouseTracking(True) - p.entered.connect(self.item_entered) - c.popup().setAlternatingRowColors(True) - - c.activated.connect(self.completion_selected, - type=Qt.QueuedConnection) - self.textEdited.connect(self.text_edited) - - # Interface {{{ - def update_items_cache(self, complete_items): - self.all_items = complete_items - - def set_separator(self, sep): - self.sep = sep - - def set_space_before_sep(self, space_before): - self.space_before_sep = space_before - - def set_add_separator(self, what): - self.add_separator = bool(what) - - # }}} - - def item_entered(self, idx): - self._completer.popup().setCurrentIndex(idx) - - def text_edited(self, *args): - self.update_completions() - self._completer.complete() - - def update_completions(self): - ' Update the list of completions ' - self.original_cursor_pos = cpos = self.cursorPosition() - text = unicode(self.text()) - prefix = text[:cpos] - self.current_prefix = prefix - complete_prefix = prefix.lstrip() - if self.sep: - complete_prefix = prefix.split(self.sep)[-1].lstrip() - self._completer.setCompletionPrefix(complete_prefix) - - def get_completed_text(self, text): - 'Get completed text in before and after parts' - if self.sep is None: - return text, '' - else: - cursor_pos = self.original_cursor_pos - if cursor_pos is None: - cursor_pos = self.cursorPosition() - self.original_cursor_pos = None - # Split text - curtext = unicode(self.text()) - before_text = curtext[:cursor_pos] - after_text = curtext[cursor_pos:].rstrip() - # Remove the completion prefix from the before text - before_text = self.sep.join(before_text.split(self.sep)[:-1]).rstrip() - if before_text: - # Add the separator to the end of before_text - if self.space_before_sep: - before_text += ' ' - before_text += self.sep + ' ' - if self.add_separator or after_text: - # Add separator to the end of completed text - if self.space_before_sep: - text = text.rstrip() + ' ' - completed_text = text + self.sep + ' ' - else: - completed_text = text - return before_text + completed_text, after_text - - def completion_selected(self, text): - before_text, after_text = self.get_completed_text(unicode(text)) - self.setText(before_text + after_text) - self.setCursorPosition(len(before_text)) - - @dynamic_property - def all_items(self): - def fget(self): - return self._model.items - def fset(self, items): - self._model.set_items(items) - self._completer.setModelSorting(self._model.sorting) - return property(fget=fget, fset=fset) - -class MultiCompleteComboBox(EnComboBox): - - def __init__(self, *args): - EnComboBox.__init__(self, *args) - self.le = MultiCompleteLineEdit(self, completer_widget=self) - self.setLineEdit(self.le) - - def showPopup(self): - c = self.le._completer - v = c.currentCompletion() - c.setCompletionPrefix('') - c.complete() - cs = c.caseSensitivity() - i = 0 - while c.setCurrentRow(i): - cr = c.currentIndex().data().toString() - if cr.startsWith(v, cs): - c.popup().setCurrentIndex(c.currentIndex()) - return - i += 1 - c.setCurrentRow(0) - - def update_items_cache(self, complete_items): - self.lineEdit().update_items_cache(complete_items) - - def set_separator(self, sep): - self.lineEdit().set_separator(sep) - - def set_space_before_sep(self, space_before): - self.lineEdit().set_space_before_sep(space_before) - - def set_add_separator(self, what): - self.lineEdit().set_add_separator(what) - - def show_initial_value(self, what): - what = unicode(what) if what else u'' - le = self.lineEdit() - self.setEditText(what) - le.selectAll() - -if __name__ == '__main__': - from PyQt5.Qt import QDialog, QVBoxLayout - app = QApplication([]) - d = QDialog() - d.setLayout(QVBoxLayout()) - le = MultiCompleteComboBox(d) - d.layout().addWidget(le) - items = ['one', 'otwo', 'othree', 'ooone', 'ootwo', - 'oothree'] - le.update_items_cache(items) - le.show_initial_value('') - d.exec_() diff --git a/src/calibre/gui2/convert/page_setup.py b/src/calibre/gui2/convert/page_setup.py index 7dd3dc05bb..c0812e8e8e 100644 --- a/src/calibre/gui2/convert/page_setup.py +++ b/src/calibre/gui2/convert/page_setup.py @@ -6,11 +6,10 @@ __license__ = 'GPL v3' __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' -from PyQt5.Qt import Qt, QAbstractListModel, QVariant, QModelIndex +from PyQt5.Qt import Qt, QAbstractListModel, QModelIndex from calibre.gui2.convert.page_setup_ui import Ui_Form from calibre.gui2.convert import Widget -from calibre.gui2 import NONE from calibre.customize.ui import input_profiles, output_profiles class ProfileModel(QAbstractListModel): @@ -25,7 +24,7 @@ class ProfileModel(QAbstractListModel): def data(self, index, role): profile = self.profiles[index.row()] if role == Qt.DisplayRole: - return QVariant(profile.name) + return (profile.name) if role in (Qt.ToolTipRole, Qt.StatusTipRole, Qt.WhatsThisRole): w, h = profile.screen_size if w >= 10000: @@ -33,8 +32,8 @@ class ProfileModel(QAbstractListModel): else: ss = _('%(width)d x %(height)d pixels') % dict(width=w, height=h) ss = _('Screen size: %s') % ss - return QVariant('%s [%s]' % (profile.description, ss)) - return NONE + return ('%s [%s]' % (profile.description, ss)) + return None class PageSetupWidget(Widget, Ui_Form): diff --git a/src/calibre/gui2/convert/single.py b/src/calibre/gui2/convert/single.py index cd67ef0600..7873a7b77b 100644 --- a/src/calibre/gui2/convert/single.py +++ b/src/calibre/gui2/convert/single.py @@ -8,9 +8,9 @@ __docformat__ = 'restructuredtext en' import cPickle, shutil -from PyQt5.Qt import QAbstractListModel, Qt, QVariant, QFont, QModelIndex +from PyQt5.Qt import QAbstractListModel, Qt, QFont, QModelIndex -from calibre.gui2 import ResizableDialog, NONE, gprefs +from calibre.gui2 import ResizableDialog, gprefs from calibre.ebooks.conversion.config import (GuiRecommendations, save_specifics, load_specifics) from calibre.gui2.convert.single_ui import Ui_Dialog @@ -75,16 +75,16 @@ class GroupModel(QAbstractListModel): try: widget = self.widgets[index.row()] except: - return NONE + return None if role == Qt.DisplayRole: - return QVariant(widget.config_title()) + return (widget.config_title()) if role == Qt.DecorationRole: - return QVariant(widget.config_icon()) + return (widget.config_icon()) if role == Qt.FontRole: f = QFont() f.setBold(True) - return QVariant(f) - return NONE + return (f) + return None def get_preferred_input_format_for_book(db, book_id): recs = load_specifics(db, book_id) diff --git a/src/calibre/gui2/cover_flow.py b/src/calibre/gui2/cover_flow.py index f36c18da9c..b464011875 100644 --- a/src/calibre/gui2/cover_flow.py +++ b/src/calibre/gui2/cover_flow.py @@ -237,7 +237,10 @@ class CBDialog(QDialog): class CoverFlowMixin(object): - def __init__(self): + def __init__(self, *args, **kwargs): + pass + + def init_cover_flow_mixin(self): self.cover_flow = None if CoverFlow is not None: self.cf_last_updated_at = None diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 0fe748e80f..705f3d4b62 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -861,7 +861,10 @@ device_signals = DeviceSignals() class DeviceMixin(object): # {{{ - def __init__(self): + def __init__(self, *args, **kwargs): + pass + + def init_device_mixin(self): self.device_error_dialog = error_dialog(self, _('Error'), _('Error communicating with device'), ' ') self.device_error_dialog.setModal(Qt.NonModal) diff --git a/src/calibre/gui2/dialogs/plugin_updater.py b/src/calibre/gui2/dialogs/plugin_updater.py index 57d96e927e..342927328c 100644 --- a/src/calibre/gui2/dialogs/plugin_updater.py +++ b/src/calibre/gui2/dialogs/plugin_updater.py @@ -11,7 +11,7 @@ import re, datetime, traceback from lxml import html from PyQt5.Qt import (Qt, QUrl, QFrame, QVBoxLayout, QLabel, QBrush, QTextEdit, QComboBox, QAbstractItemView, QHBoxLayout, QDialogButtonBox, - QAbstractTableModel, QVariant, QTableView, QModelIndex, + QAbstractTableModel, QTableView, QModelIndex, QSortFilterProxyModel, QAction, QIcon, QDialog, QFont, QPixmap, QSize, QLineEdit) @@ -20,7 +20,7 @@ from calibre.constants import numeric_version, iswindows, isosx, DEBUG, __appnam from calibre.customize.ui import ( initialized_plugins, is_disabled, remove_plugin, add_plugin, enable_plugin, disable_plugin, NameConflict, has_external_plugins) -from calibre.gui2 import error_dialog, question_dialog, info_dialog, NONE, open_url, gprefs +from calibre.gui2 import error_dialog, question_dialog, info_dialog, open_url, gprefs from calibre.gui2.preferences.plugins import ConfigWidget from calibre.utils.date import UNDEFINED_DATE, format_date @@ -270,7 +270,7 @@ class DisplayPluginModel(QAbstractTableModel): def __init__(self, display_plugins): QAbstractTableModel.__init__(self) self.display_plugins = display_plugins - self.headers = map(QVariant, [_('Plugin Name'), _('Donate'), _('Status'), _('Installed'), + self.headers = map(unicode, [_('Plugin Name'), _('Donate'), _('Status'), _('Installed'), _('Available'), _('Released'), _('Calibre'), _('Author')]) def rowCount(self, *args): @@ -282,36 +282,36 @@ class DisplayPluginModel(QAbstractTableModel): def headerData(self, section, orientation, role): if role == Qt.DisplayRole and orientation == Qt.Horizontal: return self.headers[section] - return NONE + return None def data(self, index, role): if not index.isValid(): - return NONE + return None row, col = index.row(), index.column() if row < 0 or row >= self.rowCount(): - return NONE + return None display_plugin = self.display_plugins[row] if role in [Qt.DisplayRole, Qt.UserRole]: if col == 0: - return QVariant(display_plugin.name) + return display_plugin.name if col == 1: if display_plugin.donation_link: - return QVariant(_('PayPal')) + return _('PayPal') if col == 2: return self._get_status(display_plugin) if col == 3: - return QVariant(self._get_display_version(display_plugin.installed_version)) + return self._get_display_version(display_plugin.installed_version) if col == 4: - return QVariant(self._get_display_version(display_plugin.available_version)) + return self._get_display_version(display_plugin.available_version) if col == 5: if role == Qt.UserRole: return self._get_display_release_date(display_plugin.release_date, 'yyyyMMdd') else: return self._get_display_release_date(display_plugin.release_date) if col == 6: - return QVariant(self._get_display_version(display_plugin.calibre_required_version)) + return self._get_display_version(display_plugin.calibre_required_version) if col == 7: - return QVariant(display_plugin.author) + return display_plugin.author elif role == Qt.DecorationRole: if col == 0: return self._get_status_icon(display_plugin) @@ -320,18 +320,18 @@ class DisplayPluginModel(QAbstractTableModel): return QIcon(I('donate.png')) elif role == Qt.ToolTipRole: if col == 1 and display_plugin.donation_link: - return QVariant(_('This plugin is FREE but you can reward the developer for their effort\n' + return _('This plugin is FREE but you can reward the developer for their effort\n' 'by donating to them via PayPal.\n\n' - 'Right-click and choose Donate to reward: ')+display_plugin.author) + 'Right-click and choose Donate to reward: ')+display_plugin.author else: return self._get_status_tooltip(display_plugin) elif role == Qt.ForegroundRole: if col != 1: # Never change colour of the donation column if display_plugin.is_deprecated: - return QVariant(QBrush(Qt.blue)) + return QBrush(Qt.blue) if display_plugin.is_disabled(): - return QVariant(QBrush(Qt.gray)) - return NONE + return QBrush(Qt.gray) + return None def plugin_to_index(self, display_plugin): for i, p in enumerate(self.display_plugins): @@ -345,8 +345,8 @@ class DisplayPluginModel(QAbstractTableModel): def _get_display_release_date(self, date_value, format='dd MMM yyyy'): if date_value and date_value != UNDEFINED_DATE: - return QVariant(format_date(date_value, format)) - return NONE + return format_date(date_value, format) + return None def _get_display_version(self, version): if version is None: @@ -395,24 +395,24 @@ class DisplayPluginModel(QAbstractTableModel): def _get_status_tooltip(self, display_plugin): if display_plugin.is_deprecated: - return QVariant(_('This plugin has been deprecated and should be uninstalled')+'\n\n'+ + return (_('This plugin has been deprecated and should be uninstalled')+'\n\n'+ _('Right-click to see more options')) if not display_plugin.is_valid_platform(): - return QVariant(_('This plugin can only be installed on: %s') % + return (_('This plugin can only be installed on: %s') % ', '.join(display_plugin.platforms)+'\n\n'+ _('Right-click to see more options')) if numeric_version < display_plugin.calibre_required_version: - return QVariant(_('You must upgrade to at least Calibre %s before installing this plugin') % + return (_('You must upgrade to at least Calibre %s before installing this plugin') % self._get_display_version(display_plugin.calibre_required_version)+'\n\n'+ _('Right-click to see more options')) if display_plugin.installed_version < display_plugin.available_version: if display_plugin.installed_version is None: - return QVariant(_('You can install this plugin')+'\n\n'+ + return (_('You can install this plugin')+'\n\n'+ _('Right-click to see more options')) else: - return QVariant(_('A new version of this plugin is available')+'\n\n'+ + return (_('A new version of this plugin is available')+'\n\n'+ _('Right-click to see more options')) - return QVariant(_('This plugin is installed and up-to-date')+'\n\n'+ + return (_('This plugin is installed and up-to-date')+'\n\n'+ _('Right-click to see more options')) diff --git a/src/calibre/gui2/dnd.py b/src/calibre/gui2/dnd.py index 0a837161bb..82cdecaa84 100644 --- a/src/calibre/gui2/dnd.py +++ b/src/calibre/gui2/dnd.py @@ -13,7 +13,7 @@ from threading import Thread from Queue import Queue, Empty from PyQt5.Qt import QPixmap, Qt, QDialog, QLabel, QVBoxLayout, \ - QDialogButtonBox, QProgressBar, QTimer + QDialogButtonBox, QProgressBar, QTimer, QUrl from calibre.constants import DEBUG, iswindows from calibre.ptempfile import PersistentTemporaryFile @@ -145,7 +145,7 @@ def dnd_has_extension(md, extensions): if has_firefox_ext(md, extensions): return True if md.hasUrls(): - urls = [unicode(u.toString()) for u in + urls = [unicode(u.toString(QUrl.None)) for u in md.urls()] paths = [path_from_qurl(u) for u in md.urls()] exts = frozenset([posixpath.splitext(u)[1][1:].lower() for u in @@ -196,7 +196,7 @@ def dnd_get_image(md, image_exts=IMAGE_EXTENSIONS): # No image, look for a URL pointing to an image if md.hasUrls(): - urls = [unicode(u.toString()) for u in + urls = [unicode(u.toString(QUrl.None)) for u in md.urls()] purls = [urlparse(u) for u in urls] # First look for a local file @@ -243,7 +243,7 @@ def dnd_get_files(md, exts): ''' # Look for a URL pointing to a file if md.hasUrls(): - urls = [unicode(u.toString()) for u in + urls = [unicode(u.toString(QUrl.None)) for u in md.urls()] purls = [urlparse(u) for u in urls] # First look for a local file diff --git a/src/calibre/gui2/ebook_download.py b/src/calibre/gui2/ebook_download.py index 9f678bd506..facc5016f2 100644 --- a/src/calibre/gui2/ebook_download.py +++ b/src/calibre/gui2/ebook_download.py @@ -96,6 +96,9 @@ def start_ebook_download(callback, job_manager, gui, cookie_file=None, url='', f class EbookDownloadMixin(object): + def __init__(self, *args, **kwargs): + pass + def download_ebook(self, url='', cookie_file=None, filename='', save_loc='', add_to_lib=True, tags=[]): if tags: if isinstance(tags, basestring): diff --git a/src/calibre/gui2/email.py b/src/calibre/gui2/email.py index eecc63445d..4b6a5b78fd 100644 --- a/src/calibre/gui2/email.py +++ b/src/calibre/gui2/email.py @@ -270,7 +270,7 @@ class SelectRecipients(QDialog): # {{{ ans = [] for i in self.items: if i.checkState() == Qt.Checked: - to = unicode(i.data(Qt.UserRole).toString()) + to = unicode(i.data(Qt.UserRole) or '') fmts = tuple(x.strip().upper() for x in (opts.accounts[to][0] or '').split(',')) subject = opts.subjects.get(to, '') ans.append((to, fmts, subject)) @@ -285,6 +285,9 @@ def select_recipients(parent=None): class EmailMixin(object): # {{{ + def __init__(self, *args, **kwargs): + pass + def send_multiple_by_mail(self, recipients, delete_from_library): ids = set(self.library_view.model().id(r) for r in self.library_view.selectionModel().selectedRows()) if not ids: diff --git a/src/calibre/gui2/font_family_chooser.py b/src/calibre/gui2/font_family_chooser.py index 870991ac8d..f554afdd7d 100644 --- a/src/calibre/gui2/font_family_chooser.py +++ b/src/calibre/gui2/font_family_chooser.py @@ -66,7 +66,7 @@ class FontFamilyDelegate(QStyledItemDelegate): return QSize(300, 50) def do_size_hint(self, option, index): - text = index.data(Qt.DisplayRole).toString() + text = index.data(Qt.DisplayRole) or '' font = QFont(option.font) font.setPointSize(QFontInfo(font).pointSize() * 1.5) m = QFontMetrics(font) @@ -82,7 +82,7 @@ class FontFamilyDelegate(QStyledItemDelegate): painter.restore() def do_paint(self, painter, option, index): - text = unicode(index.data(Qt.DisplayRole).toString()) + text = unicode(index.data(Qt.DisplayRole) or '') font = QFont(option.font) font.setPointSize(QFontInfo(font).pointSize() * 1.5) font2 = QFont(font) diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index 57cb2a4c3f..632c38cd7b 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -31,7 +31,10 @@ def partial(*args, **kwargs): class LibraryViewMixin(object): # {{{ - def __init__(self, db): + def __init__(self, *args, **kwargs): + pass + + def init_library_view_mixin(self, db): self.library_view.files_dropped.connect(self.iactions['Add Books'].files_dropped, type=Qt.QueuedConnection) self.library_view.add_column_signal.connect(partial(self.iactions['Preferences'].do_config, initial_plugin=('Interface', 'Custom Columns')), @@ -294,14 +297,14 @@ class VLTabs(QTabBar): # {{{ self.setVisible(False) def tab_changed(self, idx): - vl = unicode(self.tabData(idx).toString()).strip() or None + vl = unicode(self.tabData(idx) or '').strip() or None self.gui.apply_virtual_library(vl) def tab_moved(self, from_, to): - self.current_db.prefs['virt_libs_order'] = [unicode(self.tabData(i).toString()) for i in range(self.count())] + self.current_db.prefs['virt_libs_order'] = [unicode(self.tabData(i) or '') for i in range(self.count())] def tab_close(self, index): - vl = unicode(self.tabData(index).toString()) + vl = unicode(self.tabData(index) or '') if vl: # Dont allow closing the All Books tab self.current_db.prefs['virt_libs_hidden'] = list( self.current_db.prefs['virt_libs_hidden']) + [vl] @@ -381,7 +384,10 @@ class VLTabs(QTabBar): # {{{ class LayoutMixin(object): # {{{ - def __init__(self): + def __init__(self, *args, **kwargs): + pass + + def init_layout_mixin(self): self.vl_tabs = VLTabs(self) self.centralwidget.layout().addWidget(self.vl_tabs) diff --git a/src/calibre/gui2/jobs.py b/src/calibre/gui2/jobs.py index 5ccaf5a694..7664f5049c 100644 --- a/src/calibre/gui2/jobs.py +++ b/src/calibre/gui2/jobs.py @@ -10,7 +10,7 @@ Job management. import re, time from Queue import Empty, Queue -from PyQt5.Qt import (QAbstractTableModel, QVariant, QModelIndex, Qt, +from PyQt5.Qt import (QAbstractTableModel, QModelIndex, Qt, QTimer, pyqtSignal, QIcon, QDialog, QAbstractItemDelegate, QApplication, QSize, QStyleOptionProgressBar, QStyle, QToolTip, QFrame, QHBoxLayout, QVBoxLayout, QSizePolicy, QLabel, QCoreApplication, QAction, @@ -18,7 +18,7 @@ from PyQt5.Qt import (QAbstractTableModel, QVariant, QModelIndex, Qt, from calibre.utils.ipc.server import Server from calibre.utils.ipc.job import ParallelJob -from calibre.gui2 import (Dispatcher, error_dialog, question_dialog, NONE, +from calibre.gui2 import (Dispatcher, error_dialog, question_dialog, config, gprefs) from calibre.gui2.device import DeviceJob from calibre.gui2.dialogs.jobs_ui import Ui_JobsDialog @@ -38,10 +38,10 @@ class JobManager(QAbstractTableModel, SearchQueryParser): # {{{ QAbstractTableModel.__init__(self) SearchQueryParser.__init__(self, ['all']) - self.wait_icon = QVariant(QIcon(I('jobs.png'))) - self.running_icon = QVariant(QIcon(I('exec.png'))) - self.error_icon = QVariant(QIcon(I('dialog_error.png'))) - self.done_icon = QVariant(QIcon(I('ok.png'))) + self.wait_icon = (QIcon(I('jobs.png'))) + self.running_icon = (QIcon(I('exec.png'))) + self.error_icon = (QIcon(I('dialog_error.png'))) + self.done_icon = (QIcon(I('ok.png'))) self.jobs = [] self.add_job = Dispatcher(self._add_job) @@ -62,9 +62,9 @@ class JobManager(QAbstractTableModel, SearchQueryParser): # {{{ def headerData(self, section, orientation, role): if role != Qt.DisplayRole: - return NONE + return None if orientation == Qt.Horizontal: - return QVariant({ + return ({ 0: _('Job'), 1: _('Status'), 2: _('Progress'), @@ -72,7 +72,7 @@ class JobManager(QAbstractTableModel, SearchQueryParser): # {{{ 4: _('Start time'), }.get(section, '')) else: - return QVariant(section+1) + return (section+1) def show_tooltip(self, arg): widget, pos = arg @@ -99,7 +99,7 @@ class JobManager(QAbstractTableModel, SearchQueryParser): # {{{ def data(self, index, role): try: if role not in (Qt.DisplayRole, Qt.DecorationRole): - return NONE + return None row, col = index.row(), index.column() job = self.jobs[row] @@ -108,19 +108,19 @@ class JobManager(QAbstractTableModel, SearchQueryParser): # {{{ desc = job.description if not desc: desc = _('Unknown job') - return QVariant(desc) + return (desc) if col == 1: - return QVariant(job.status_text) + return (job.status_text) if col == 2: p = 100. if job.is_finished else job.percent - return QVariant(p) + return (p) if col == 3: rtime = job.running_time if rtime is None: - return NONE - return QVariant('%dm %ds'%(int(rtime)//60, int(rtime)%60)) + return None + return ('%dm %ds'%(int(rtime)//60, int(rtime)%60)) if col == 4 and job.start_time is not None: - return QVariant(time.strftime('%H:%M -- %d %b', time.localtime(job.start_time))) + return (time.strftime('%H:%M -- %d %b', time.localtime(job.start_time))) if role == Qt.DecorationRole and col == 0: state = job.run_state if state == job.WAITING: @@ -133,7 +133,7 @@ class JobManager(QAbstractTableModel, SearchQueryParser): # {{{ except: import traceback traceback.print_exc() - return NONE + return None def update(self): try: @@ -392,8 +392,9 @@ class ProgressBarDelegate(QAbstractItemDelegate): # {{{ opts.minimum = 1 opts.maximum = 100 opts.textVisible = True - percent, ok = index.model().data(index, Qt.DisplayRole).toInt() - if not ok: + try: + percent = int(index.model().data(index, Qt.DisplayRole)) + except (TypeError, ValueError): percent = 0 opts.progress = percent opts.text = (_('Unavailable') if percent == 0 else '%d%%'%percent) diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py index a8e5562dc6..6aa9bce46e 100644 --- a/src/calibre/gui2/layout.py +++ b/src/calibre/gui2/layout.py @@ -267,7 +267,10 @@ class Spacer(QWidget): # {{{ class MainWindowMixin(object): # {{{ - def __init__(self, db): + def __init__(self, *args, **kwargs): + pass + + def init_main_window_mixin(self, db): self.setObjectName('MainWindow') self.setWindowIcon(QIcon(I('lt.png'))) self.setWindowTitle(__appname__) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 6bea39e9f0..d8fbfc652a 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -9,9 +9,9 @@ import functools, re, os, traceback, errno, time from collections import defaultdict, namedtuple from PyQt5.Qt import (QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage, - QModelIndex, QVariant, QDateTime, QColor, QPixmap, QPainter) + QModelIndex, QDateTime, QColor, QPixmap, QPainter) -from calibre.gui2 import NONE, error_dialog +from calibre.gui2 import error_dialog from calibre.utils.search_query_parser import ParseException from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors from calibre.ebooks.metadata.book.formatter import SafeFormat @@ -60,7 +60,7 @@ class ColumnColor(object): # {{{ self.mi = None color = color_cache[id_][key] if color.isValid(): - return QVariant(color) + return color return None try: if self.mi is None: @@ -70,7 +70,6 @@ class ColumnColor(object): # {{{ template_cache=template_cache)) color_cache[id_][key] = color if color.isValid(): - color = QVariant(color) self.mi = None return color except: @@ -199,7 +198,7 @@ class BooksModel(QAbstractTableModel): # {{{ self.bool_no_icon = QIcon(I('list_remove.png')) self.bool_blank_icon = QIcon(I('blank.png')) self.marked_icon = QIcon(I('marked.png')) - self.row_decoration = NONE + self.row_decoration = None self.device_connected = False self.ids_to_highlight = [] self.ids_to_highlight_set = set() @@ -712,19 +711,19 @@ class BooksModel(QAbstractTableModel): # {{{ def func(idx): val = force_to_bool(fffunc(field_obj, idfunc(idx))) if val is None: - return NONE if bt else bn + return None if bt else bn return by if val else bn elif field == 'size': sz_mult = 1.0/(1024**2) def func(idx): val = fffunc(field_obj, idfunc(idx), default_value=0) or 0 if val is 0: - return NONE + return None ans = u'%.1f' % (val * sz_mult) - return QVariant(u'<0.1' if ans == u'0.0' else ans) + return (u'<0.1' if ans == u'0.0' else ans) elif field == 'languages': def func(idx): - return QVariant(', '.join(calibre_langcode_to_name(x) for x in fffunc(field_obj, idfunc(idx)))) + return (', '.join(calibre_langcode_to_name(x) for x in fffunc(field_obj, idfunc(idx)))) elif field == 'ondevice' and decorator: by = self.bool_yes_icon bb = self.bool_blank_icon @@ -739,54 +738,54 @@ class BooksModel(QAbstractTableModel): # {{{ sv = m['is_multiple']['cache_to_list'] def func(idx): val = fffunc(field_obj, idfunc(idx), default_value='') or '' - return QVariant(jv.join(sorted((x.strip() for x in val.split(sv)), key=sort_key))) + return (jv.join(sorted((x.strip() for x in val.split(sv)), key=sort_key))) else: def func(idx): - return QVariant(fffunc(field_obj, idfunc(idx), default_value='')) + return (fffunc(field_obj, idfunc(idx), default_value='')) else: if do_sort: def func(idx): - return QVariant(jv.join(sorted(fffunc(field_obj, idfunc(idx), default_value=()), key=sort_key))) + return (jv.join(sorted(fffunc(field_obj, idfunc(idx), default_value=()), key=sort_key))) else: def func(idx): - return QVariant(jv.join(fffunc(field_obj, idfunc(idx), default_value=()))) + return (jv.join(fffunc(field_obj, idfunc(idx), default_value=()))) else: if dt in {'text', 'composite', 'enumeration'} and m['display'].get('use_decorations', False): def func(idx): text = fffunc(field_obj, idfunc(idx)) - return QVariant(text) if force_to_bool(text) is None else NONE + return (text) if force_to_bool(text) is None else None else: def func(idx): - return QVariant(fffunc(field_obj, idfunc(idx), default_value='')) + return (fffunc(field_obj, idfunc(idx), default_value='')) elif dt == 'datetime': def func(idx): - return QVariant(QDateTime(as_local_time(fffunc(field_obj, idfunc(idx), default_value=UNDEFINED_DATE)))) + return (QDateTime(as_local_time(fffunc(field_obj, idfunc(idx), default_value=UNDEFINED_DATE)))) elif dt == 'rating': def func(idx): - return QVariant(int(fffunc(field_obj, idfunc(idx), default_value=0)/2.0)) + return (int(fffunc(field_obj, idfunc(idx), default_value=0)/2.0)) elif dt == 'series': sidx_field = self.db.new_api.fields[field + '_index'] def func(idx): book_id = idfunc(idx) series = fffunc(field_obj, book_id, default_value=False) if series: - return QVariant('%s [%s]' % (series, fmt_sidx(fffunc(sidx_field, book_id, default_value=1.0)))) - return NONE + return ('%s [%s]' % (series, fmt_sidx(fffunc(sidx_field, book_id, default_value=1.0)))) + return None elif dt in {'int', 'float'}: fmt = m['display'].get('number_format', None) def func(idx): val = fffunc(field_obj, idfunc(idx)) if val is None: - return NONE + return None if fmt: try: - return QVariant(fmt.format(val)) + return (fmt.format(val)) except (TypeError, ValueError, AttributeError, IndexError, KeyError): pass - return QVariant(val) + return (val) else: def func(idx): - return NONE + return None return func @@ -813,7 +812,7 @@ class BooksModel(QAbstractTableModel): # {{{ # the column map does not accurately represent the screen. In these cases, # we will get asked to display columns we don't know about. Must test for this. if col >= len(self.column_to_dc_map): - return NONE + return None if role == Qt.DisplayRole: rules = self.db.prefs['column_icon_rules'] if rules: @@ -833,14 +832,14 @@ class BooksModel(QAbstractTableModel): # {{{ self.icon_cache, self.icon_bitmap_cache, self.icon_template_cache) if ccicon is not None: - return NONE + return None self.icon_cache[id_][cache_index] = None return self.column_to_dc_map[col](index.row()) elif role in (Qt.EditRole, Qt.ToolTipRole): return self.column_to_dc_map[col](index.row()) elif role == Qt.BackgroundRole: if self.id(index) in self.ids_to_highlight_set: - return QVariant(QColor('lightgreen')) + return (QColor('lightgreen')) elif role == Qt.ForegroundRole: key = self.column_map[col] id_ = self.id(index) @@ -862,13 +861,13 @@ class BooksModel(QAbstractTableModel): # {{{ cc = self.custom_columns[self.column_map[col]]['display'] colors = cc.get('enum_colors', []) values = cc.get('enum_values', []) - txt = unicode(index.data(Qt.DisplayRole).toString()) + txt = unicode(index.data(Qt.DisplayRole) or '') if len(colors) > 0 and txt in values: try: color = QColor(colors[values.index(txt)]) if color.isValid(): self.column_color.mi = None - return QVariant(color) + return (color) except: pass @@ -879,11 +878,11 @@ class BooksModel(QAbstractTableModel): # {{{ return ccol self.column_color.mi = None - return NONE + return None elif role == Qt.DecorationRole: if self.column_to_dc_decorator_map[col] is not None: ccicon = self.column_to_dc_decorator_map[index.column()](index.row()) - if ccicon != NONE: + if ccicon is not None: return ccicon rules = self.db.prefs['column_icon_rules'] @@ -915,11 +914,11 @@ class BooksModel(QAbstractTableModel): # {{{ cname = self.column_map[index.column()] ans = Qt.AlignVCenter | ALIGNMENT_MAP[self.alignment_map.get(cname, 'left')] - return QVariant(ans) + return (ans) # elif role == Qt.ToolTipRole and index.isValid(): # if self.column_map[index.column()] in self.editable_cols: - # return QVariant(_("Double click to edit me

")) - return NONE + # return (_("Double click to edit me

")) + return None def headerData(self, section, orientation, role): if orientation == Qt.Horizontal: @@ -933,22 +932,22 @@ class BooksModel(QAbstractTableModel): # {{{ is_cat = '.\n\n' + _('Click in this column and press Q to Quickview books with the same %s') % ht else: is_cat = '' - return QVariant(_('The lookup/search name is "{0}"{1}').format(ht, is_cat)) + return (_('The lookup/search name is "{0}"{1}').format(ht, is_cat)) if role == Qt.DisplayRole: - return QVariant(self.headers[self.column_map[section]]) - return NONE + return (self.headers[self.column_map[section]]) + return None if DEBUG and role == Qt.ToolTipRole and orientation == Qt.Vertical: col = self.db.field_metadata['uuid']['rec_index'] - return QVariant(_('This book\'s UUID is "{0}"').format(self.db.data[section][col])) + return (_('This book\'s UUID is "{0}"').format(self.db.data[section][col])) if role == Qt.DisplayRole: # orientation is vertical - return QVariant(section+1) + return (section+1) if role == Qt.DecorationRole: try: return self.marked_icon if self.db.data.get_marked(self.db.data.index_to_id(section)) else self.row_decoration except (ValueError, IndexError): pass - return NONE + return None def flags(self, index): flags = QAbstractTableModel.flags(self, index) @@ -967,24 +966,24 @@ class BooksModel(QAbstractTableModel): # {{{ label=self.db.field_metadata.key_to_label(colhead) s_index = None if typ in ('text', 'comments'): - val = unicode(value.toString()).strip() + val = unicode(value or '').strip() val = val if val else None elif typ == 'enumeration': - val = unicode(value.toString()).strip() + val = unicode(value or '').strip() if not val: val = None elif typ == 'bool': - val = value.toPyObject() + val = bool(value) elif typ == 'rating': - val = value.toInt()[0] + val = int(value) val = 0 if val < 0 else 5 if val > 5 else val val *= 2 elif typ in ('int', 'float'): - val = unicode(value.toString()).strip() + val = unicode(value or '').strip() if not val: val = None elif typ == 'datetime': - val = value.toDateTime() + val = value if val.isNull(): val = None else: @@ -992,7 +991,7 @@ class BooksModel(QAbstractTableModel): # {{{ return False val = qt_to_dt(val, as_utc=False) elif typ == 'series': - val = unicode(value.toString()).strip() + val = unicode(value or '').strip() if val: pat = re.compile(r'\[([.0-9]+)\]') match = pat.search(val) @@ -1006,7 +1005,7 @@ class BooksModel(QAbstractTableModel): # {{{ s_index = self.db.get_next_cc_series_num_for(val, label=label, num=None) elif typ == 'composite': - tmpl = unicode(value.toString()).strip() + tmpl = unicode(value or '').strip() disp = cc['display'] disp['composite_template'] = tmpl self.db.set_custom_column_metadata(cc['colnum'], display=disp, @@ -1057,9 +1056,9 @@ class BooksModel(QAbstractTableModel): # {{{ else: if column not in self.editable_cols: return False - val = (int(value.toInt()[0]) if column == 'rating' else - value.toDateTime() if column in ('timestamp', 'pubdate') - else re.sub(ur'\s', u' ', unicode(value.toString()).strip())) + val = (int(value) if column == 'rating' else + value if column in ('timestamp', 'pubdate') + else re.sub(ur'\s', u' ', unicode(value or '').strip())) id = self.db.id(row) books_to_refresh = set([id]) if column == 'rating': @@ -1543,17 +1542,17 @@ class DeviceBooksModel(BooksModel): # {{{ text = self.db[self.map[row]].title if not text: text = self.unknown - return QVariant(text) + return (text) elif cname == 'authors': au = self.db[self.map[row]].authors if not au: au = [_('Unknown')] - return QVariant(authors_to_string(au)) + return (authors_to_string(au)) elif cname == 'size': size = self.db[self.map[row]].size if not isinstance(size, (float, int)): size = 0 - return QVariant(human_readable(size)) + return (human_readable(size)) elif cname == 'timestamp': dt = self.db[self.map[row]].datetime try: @@ -1561,49 +1560,49 @@ class DeviceBooksModel(BooksModel): # {{{ except OverflowError: dt = dt_factory(time.gmtime(), assume_utc=True, as_utc=False) - return QVariant(strftime(TIME_FMT, dt.timetuple())) + return (strftime(TIME_FMT, dt.timetuple())) elif cname == 'collections': tags = self.db[self.map[row]].device_collections if tags: tags.sort(key=sort_key) - return QVariant(', '.join(tags)) + return (', '.join(tags)) elif DEBUG and cname == 'inlibrary': - return QVariant(self.db[self.map[row]].in_library) + return (self.db[self.map[row]].in_library) elif role == Qt.ToolTipRole and index.isValid(): if col == 0 and hasattr(self.db[self.map[row]], 'in_library_waiting'): - return QVariant(_('Waiting for metadata to be updated')) + return (_('Waiting for metadata to be updated')) if self.is_row_marked_for_deletion(row): - return QVariant(_('Marked for deletion')) + return (_('Marked for deletion')) if cname in ['title', 'authors'] or (cname == 'collections' and self.db.supports_collections()): - return QVariant(_("Double click to edit me

")) + return (_("Double click to edit me

")) elif role == Qt.DecorationRole and cname == 'inlibrary': if hasattr(self.db[self.map[row]], 'in_library_waiting'): - return QVariant(self.sync_icon) + return (self.sync_icon) elif self.db[self.map[row]].in_library: - return QVariant(self.bool_yes_icon) + return (self.bool_yes_icon) elif self.db[self.map[row]].in_library is not None: - return QVariant(self.bool_no_icon) + return (self.bool_no_icon) elif role == Qt.TextAlignmentRole: cname = self.column_map[index.column()] ans = Qt.AlignVCenter | ALIGNMENT_MAP[self.alignment_map.get(cname, 'left')] - return QVariant(ans) - return NONE + return (ans) + return None def headerData(self, section, orientation, role): if role == Qt.ToolTipRole and orientation == Qt.Horizontal: - return QVariant(_('The lookup/search name is "{0}"').format(self.column_map[section])) + return (_('The lookup/search name is "{0}"').format(self.column_map[section])) if DEBUG and role == Qt.ToolTipRole and orientation == Qt.Vertical: - return QVariant(_('This book\'s UUID is "{0}"').format(self.db[self.map[section]].uuid)) + return (_('This book\'s UUID is "{0}"').format(self.db[self.map[section]].uuid)) if role != Qt.DisplayRole: - return NONE + return None if orientation == Qt.Horizontal: cname = self.column_map[section] text = self.headers[cname] - return QVariant(text) + return (text) else: - return QVariant(section+1) + return (section+1) def setData(self, index, value, role): done = False @@ -1612,7 +1611,7 @@ class DeviceBooksModel(BooksModel): # {{{ cname = self.column_map[col] if cname in ('size', 'timestamp', 'inlibrary'): return False - val = unicode(value.toString()).strip() + val = unicode(value or '').strip() idx = self.map[row] if cname == 'collections': tags = [i.strip() for i in val.split(',')] diff --git a/src/calibre/gui2/preferences/plugins.py b/src/calibre/gui2/preferences/plugins.py index 83a52b82a6..00230970b3 100644 --- a/src/calibre/gui2/preferences/plugins.py +++ b/src/calibre/gui2/preferences/plugins.py @@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en' import textwrap, os from collections import OrderedDict -from PyQt5.Qt import (Qt, QModelIndex, QAbstractItemModel, QVariant, QIcon, +from PyQt5.Qt import (Qt, QModelIndex, QAbstractItemModel, QIcon, QBrush) from calibre.gui2.preferences import ConfigWidgetBase, test_widget @@ -16,7 +16,7 @@ from calibre.gui2.preferences.plugins_ui import Ui_Form from calibre.customize.ui import (initialized_plugins, is_disabled, enable_plugin, disable_plugin, plugin_customization, add_plugin, remove_plugin, NameConflict) -from calibre.gui2 import (NONE, error_dialog, info_dialog, choose_files, +from calibre.gui2 import (error_dialog, info_dialog, choose_files, question_dialog, gprefs) from calibre.gui2.dialogs.confirm_delete import confirm from calibre.utils.search_query_parser import SearchQueryParser @@ -29,9 +29,9 @@ class PluginModel(QAbstractItemModel, SearchQueryParser): # {{{ QAbstractItemModel.__init__(self) SearchQueryParser.__init__(self, ['all']) self.show_only_user_plugins = show_only_user_plugins - self.icon = QVariant(QIcon(I('plugins.png'))) + self.icon = QIcon(I('plugins.png')) p = QIcon(self.icon).pixmap(64, 64, QIcon.Disabled, QIcon.On) - self.disabled_icon = QVariant(QIcon(p)) + self.disabled_icon = QIcon(p) self._p = p self.populate() @@ -187,11 +187,11 @@ class PluginModel(QAbstractItemModel, SearchQueryParser): # {{{ def data(self, index, role): if not index.isValid(): - return NONE + return None if index.internalId() == 0: if role == Qt.DisplayRole: category = self.categories[index.row()] - return QVariant(_("%(plugin_type)s %(plugins)s")% + return (_("%(plugin_type)s %(plugins)s")% dict(plugin_type=category, plugins=_('plugins'))) else: plugin = self.index_to_plugin(index) @@ -205,14 +205,14 @@ class PluginModel(QAbstractItemModel, SearchQueryParser): # {{{ ans += _('\nCustomization: ')+c if disabled: ans += _('\n\nThis plugin has been disabled') - return QVariant(ans) + return (ans) if role == Qt.DecorationRole: return self.disabled_icon if disabled else self.icon if role == Qt.ForegroundRole and disabled: - return QVariant(QBrush(Qt.gray)) + return (QBrush(Qt.gray)) if role == Qt.UserRole: return plugin - return NONE + return None # }}} @@ -333,7 +333,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): index = self.plugin_view.currentIndex() if index.isValid(): if not index.parent().isValid(): - name = unicode(index.data().toString()) + name = unicode(index.data() or '') return error_dialog(self, _('Error'), '

'+ _('Select an actual plugin under %s to customize')%name, show=True, show_copy_button=False) diff --git a/src/calibre/gui2/search_box.py b/src/calibre/gui2/search_box.py index eb7fbcf8d0..905039e7f4 100644 --- a/src/calibre/gui2/search_box.py +++ b/src/calibre/gui2/search_box.py @@ -398,7 +398,10 @@ class SavedSearchBox(QComboBox): # {{{ class SearchBoxMixin(object): # {{{ - def __init__(self): + def __init__(self, *args, **kwargs): + pass + + def init_search_box_mixin(self): self.search.initialize('main_search_history', colorize=True, help_text=_('Search (For Advanced Search click the button to the left)')) self.search.cleared.connect(self.search_box_cleared) @@ -413,7 +416,7 @@ class SearchBoxMixin(object): # {{{ self.search.setMaximumWidth(self.width()-150) self.action_focus_search = QAction(self) shortcuts = list( - map(lambda x:unicode(x.toString()), + map(lambda x:unicode(x.toString(QKeySequence.PortableText)), QKeySequence.keyBindings(QKeySequence.Find))) shortcuts += ['/', 'Alt+S'] self.keyboard.register_shortcut('start search', _('Start search'), @@ -478,7 +481,10 @@ class SearchBoxMixin(object): # {{{ class SavedSearchBoxMixin(object): # {{{ - def __init__(self): + def __init__(self, *args, **kwargs): + pass + + def init_saved_seach_box_mixin(self): self.saved_search.changed.connect(self.saved_searches_changed) self.clear_button.clicked.connect(self.saved_search.clear) self.save_search_button.clicked.connect( diff --git a/src/calibre/gui2/search_restriction_mixin.py b/src/calibre/gui2/search_restriction_mixin.py index 9a5917fd4c..4d4ee3c689 100644 --- a/src/calibre/gui2/search_restriction_mixin.py +++ b/src/calibre/gui2/search_restriction_mixin.py @@ -50,7 +50,7 @@ class SelectNames(QDialog): # {{{ @property def names(self): for item in self._names.selectedItems(): - yield unicode(item.data(Qt.DisplayRole).toString()) + yield unicode(item.data(Qt.DisplayRole) or '') @property def match_type(self): @@ -231,7 +231,7 @@ class CreateVirtualLibrary(QDialog): # {{{ return self.new_name = self.editing = self.vl_name.currentText() self.original_index = dex - self.original_search = unicode(self.vl_name.itemData(dex).toString()) + self.original_search = unicode(self.vl_name.itemData(dex) or '') self.vl_text.setText(self.original_search) def link_activated(self, url): @@ -308,7 +308,10 @@ class SearchRestrictionMixin(object): no_restriction = _('') - def __init__(self): + def __init__(self, *args, **kwargs): + pass + + def init_search_restirction_mixin(self): self.checked = QIcon(I('ok.png')) self.empty = QIcon(I('blank.png')) self.current_search_action = QAction(self.empty, _('*current search'), self) diff --git a/src/calibre/gui2/store/stores/mobileread/models.py b/src/calibre/gui2/store/stores/mobileread/models.py index f7acd8eb72..669601ba91 100644 --- a/src/calibre/gui2/store/stores/mobileread/models.py +++ b/src/calibre/gui2/store/stores/mobileread/models.py @@ -8,9 +8,8 @@ __docformat__ = 'restructuredtext en' from operator import attrgetter -from PyQt5.Qt import (Qt, QAbstractItemModel, QModelIndex, QVariant, pyqtSignal) +from PyQt5.Qt import (Qt, QAbstractItemModel, QModelIndex, pyqtSignal) -from calibre.gui2 import NONE from calibre.db.search import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH from calibre.utils.config_base import prefs from calibre.utils.icu import sort_key @@ -67,26 +66,26 @@ class BooksModel(QAbstractItemModel): def headerData(self, section, orientation, role): if role != Qt.DisplayRole: - return NONE + return None text = '' if orientation == Qt.Horizontal: if section < len(self.HEADERS): text = self.HEADERS[section] - return QVariant(text) + return (text) else: - return QVariant(section+1) + return (section+1) def data(self, index, role): row, col = index.row(), index.column() result = self.books[row] if role == Qt.DisplayRole: if col == 0: - return QVariant(result.title) + return (result.title) elif col == 1: - return QVariant(result.author) + return (result.author) elif col == 2: - return QVariant(result.formats) - return NONE + return (result.formats) + return None def data_as_text(self, result, col): text = '' diff --git a/src/calibre/gui2/tag_browser/model.py b/src/calibre/gui2/tag_browser/model.py index 0672e4c110..f25bb49afb 100644 --- a/src/calibre/gui2/tag_browser/model.py +++ b/src/calibre/gui2/tag_browser/model.py @@ -10,11 +10,11 @@ __docformat__ = 'restructuredtext en' import traceback, cPickle, copy, os -from PyQt5.Qt import (QAbstractItemModel, QIcon, QVariant, QFont, Qt, +from PyQt5.Qt import (QAbstractItemModel, QIcon, QFont, Qt, QMimeData, QModelIndex, pyqtSignal, QObject) from calibre.constants import config_dir -from calibre.gui2 import NONE, gprefs, config, error_dialog +from calibre.gui2 import gprefs, config, error_dialog from calibre.db.categories import Tag from calibre.utils.config import tweaks from calibre.utils.icu import sort_key, lower, strcmp, collation_order @@ -31,7 +31,7 @@ def bf(): if _bf is None: _bf = QFont() _bf.setBold(True) - _bf = QVariant(_bf) + _bf = (_bf) return _bf class TagTreeItem(object): # {{{ @@ -48,7 +48,7 @@ class TagTreeItem(object): # {{{ self.id_set = set() self.is_gst = False self.boxed = False - self.icon_state_map = list(map(QVariant, icon_map)) + self.icon_state_map = list(icon_map) if self.parent is not None: self.parent.append(self) @@ -58,7 +58,7 @@ class TagTreeItem(object): # {{{ self.type = self.TAG if category_icon is None else self.CATEGORY if self.type == self.CATEGORY: - self.name, self.icon = map(QVariant, (data, category_icon)) + self.name, self.icon = data, category_icon self.py_name = data self.category_key = category_key self.temporary = temporary @@ -67,7 +67,7 @@ class TagTreeItem(object): # {{{ ['news', 'search', 'identifiers', 'languages'], is_searchable=category_key not in ['search']) elif self.type == self.TAG: - self.icon_state_map[0] = QVariant(data.icon) + self.icon_state_map[0] = (data.icon) self.tag = data self.tooltip = (tooltip + ' ') if tooltip else '' @@ -80,8 +80,8 @@ class TagTreeItem(object): # {{{ if self.type == self.ROOT: return 'ROOT' if self.type == self.CATEGORY: - return 'CATEGORY:'+str(QVariant.toString( - self.name))+':%d'%len(getattr(self, + return 'CATEGORY:'+str( + self.name)+':%d'%len(getattr(self, 'children', [])) return 'TAG: %s'%self.tag.name @@ -101,13 +101,13 @@ class TagTreeItem(object): # {{{ return self.tag_data(role) if self.type == self.CATEGORY: return self.category_data(role) - return NONE + return None def category_data(self, role): if role == Qt.DisplayRole: - return QVariant(self.py_name + ' [%d]'%len(self.child_tags())) + return (self.py_name + ' [%d]'%len(self.child_tags())) if role == Qt.EditRole: - return QVariant(self.py_name) + return (self.py_name) if role == Qt.DecorationRole: if self.tag.state: return self.icon_state_map[self.tag.state] @@ -115,8 +115,8 @@ class TagTreeItem(object): # {{{ if role == Qt.FontRole: return bf() if role == Qt.ToolTipRole and self.tooltip is not None: - return QVariant(self.tooltip) - return NONE + return (self.tooltip) + return None def tag_data(self, role): tag = self.tag @@ -136,24 +136,24 @@ class TagTreeItem(object): # {{{ count = len(self.id_set) count = count if count > 0 else tag.count if count == 0: - return QVariant('%s'%(name)) + return ('%s'%(name)) else: - return QVariant('[%d] %s'%(count, name)) + return ('[%d] %s'%(count, name)) if role == Qt.EditRole: - return QVariant(tag.original_name) + return (tag.original_name) if role == Qt.DecorationRole: return self.icon_state_map[tag.state] if role == Qt.ToolTipRole: if tt_author: if tag.tooltip is not None: - return QVariant('(%s) %s'%(tag.name, tag.tooltip)) + return ('(%s) %s'%(tag.name, tag.tooltip)) else: - return QVariant(tag.name) + return (tag.name) if tag.tooltip: - return QVariant(self.tooltip + tag.tooltip) + return (self.tooltip + tag.tooltip) else: - return QVariant(self.tooltip) - return NONE + return (self.tooltip) + return None def toggle(self, set_to=None): ''' @@ -940,7 +940,7 @@ class TagsModel(QAbstractItemModel): # {{{ def data(self, index, role): if not index.isValid(): - return NONE + return None item = self.get_node(index) return item.data(role) @@ -950,7 +950,7 @@ class TagsModel(QAbstractItemModel): # {{{ # set up to reposition at the same item. We can do this except if # working with the last item and that item is deleted, in which case # we position at the parent label - val = unicode(value.toString()).strip() + val = unicode(value or '').strip() if not val: error_dialog(self.gui_parent, _('Item is blank'), _('An item cannot be set to nothing. Delete it instead.')).exec_() @@ -1014,7 +1014,7 @@ class TagsModel(QAbstractItemModel): # {{{ error_dialog(self.gui_parent, _('Duplicate search name'), _('The saved search name %s is already used.')%val).exec_() return False - self.db.saved_search_rename(unicode(item.data(role).toString()), val) + self.db.saved_search_rename(unicode(item.data(role) or ''), val) item.tag.name = val self.search_item_renamed.emit() # Does a refresh else: @@ -1079,7 +1079,7 @@ class TagsModel(QAbstractItemModel): # {{{ self.db.prefs.set('user_categories', user_cats) def headerData(self, *args): - return NONE + return None def flags(self, index, *args): ans = Qt.ItemIsEnabled|Qt.ItemIsEditable diff --git a/src/calibre/gui2/tag_browser/ui.py b/src/calibre/gui2/tag_browser/ui.py index 8be77ca58c..0adc292042 100644 --- a/src/calibre/gui2/tag_browser/ui.py +++ b/src/calibre/gui2/tag_browser/ui.py @@ -25,7 +25,10 @@ from calibre.gui2.dialogs.edit_authors_dialog import EditAuthorsDialog class TagBrowserMixin(object): # {{{ - def __init__(self, db): + def __init__(self, *args, **kwargs): + pass + + def init_tag_browser_mixin(self, db): self.library_view.model().count_changed_signal.connect(self.tags_view.recount) self.tags_view.set_database(db, self.alter_tb) self.tags_view.tags_marked.connect(self.search.set_search_string) diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index ce0c31ab1e..4cfbcc019a 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -245,7 +245,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ _('&Donate to support calibre'), self) for st in self.istores.values(): st.do_genesis() - MainWindowMixin.__init__(self, db) + MainWindowMixin.init_main_window_mixin(self, db) # Jobs Button {{{ self.job_manager = JobManager() @@ -254,10 +254,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ self.jobs_button.initialize(self.jobs_dialog, self.job_manager) # }}} - LayoutMixin.__init__(self) - EmailMixin.__init__(self) - EbookDownloadMixin.__init__(self) - DeviceMixin.__init__(self) + LayoutMixin.init_layout_mixin(self) + DeviceMixin.init_device_mixin(self) self.progress_indicator = ProgressIndicator(self) self.progress_indicator.pos = (0, 20) @@ -335,15 +333,15 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ self.eject_action.triggered.connect(self.device_manager.umount_device) #################### Update notification ################### - UpdateMixin.__init__(self, opts) + UpdateMixin.init_update_mixin(self, opts) ####################### Search boxes ######################## - SearchRestrictionMixin.__init__(self) - SavedSearchBoxMixin.__init__(self) + SearchRestrictionMixin.init_search_restirction_mixin(self) + SavedSearchBoxMixin.init_saved_seach_box_mixin(self) ####################### Library view ######################## - LibraryViewMixin.__init__(self, db) - SearchBoxMixin.__init__(self) # Requires current_db + LibraryViewMixin.init_library_view_mixin(self, db) + SearchBoxMixin.init_search_box_mixin(self) # Requires current_db if show_gui: self.show() @@ -369,7 +367,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ type=Qt.QueuedConnection) ########################### Tags Browser ############################## - TagBrowserMixin.__init__(self, db) + TagBrowserMixin.init_tag_browser_mixin(self, db) ######################### Search Restriction ########################## if db.prefs['virtual_lib_on_startup']: @@ -378,7 +376,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ ########################### Cover Flow ################################ - CoverFlowMixin.__init__(self) + CoverFlowMixin.init_cover_flow_mixin(self) self._calculated_available_height = min(max_available_height()-15, self.height()) diff --git a/src/calibre/gui2/update.py b/src/calibre/gui2/update.py index 3f43457c5f..e6845f9bcb 100644 --- a/src/calibre/gui2/update.py +++ b/src/calibre/gui2/update.py @@ -134,7 +134,10 @@ class UpdateNotification(QDialog): class UpdateMixin(object): - def __init__(self, opts): + def __init__(self, *args, **kw): + pass + + def init_update_mixin(self, opts): self.last_newest_calibre_version = NO_CALIBRE_UPDATE if not opts.no_update_check: self.update_checker = CheckForUpdates(self) diff --git a/src/calibre/web/feeds/recipes/model.py b/src/calibre/web/feeds/recipes/model.py index e113e5c10a..673679d2b5 100644 --- a/src/calibre/web/feeds/recipes/model.py +++ b/src/calibre/web/feeds/recipes/model.py @@ -8,11 +8,10 @@ __docformat__ = 'restructuredtext en' import copy, zipfile -from PyQt5.Qt import QAbstractItemModel, QVariant, Qt, QColor, QFont, QIcon, \ +from PyQt5.Qt import QAbstractItemModel, Qt, QColor, QFont, QIcon, \ QModelIndex, pyqtSignal, QPixmap from calibre.utils.search_query_parser import SearchQueryParser -from calibre.gui2 import NONE from calibre.utils.localization import get_language from calibre.web.feeds.recipes.collection import \ get_builtin_recipe_collection, get_custom_recipe_collection, \ @@ -41,7 +40,7 @@ class NewsTreeItem(object): self.children.append(child) def data(self, role): - return NONE + return None def flags(self): return Qt.ItemIsEnabled|Qt.ItemIsSelectable @@ -65,16 +64,16 @@ class NewsCategory(NewsTreeItem): self.cdata = get_language(self.category) self.bold_font = QFont() self.bold_font.setBold(True) - self.bold_font = QVariant(self.bold_font) + self.bold_font = (self.bold_font) def data(self, role): if role == Qt.DisplayRole: - return QVariant(self.cdata + ' [%d]'%len(self.children)) + return (self.cdata + ' [%d]'%len(self.children)) elif role == Qt.FontRole: return self.bold_font elif role == Qt.ForegroundRole and self.category == _('Scheduled'): - return QVariant(QColor(0, 255, 0)) - return NONE + return (QColor(0, 255, 0)) + return None def flags(self): return Qt.ItemIsEnabled @@ -106,7 +105,7 @@ class NewsItem(NewsTreeItem): def data(self, role): if role == Qt.DisplayRole: - return QVariant(self.title) + return (self.title) if role == Qt.DecorationRole: if self.icon is None: icon = '%s.png'%self.urn[8:] @@ -118,11 +117,11 @@ class NewsItem(NewsTreeItem): except: pass if not p.isNull(): - self.icon = QVariant(QIcon(p)) + self.icon = (QIcon(p)) else: self.icon = self.default_icon return self.icon - return NONE + return None def __cmp__(self, other): return cmp(self.title.lower(), getattr(other, 'title', '').lower()) @@ -135,8 +134,8 @@ class RecipeModel(QAbstractItemModel, SearchQueryParser): def __init__(self, *args): QAbstractItemModel.__init__(self, *args) SearchQueryParser.__init__(self, locations=['all']) - self.default_icon = QVariant(QIcon(I('news.png'))) - self.custom_icon = QVariant(QIcon(I('user_profile.png'))) + self.default_icon = (QIcon(I('news.png'))) + self.custom_icon = (QIcon(I('user_profile.png'))) self.builtin_recipe_collection = get_builtin_recipe_collection() self.scheduler_config = SchedulerConfig() try: @@ -300,12 +299,12 @@ class RecipeModel(QAbstractItemModel, SearchQueryParser): def data(self, index, role): if not index.isValid(): - return NONE + return None item = index.internalPointer() return item.data(role) def headerData(self, *args): - return NONE + return None def flags(self, index): if not index.isValid():