More removal anf QVariant. Also fix PyQt5 multiple inheritance problem with QMainWindow for main calibre gui

This commit is contained in:
Kovid Goyal 2014-04-22 21:17:03 +05:30
parent 1c01665fe7
commit a5dc23ae0f
27 changed files with 256 additions and 436 deletions

View File

@ -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 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 = { exclusions = {
'src/calibre/gui2/viewer/gestures.py': {'toPoint'}, '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(): for path in all_py_files():
if os.path.basename(path) in { if os.path.basename(path) in {

View File

@ -146,7 +146,7 @@ def _config(): # {{{
c.add_opt('confirm_delete', default=False, c.add_opt('confirm_delete', default=False,
help=_('Confirm before deleting')) help=_('Confirm before deleting'))
c.add_opt('main_window_geometry', default=None, 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, c.add_opt('new_version_notification', default=True,
help=_('Notify when a new version is available')) help=_('Notify when a new version is available'))
c.add_opt('use_roman_numerals_for_series_number', default=True, c.add_opt('use_roman_numerals_for_series_number', default=True,

View File

@ -325,7 +325,7 @@ class BookInfo(QWebView):
self._link_clicked = True self._link_clicked = True
if unicode(link.scheme()) in ('http', 'https'): if unicode(link.scheme()) in ('http', 'https'):
return open_url(link) return open_url(link)
link = unicode(link.toString()) link = unicode(link.toString(QUrl.None))
self.link_clicked.emit(link) self.link_clicked.emit(link)
def turnoff_scrollbar(self, *args): def turnoff_scrollbar(self, *args):
@ -349,7 +349,7 @@ class BookInfo(QWebView):
p = self.page() p = self.page()
mf = p.mainFrame() mf = p.mainFrame()
r = mf.hitTestContent(ev.pos()) r = mf.hitTestContent(ev.pos())
url = unicode(r.linkUrl().toString()).strip() url = unicode(r.linkUrl().toString(QUrl.None)).strip()
menu = p.createStandardContextMenu() menu = p.createStandardContextMenu()
ca = self.pageAction(p.Copy) ca = self.pageAction(p.Copy)
for action in list(menu.actions()): for action in list(menu.actions()):

View File

@ -211,7 +211,7 @@ class EditorWidget(QWebView): # {{{
return return
url = self.parse_link(link) url = self.parse_link(link)
if url.isValid(): if url.isValid():
url = unicode(url.toString()) url = unicode(url.toString(QUrl.None))
self.setFocus(Qt.OtherFocusReason) self.setFocus(Qt.OtherFocusReason)
if is_image: if is_image:
self.exec_command('insertHTML', self.exec_command('insertHTML',

View File

@ -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 <kovid@kovidgoyal.net>'
__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_()

View File

@ -6,11 +6,10 @@ __license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __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.page_setup_ui import Ui_Form
from calibre.gui2.convert import Widget from calibre.gui2.convert import Widget
from calibre.gui2 import NONE
from calibre.customize.ui import input_profiles, output_profiles from calibre.customize.ui import input_profiles, output_profiles
class ProfileModel(QAbstractListModel): class ProfileModel(QAbstractListModel):
@ -25,7 +24,7 @@ class ProfileModel(QAbstractListModel):
def data(self, index, role): def data(self, index, role):
profile = self.profiles[index.row()] profile = self.profiles[index.row()]
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
return QVariant(profile.name) return (profile.name)
if role in (Qt.ToolTipRole, Qt.StatusTipRole, Qt.WhatsThisRole): if role in (Qt.ToolTipRole, Qt.StatusTipRole, Qt.WhatsThisRole):
w, h = profile.screen_size w, h = profile.screen_size
if w >= 10000: if w >= 10000:
@ -33,8 +32,8 @@ class ProfileModel(QAbstractListModel):
else: else:
ss = _('%(width)d x %(height)d pixels') % dict(width=w, height=h) ss = _('%(width)d x %(height)d pixels') % dict(width=w, height=h)
ss = _('Screen size: %s') % ss ss = _('Screen size: %s') % ss
return QVariant('%s [%s]' % (profile.description, ss)) return ('%s [%s]' % (profile.description, ss))
return NONE return None
class PageSetupWidget(Widget, Ui_Form): class PageSetupWidget(Widget, Ui_Form):

View File

@ -8,9 +8,9 @@ __docformat__ = 'restructuredtext en'
import cPickle, shutil 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, from calibre.ebooks.conversion.config import (GuiRecommendations, save_specifics,
load_specifics) load_specifics)
from calibre.gui2.convert.single_ui import Ui_Dialog from calibre.gui2.convert.single_ui import Ui_Dialog
@ -75,16 +75,16 @@ class GroupModel(QAbstractListModel):
try: try:
widget = self.widgets[index.row()] widget = self.widgets[index.row()]
except: except:
return NONE return None
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
return QVariant(widget.config_title()) return (widget.config_title())
if role == Qt.DecorationRole: if role == Qt.DecorationRole:
return QVariant(widget.config_icon()) return (widget.config_icon())
if role == Qt.FontRole: if role == Qt.FontRole:
f = QFont() f = QFont()
f.setBold(True) f.setBold(True)
return QVariant(f) return (f)
return NONE return None
def get_preferred_input_format_for_book(db, book_id): def get_preferred_input_format_for_book(db, book_id):
recs = load_specifics(db, book_id) recs = load_specifics(db, book_id)

View File

@ -237,7 +237,10 @@ class CBDialog(QDialog):
class CoverFlowMixin(object): class CoverFlowMixin(object):
def __init__(self): def __init__(self, *args, **kwargs):
pass
def init_cover_flow_mixin(self):
self.cover_flow = None self.cover_flow = None
if CoverFlow is not None: if CoverFlow is not None:
self.cf_last_updated_at = None self.cf_last_updated_at = None

View File

@ -861,7 +861,10 @@ device_signals = DeviceSignals()
class DeviceMixin(object): # {{{ 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'), self.device_error_dialog = error_dialog(self, _('Error'),
_('Error communicating with device'), ' ') _('Error communicating with device'), ' ')
self.device_error_dialog.setModal(Qt.NonModal) self.device_error_dialog.setModal(Qt.NonModal)

View File

@ -11,7 +11,7 @@ import re, datetime, traceback
from lxml import html from lxml import html
from PyQt5.Qt import (Qt, QUrl, QFrame, QVBoxLayout, QLabel, QBrush, QTextEdit, from PyQt5.Qt import (Qt, QUrl, QFrame, QVBoxLayout, QLabel, QBrush, QTextEdit,
QComboBox, QAbstractItemView, QHBoxLayout, QDialogButtonBox, QComboBox, QAbstractItemView, QHBoxLayout, QDialogButtonBox,
QAbstractTableModel, QVariant, QTableView, QModelIndex, QAbstractTableModel, QTableView, QModelIndex,
QSortFilterProxyModel, QAction, QIcon, QDialog, QSortFilterProxyModel, QAction, QIcon, QDialog,
QFont, QPixmap, QSize, QLineEdit) QFont, QPixmap, QSize, QLineEdit)
@ -20,7 +20,7 @@ from calibre.constants import numeric_version, iswindows, isosx, DEBUG, __appnam
from calibre.customize.ui import ( from calibre.customize.ui import (
initialized_plugins, is_disabled, remove_plugin, add_plugin, enable_plugin, disable_plugin, initialized_plugins, is_disabled, remove_plugin, add_plugin, enable_plugin, disable_plugin,
NameConflict, has_external_plugins) 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.gui2.preferences.plugins import ConfigWidget
from calibre.utils.date import UNDEFINED_DATE, format_date from calibre.utils.date import UNDEFINED_DATE, format_date
@ -270,7 +270,7 @@ class DisplayPluginModel(QAbstractTableModel):
def __init__(self, display_plugins): def __init__(self, display_plugins):
QAbstractTableModel.__init__(self) QAbstractTableModel.__init__(self)
self.display_plugins = display_plugins 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')]) _('Available'), _('Released'), _('Calibre'), _('Author')])
def rowCount(self, *args): def rowCount(self, *args):
@ -282,36 +282,36 @@ class DisplayPluginModel(QAbstractTableModel):
def headerData(self, section, orientation, role): def headerData(self, section, orientation, role):
if role == Qt.DisplayRole and orientation == Qt.Horizontal: if role == Qt.DisplayRole and orientation == Qt.Horizontal:
return self.headers[section] return self.headers[section]
return NONE return None
def data(self, index, role): def data(self, index, role):
if not index.isValid(): if not index.isValid():
return NONE return None
row, col = index.row(), index.column() row, col = index.row(), index.column()
if row < 0 or row >= self.rowCount(): if row < 0 or row >= self.rowCount():
return NONE return None
display_plugin = self.display_plugins[row] display_plugin = self.display_plugins[row]
if role in [Qt.DisplayRole, Qt.UserRole]: if role in [Qt.DisplayRole, Qt.UserRole]:
if col == 0: if col == 0:
return QVariant(display_plugin.name) return display_plugin.name
if col == 1: if col == 1:
if display_plugin.donation_link: if display_plugin.donation_link:
return QVariant(_('PayPal')) return _('PayPal')
if col == 2: if col == 2:
return self._get_status(display_plugin) return self._get_status(display_plugin)
if col == 3: 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: 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 col == 5:
if role == Qt.UserRole: if role == Qt.UserRole:
return self._get_display_release_date(display_plugin.release_date, 'yyyyMMdd') return self._get_display_release_date(display_plugin.release_date, 'yyyyMMdd')
else: else:
return self._get_display_release_date(display_plugin.release_date) return self._get_display_release_date(display_plugin.release_date)
if col == 6: 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: if col == 7:
return QVariant(display_plugin.author) return display_plugin.author
elif role == Qt.DecorationRole: elif role == Qt.DecorationRole:
if col == 0: if col == 0:
return self._get_status_icon(display_plugin) return self._get_status_icon(display_plugin)
@ -320,18 +320,18 @@ class DisplayPluginModel(QAbstractTableModel):
return QIcon(I('donate.png')) return QIcon(I('donate.png'))
elif role == Qt.ToolTipRole: elif role == Qt.ToolTipRole:
if col == 1 and display_plugin.donation_link: 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' '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: else:
return self._get_status_tooltip(display_plugin) return self._get_status_tooltip(display_plugin)
elif role == Qt.ForegroundRole: elif role == Qt.ForegroundRole:
if col != 1: # Never change colour of the donation column if col != 1: # Never change colour of the donation column
if display_plugin.is_deprecated: if display_plugin.is_deprecated:
return QVariant(QBrush(Qt.blue)) return QBrush(Qt.blue)
if display_plugin.is_disabled(): if display_plugin.is_disabled():
return QVariant(QBrush(Qt.gray)) return QBrush(Qt.gray)
return NONE return None
def plugin_to_index(self, display_plugin): def plugin_to_index(self, display_plugin):
for i, p in enumerate(self.display_plugins): 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'): def _get_display_release_date(self, date_value, format='dd MMM yyyy'):
if date_value and date_value != UNDEFINED_DATE: if date_value and date_value != UNDEFINED_DATE:
return QVariant(format_date(date_value, format)) return format_date(date_value, format)
return NONE return None
def _get_display_version(self, version): def _get_display_version(self, version):
if version is None: if version is None:
@ -395,24 +395,24 @@ class DisplayPluginModel(QAbstractTableModel):
def _get_status_tooltip(self, display_plugin): def _get_status_tooltip(self, display_plugin):
if display_plugin.is_deprecated: 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')) _('Right-click to see more options'))
if not display_plugin.is_valid_platform(): 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'+ ', '.join(display_plugin.platforms)+'\n\n'+
_('Right-click to see more options')) _('Right-click to see more options'))
if numeric_version < display_plugin.calibre_required_version: 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'+ self._get_display_version(display_plugin.calibre_required_version)+'\n\n'+
_('Right-click to see more options')) _('Right-click to see more options'))
if display_plugin.installed_version < display_plugin.available_version: if display_plugin.installed_version < display_plugin.available_version:
if display_plugin.installed_version is None: 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')) _('Right-click to see more options'))
else: 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')) _('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')) _('Right-click to see more options'))

View File

@ -13,7 +13,7 @@ from threading import Thread
from Queue import Queue, Empty from Queue import Queue, Empty
from PyQt5.Qt import QPixmap, Qt, QDialog, QLabel, QVBoxLayout, \ from PyQt5.Qt import QPixmap, Qt, QDialog, QLabel, QVBoxLayout, \
QDialogButtonBox, QProgressBar, QTimer QDialogButtonBox, QProgressBar, QTimer, QUrl
from calibre.constants import DEBUG, iswindows from calibre.constants import DEBUG, iswindows
from calibre.ptempfile import PersistentTemporaryFile from calibre.ptempfile import PersistentTemporaryFile
@ -145,7 +145,7 @@ def dnd_has_extension(md, extensions):
if has_firefox_ext(md, extensions): if has_firefox_ext(md, extensions):
return True return True
if md.hasUrls(): if md.hasUrls():
urls = [unicode(u.toString()) for u in urls = [unicode(u.toString(QUrl.None)) for u in
md.urls()] md.urls()]
paths = [path_from_qurl(u) 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 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 # No image, look for a URL pointing to an image
if md.hasUrls(): if md.hasUrls():
urls = [unicode(u.toString()) for u in urls = [unicode(u.toString(QUrl.None)) for u in
md.urls()] md.urls()]
purls = [urlparse(u) for u in urls] purls = [urlparse(u) for u in urls]
# First look for a local file # First look for a local file
@ -243,7 +243,7 @@ def dnd_get_files(md, exts):
''' '''
# Look for a URL pointing to a file # Look for a URL pointing to a file
if md.hasUrls(): if md.hasUrls():
urls = [unicode(u.toString()) for u in urls = [unicode(u.toString(QUrl.None)) for u in
md.urls()] md.urls()]
purls = [urlparse(u) for u in urls] purls = [urlparse(u) for u in urls]
# First look for a local file # First look for a local file

View File

@ -96,6 +96,9 @@ def start_ebook_download(callback, job_manager, gui, cookie_file=None, url='', f
class EbookDownloadMixin(object): 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=[]): def download_ebook(self, url='', cookie_file=None, filename='', save_loc='', add_to_lib=True, tags=[]):
if tags: if tags:
if isinstance(tags, basestring): if isinstance(tags, basestring):

View File

@ -270,7 +270,7 @@ class SelectRecipients(QDialog): # {{{
ans = [] ans = []
for i in self.items: for i in self.items:
if i.checkState() == Qt.Checked: 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(',')) fmts = tuple(x.strip().upper() for x in (opts.accounts[to][0] or '').split(','))
subject = opts.subjects.get(to, '') subject = opts.subjects.get(to, '')
ans.append((to, fmts, subject)) ans.append((to, fmts, subject))
@ -285,6 +285,9 @@ def select_recipients(parent=None):
class EmailMixin(object): # {{{ class EmailMixin(object): # {{{
def __init__(self, *args, **kwargs):
pass
def send_multiple_by_mail(self, recipients, delete_from_library): 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()) ids = set(self.library_view.model().id(r) for r in self.library_view.selectionModel().selectedRows())
if not ids: if not ids:

View File

@ -66,7 +66,7 @@ class FontFamilyDelegate(QStyledItemDelegate):
return QSize(300, 50) return QSize(300, 50)
def do_size_hint(self, option, index): def do_size_hint(self, option, index):
text = index.data(Qt.DisplayRole).toString() text = index.data(Qt.DisplayRole) or ''
font = QFont(option.font) font = QFont(option.font)
font.setPointSize(QFontInfo(font).pointSize() * 1.5) font.setPointSize(QFontInfo(font).pointSize() * 1.5)
m = QFontMetrics(font) m = QFontMetrics(font)
@ -82,7 +82,7 @@ class FontFamilyDelegate(QStyledItemDelegate):
painter.restore() painter.restore()
def do_paint(self, painter, option, index): 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 = QFont(option.font)
font.setPointSize(QFontInfo(font).pointSize() * 1.5) font.setPointSize(QFontInfo(font).pointSize() * 1.5)
font2 = QFont(font) font2 = QFont(font)

View File

@ -31,7 +31,10 @@ def partial(*args, **kwargs):
class LibraryViewMixin(object): # {{{ 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.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, self.library_view.add_column_signal.connect(partial(self.iactions['Preferences'].do_config,
initial_plugin=('Interface', 'Custom Columns')), initial_plugin=('Interface', 'Custom Columns')),
@ -294,14 +297,14 @@ class VLTabs(QTabBar): # {{{
self.setVisible(False) self.setVisible(False)
def tab_changed(self, idx): 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) self.gui.apply_virtual_library(vl)
def tab_moved(self, from_, to): 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): 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 if vl: # Dont allow closing the All Books tab
self.current_db.prefs['virt_libs_hidden'] = list( self.current_db.prefs['virt_libs_hidden'] = list(
self.current_db.prefs['virt_libs_hidden']) + [vl] self.current_db.prefs['virt_libs_hidden']) + [vl]
@ -381,7 +384,10 @@ class VLTabs(QTabBar): # {{{
class LayoutMixin(object): # {{{ class LayoutMixin(object): # {{{
def __init__(self): def __init__(self, *args, **kwargs):
pass
def init_layout_mixin(self):
self.vl_tabs = VLTabs(self) self.vl_tabs = VLTabs(self)
self.centralwidget.layout().addWidget(self.vl_tabs) self.centralwidget.layout().addWidget(self.vl_tabs)

View File

@ -10,7 +10,7 @@ Job management.
import re, time import re, time
from Queue import Empty, Queue 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, QTimer, pyqtSignal, QIcon, QDialog, QAbstractItemDelegate, QApplication,
QSize, QStyleOptionProgressBar, QStyle, QToolTip, QFrame, QSize, QStyleOptionProgressBar, QStyle, QToolTip, QFrame,
QHBoxLayout, QVBoxLayout, QSizePolicy, QLabel, QCoreApplication, QAction, 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.server import Server
from calibre.utils.ipc.job import ParallelJob 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) config, gprefs)
from calibre.gui2.device import DeviceJob from calibre.gui2.device import DeviceJob
from calibre.gui2.dialogs.jobs_ui import Ui_JobsDialog from calibre.gui2.dialogs.jobs_ui import Ui_JobsDialog
@ -38,10 +38,10 @@ class JobManager(QAbstractTableModel, SearchQueryParser): # {{{
QAbstractTableModel.__init__(self) QAbstractTableModel.__init__(self)
SearchQueryParser.__init__(self, ['all']) SearchQueryParser.__init__(self, ['all'])
self.wait_icon = QVariant(QIcon(I('jobs.png'))) self.wait_icon = (QIcon(I('jobs.png')))
self.running_icon = QVariant(QIcon(I('exec.png'))) self.running_icon = (QIcon(I('exec.png')))
self.error_icon = QVariant(QIcon(I('dialog_error.png'))) self.error_icon = (QIcon(I('dialog_error.png')))
self.done_icon = QVariant(QIcon(I('ok.png'))) self.done_icon = (QIcon(I('ok.png')))
self.jobs = [] self.jobs = []
self.add_job = Dispatcher(self._add_job) self.add_job = Dispatcher(self._add_job)
@ -62,9 +62,9 @@ class JobManager(QAbstractTableModel, SearchQueryParser): # {{{
def headerData(self, section, orientation, role): def headerData(self, section, orientation, role):
if role != Qt.DisplayRole: if role != Qt.DisplayRole:
return NONE return None
if orientation == Qt.Horizontal: if orientation == Qt.Horizontal:
return QVariant({ return ({
0: _('Job'), 0: _('Job'),
1: _('Status'), 1: _('Status'),
2: _('Progress'), 2: _('Progress'),
@ -72,7 +72,7 @@ class JobManager(QAbstractTableModel, SearchQueryParser): # {{{
4: _('Start time'), 4: _('Start time'),
}.get(section, '')) }.get(section, ''))
else: else:
return QVariant(section+1) return (section+1)
def show_tooltip(self, arg): def show_tooltip(self, arg):
widget, pos = arg widget, pos = arg
@ -99,7 +99,7 @@ class JobManager(QAbstractTableModel, SearchQueryParser): # {{{
def data(self, index, role): def data(self, index, role):
try: try:
if role not in (Qt.DisplayRole, Qt.DecorationRole): if role not in (Qt.DisplayRole, Qt.DecorationRole):
return NONE return None
row, col = index.row(), index.column() row, col = index.row(), index.column()
job = self.jobs[row] job = self.jobs[row]
@ -108,19 +108,19 @@ class JobManager(QAbstractTableModel, SearchQueryParser): # {{{
desc = job.description desc = job.description
if not desc: if not desc:
desc = _('Unknown job') desc = _('Unknown job')
return QVariant(desc) return (desc)
if col == 1: if col == 1:
return QVariant(job.status_text) return (job.status_text)
if col == 2: if col == 2:
p = 100. if job.is_finished else job.percent p = 100. if job.is_finished else job.percent
return QVariant(p) return (p)
if col == 3: if col == 3:
rtime = job.running_time rtime = job.running_time
if rtime is None: if rtime is None:
return NONE return None
return QVariant('%dm %ds'%(int(rtime)//60, int(rtime)%60)) return ('%dm %ds'%(int(rtime)//60, int(rtime)%60))
if col == 4 and job.start_time is not None: 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: if role == Qt.DecorationRole and col == 0:
state = job.run_state state = job.run_state
if state == job.WAITING: if state == job.WAITING:
@ -133,7 +133,7 @@ class JobManager(QAbstractTableModel, SearchQueryParser): # {{{
except: except:
import traceback import traceback
traceback.print_exc() traceback.print_exc()
return NONE return None
def update(self): def update(self):
try: try:
@ -392,8 +392,9 @@ class ProgressBarDelegate(QAbstractItemDelegate): # {{{
opts.minimum = 1 opts.minimum = 1
opts.maximum = 100 opts.maximum = 100
opts.textVisible = True opts.textVisible = True
percent, ok = index.model().data(index, Qt.DisplayRole).toInt() try:
if not ok: percent = int(index.model().data(index, Qt.DisplayRole))
except (TypeError, ValueError):
percent = 0 percent = 0
opts.progress = percent opts.progress = percent
opts.text = (_('Unavailable') if percent == 0 else '%d%%'%percent) opts.text = (_('Unavailable') if percent == 0 else '%d%%'%percent)

View File

@ -267,7 +267,10 @@ class Spacer(QWidget): # {{{
class MainWindowMixin(object): # {{{ class MainWindowMixin(object): # {{{
def __init__(self, db): def __init__(self, *args, **kwargs):
pass
def init_main_window_mixin(self, db):
self.setObjectName('MainWindow') self.setObjectName('MainWindow')
self.setWindowIcon(QIcon(I('lt.png'))) self.setWindowIcon(QIcon(I('lt.png')))
self.setWindowTitle(__appname__) self.setWindowTitle(__appname__)

View File

@ -9,9 +9,9 @@ import functools, re, os, traceback, errno, time
from collections import defaultdict, namedtuple from collections import defaultdict, namedtuple
from PyQt5.Qt import (QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage, 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.utils.search_query_parser import ParseException
from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors
from calibre.ebooks.metadata.book.formatter import SafeFormat from calibre.ebooks.metadata.book.formatter import SafeFormat
@ -60,7 +60,7 @@ class ColumnColor(object): # {{{
self.mi = None self.mi = None
color = color_cache[id_][key] color = color_cache[id_][key]
if color.isValid(): if color.isValid():
return QVariant(color) return color
return None return None
try: try:
if self.mi is None: if self.mi is None:
@ -70,7 +70,6 @@ class ColumnColor(object): # {{{
template_cache=template_cache)) template_cache=template_cache))
color_cache[id_][key] = color color_cache[id_][key] = color
if color.isValid(): if color.isValid():
color = QVariant(color)
self.mi = None self.mi = None
return color return color
except: except:
@ -199,7 +198,7 @@ class BooksModel(QAbstractTableModel): # {{{
self.bool_no_icon = QIcon(I('list_remove.png')) self.bool_no_icon = QIcon(I('list_remove.png'))
self.bool_blank_icon = QIcon(I('blank.png')) self.bool_blank_icon = QIcon(I('blank.png'))
self.marked_icon = QIcon(I('marked.png')) self.marked_icon = QIcon(I('marked.png'))
self.row_decoration = NONE self.row_decoration = None
self.device_connected = False self.device_connected = False
self.ids_to_highlight = [] self.ids_to_highlight = []
self.ids_to_highlight_set = set() self.ids_to_highlight_set = set()
@ -712,19 +711,19 @@ class BooksModel(QAbstractTableModel): # {{{
def func(idx): def func(idx):
val = force_to_bool(fffunc(field_obj, idfunc(idx))) val = force_to_bool(fffunc(field_obj, idfunc(idx)))
if val is None: if val is None:
return NONE if bt else bn return None if bt else bn
return by if val else bn return by if val else bn
elif field == 'size': elif field == 'size':
sz_mult = 1.0/(1024**2) sz_mult = 1.0/(1024**2)
def func(idx): def func(idx):
val = fffunc(field_obj, idfunc(idx), default_value=0) or 0 val = fffunc(field_obj, idfunc(idx), default_value=0) or 0
if val is 0: if val is 0:
return NONE return None
ans = u'%.1f' % (val * sz_mult) 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': elif field == 'languages':
def func(idx): 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: elif field == 'ondevice' and decorator:
by = self.bool_yes_icon by = self.bool_yes_icon
bb = self.bool_blank_icon bb = self.bool_blank_icon
@ -739,54 +738,54 @@ class BooksModel(QAbstractTableModel): # {{{
sv = m['is_multiple']['cache_to_list'] sv = m['is_multiple']['cache_to_list']
def func(idx): def func(idx):
val = fffunc(field_obj, idfunc(idx), default_value='') or '' 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: else:
def func(idx): def func(idx):
return QVariant(fffunc(field_obj, idfunc(idx), default_value='')) return (fffunc(field_obj, idfunc(idx), default_value=''))
else: else:
if do_sort: if do_sort:
def func(idx): 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: else:
def func(idx): 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: else:
if dt in {'text', 'composite', 'enumeration'} and m['display'].get('use_decorations', False): if dt in {'text', 'composite', 'enumeration'} and m['display'].get('use_decorations', False):
def func(idx): def func(idx):
text = fffunc(field_obj, idfunc(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: else:
def func(idx): def func(idx):
return QVariant(fffunc(field_obj, idfunc(idx), default_value='')) return (fffunc(field_obj, idfunc(idx), default_value=''))
elif dt == 'datetime': elif dt == 'datetime':
def func(idx): 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': elif dt == 'rating':
def func(idx): 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': elif dt == 'series':
sidx_field = self.db.new_api.fields[field + '_index'] sidx_field = self.db.new_api.fields[field + '_index']
def func(idx): def func(idx):
book_id = idfunc(idx) book_id = idfunc(idx)
series = fffunc(field_obj, book_id, default_value=False) series = fffunc(field_obj, book_id, default_value=False)
if series: if series:
return QVariant('%s [%s]' % (series, fmt_sidx(fffunc(sidx_field, book_id, default_value=1.0)))) return ('%s [%s]' % (series, fmt_sidx(fffunc(sidx_field, book_id, default_value=1.0))))
return NONE return None
elif dt in {'int', 'float'}: elif dt in {'int', 'float'}:
fmt = m['display'].get('number_format', None) fmt = m['display'].get('number_format', None)
def func(idx): def func(idx):
val = fffunc(field_obj, idfunc(idx)) val = fffunc(field_obj, idfunc(idx))
if val is None: if val is None:
return NONE return None
if fmt: if fmt:
try: try:
return QVariant(fmt.format(val)) return (fmt.format(val))
except (TypeError, ValueError, AttributeError, IndexError, KeyError): except (TypeError, ValueError, AttributeError, IndexError, KeyError):
pass pass
return QVariant(val) return (val)
else: else:
def func(idx): def func(idx):
return NONE return None
return func return func
@ -813,7 +812,7 @@ class BooksModel(QAbstractTableModel): # {{{
# the column map does not accurately represent the screen. In these cases, # 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. # we will get asked to display columns we don't know about. Must test for this.
if col >= len(self.column_to_dc_map): if col >= len(self.column_to_dc_map):
return NONE return None
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
rules = self.db.prefs['column_icon_rules'] rules = self.db.prefs['column_icon_rules']
if rules: if rules:
@ -833,14 +832,14 @@ class BooksModel(QAbstractTableModel): # {{{
self.icon_cache, self.icon_bitmap_cache, self.icon_cache, self.icon_bitmap_cache,
self.icon_template_cache) self.icon_template_cache)
if ccicon is not None: if ccicon is not None:
return NONE return None
self.icon_cache[id_][cache_index] = None self.icon_cache[id_][cache_index] = None
return self.column_to_dc_map[col](index.row()) return self.column_to_dc_map[col](index.row())
elif role in (Qt.EditRole, Qt.ToolTipRole): elif role in (Qt.EditRole, Qt.ToolTipRole):
return self.column_to_dc_map[col](index.row()) return self.column_to_dc_map[col](index.row())
elif role == Qt.BackgroundRole: elif role == Qt.BackgroundRole:
if self.id(index) in self.ids_to_highlight_set: if self.id(index) in self.ids_to_highlight_set:
return QVariant(QColor('lightgreen')) return (QColor('lightgreen'))
elif role == Qt.ForegroundRole: elif role == Qt.ForegroundRole:
key = self.column_map[col] key = self.column_map[col]
id_ = self.id(index) id_ = self.id(index)
@ -862,13 +861,13 @@ class BooksModel(QAbstractTableModel): # {{{
cc = self.custom_columns[self.column_map[col]]['display'] cc = self.custom_columns[self.column_map[col]]['display']
colors = cc.get('enum_colors', []) colors = cc.get('enum_colors', [])
values = cc.get('enum_values', []) 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: if len(colors) > 0 and txt in values:
try: try:
color = QColor(colors[values.index(txt)]) color = QColor(colors[values.index(txt)])
if color.isValid(): if color.isValid():
self.column_color.mi = None self.column_color.mi = None
return QVariant(color) return (color)
except: except:
pass pass
@ -879,11 +878,11 @@ class BooksModel(QAbstractTableModel): # {{{
return ccol return ccol
self.column_color.mi = None self.column_color.mi = None
return NONE return None
elif role == Qt.DecorationRole: elif role == Qt.DecorationRole:
if self.column_to_dc_decorator_map[col] is not None: if self.column_to_dc_decorator_map[col] is not None:
ccicon = self.column_to_dc_decorator_map[index.column()](index.row()) ccicon = self.column_to_dc_decorator_map[index.column()](index.row())
if ccicon != NONE: if ccicon is not None:
return ccicon return ccicon
rules = self.db.prefs['column_icon_rules'] rules = self.db.prefs['column_icon_rules']
@ -915,11 +914,11 @@ class BooksModel(QAbstractTableModel): # {{{
cname = self.column_map[index.column()] cname = self.column_map[index.column()]
ans = Qt.AlignVCenter | ALIGNMENT_MAP[self.alignment_map.get(cname, ans = Qt.AlignVCenter | ALIGNMENT_MAP[self.alignment_map.get(cname,
'left')] 'left')]
return QVariant(ans) return (ans)
# elif role == Qt.ToolTipRole and index.isValid(): # elif role == Qt.ToolTipRole and index.isValid():
# if self.column_map[index.column()] in self.editable_cols: # if self.column_map[index.column()] in self.editable_cols:
# return QVariant(_("Double click to <b>edit</b> me<br><br>")) # return (_("Double click to <b>edit</b> me<br><br>"))
return NONE return None
def headerData(self, section, orientation, role): def headerData(self, section, orientation, role):
if orientation == Qt.Horizontal: 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 is_cat = '.\n\n' + _('Click in this column and press Q to Quickview books with the same %s') % ht
else: else:
is_cat = '' 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: if role == Qt.DisplayRole:
return QVariant(self.headers[self.column_map[section]]) return (self.headers[self.column_map[section]])
return NONE return None
if DEBUG and role == Qt.ToolTipRole and orientation == Qt.Vertical: if DEBUG and role == Qt.ToolTipRole and orientation == Qt.Vertical:
col = self.db.field_metadata['uuid']['rec_index'] 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 if role == Qt.DisplayRole: # orientation is vertical
return QVariant(section+1) return (section+1)
if role == Qt.DecorationRole: if role == Qt.DecorationRole:
try: try:
return self.marked_icon if self.db.data.get_marked(self.db.data.index_to_id(section)) else self.row_decoration return self.marked_icon if self.db.data.get_marked(self.db.data.index_to_id(section)) else self.row_decoration
except (ValueError, IndexError): except (ValueError, IndexError):
pass pass
return NONE return None
def flags(self, index): def flags(self, index):
flags = QAbstractTableModel.flags(self, index) flags = QAbstractTableModel.flags(self, index)
@ -967,24 +966,24 @@ class BooksModel(QAbstractTableModel): # {{{
label=self.db.field_metadata.key_to_label(colhead) label=self.db.field_metadata.key_to_label(colhead)
s_index = None s_index = None
if typ in ('text', 'comments'): if typ in ('text', 'comments'):
val = unicode(value.toString()).strip() val = unicode(value or '').strip()
val = val if val else None val = val if val else None
elif typ == 'enumeration': elif typ == 'enumeration':
val = unicode(value.toString()).strip() val = unicode(value or '').strip()
if not val: if not val:
val = None val = None
elif typ == 'bool': elif typ == 'bool':
val = value.toPyObject() val = bool(value)
elif typ == 'rating': elif typ == 'rating':
val = value.toInt()[0] val = int(value)
val = 0 if val < 0 else 5 if val > 5 else val val = 0 if val < 0 else 5 if val > 5 else val
val *= 2 val *= 2
elif typ in ('int', 'float'): elif typ in ('int', 'float'):
val = unicode(value.toString()).strip() val = unicode(value or '').strip()
if not val: if not val:
val = None val = None
elif typ == 'datetime': elif typ == 'datetime':
val = value.toDateTime() val = value
if val.isNull(): if val.isNull():
val = None val = None
else: else:
@ -992,7 +991,7 @@ class BooksModel(QAbstractTableModel): # {{{
return False return False
val = qt_to_dt(val, as_utc=False) val = qt_to_dt(val, as_utc=False)
elif typ == 'series': elif typ == 'series':
val = unicode(value.toString()).strip() val = unicode(value or '').strip()
if val: if val:
pat = re.compile(r'\[([.0-9]+)\]') pat = re.compile(r'\[([.0-9]+)\]')
match = pat.search(val) match = pat.search(val)
@ -1006,7 +1005,7 @@ class BooksModel(QAbstractTableModel): # {{{
s_index = self.db.get_next_cc_series_num_for(val, s_index = self.db.get_next_cc_series_num_for(val,
label=label, num=None) label=label, num=None)
elif typ == 'composite': elif typ == 'composite':
tmpl = unicode(value.toString()).strip() tmpl = unicode(value or '').strip()
disp = cc['display'] disp = cc['display']
disp['composite_template'] = tmpl disp['composite_template'] = tmpl
self.db.set_custom_column_metadata(cc['colnum'], display=disp, self.db.set_custom_column_metadata(cc['colnum'], display=disp,
@ -1057,9 +1056,9 @@ class BooksModel(QAbstractTableModel): # {{{
else: else:
if column not in self.editable_cols: if column not in self.editable_cols:
return False return False
val = (int(value.toInt()[0]) if column == 'rating' else val = (int(value) if column == 'rating' else
value.toDateTime() if column in ('timestamp', 'pubdate') value if column in ('timestamp', 'pubdate')
else re.sub(ur'\s', u' ', unicode(value.toString()).strip())) else re.sub(ur'\s', u' ', unicode(value or '').strip()))
id = self.db.id(row) id = self.db.id(row)
books_to_refresh = set([id]) books_to_refresh = set([id])
if column == 'rating': if column == 'rating':
@ -1543,17 +1542,17 @@ class DeviceBooksModel(BooksModel): # {{{
text = self.db[self.map[row]].title text = self.db[self.map[row]].title
if not text: if not text:
text = self.unknown text = self.unknown
return QVariant(text) return (text)
elif cname == 'authors': elif cname == 'authors':
au = self.db[self.map[row]].authors au = self.db[self.map[row]].authors
if not au: if not au:
au = [_('Unknown')] au = [_('Unknown')]
return QVariant(authors_to_string(au)) return (authors_to_string(au))
elif cname == 'size': elif cname == 'size':
size = self.db[self.map[row]].size size = self.db[self.map[row]].size
if not isinstance(size, (float, int)): if not isinstance(size, (float, int)):
size = 0 size = 0
return QVariant(human_readable(size)) return (human_readable(size))
elif cname == 'timestamp': elif cname == 'timestamp':
dt = self.db[self.map[row]].datetime dt = self.db[self.map[row]].datetime
try: try:
@ -1561,49 +1560,49 @@ class DeviceBooksModel(BooksModel): # {{{
except OverflowError: except OverflowError:
dt = dt_factory(time.gmtime(), assume_utc=True, dt = dt_factory(time.gmtime(), assume_utc=True,
as_utc=False) as_utc=False)
return QVariant(strftime(TIME_FMT, dt.timetuple())) return (strftime(TIME_FMT, dt.timetuple()))
elif cname == 'collections': elif cname == 'collections':
tags = self.db[self.map[row]].device_collections tags = self.db[self.map[row]].device_collections
if tags: if tags:
tags.sort(key=sort_key) tags.sort(key=sort_key)
return QVariant(', '.join(tags)) return (', '.join(tags))
elif DEBUG and cname == 'inlibrary': 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(): elif role == Qt.ToolTipRole and index.isValid():
if col == 0 and hasattr(self.db[self.map[row]], 'in_library_waiting'): 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): 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 if cname in ['title', 'authors'] or (cname == 'collections' and
self.db.supports_collections()): self.db.supports_collections()):
return QVariant(_("Double click to <b>edit</b> me<br><br>")) return (_("Double click to <b>edit</b> me<br><br>"))
elif role == Qt.DecorationRole and cname == 'inlibrary': elif role == Qt.DecorationRole and cname == 'inlibrary':
if hasattr(self.db[self.map[row]], 'in_library_waiting'): 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: 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: 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: elif role == Qt.TextAlignmentRole:
cname = self.column_map[index.column()] cname = self.column_map[index.column()]
ans = Qt.AlignVCenter | ALIGNMENT_MAP[self.alignment_map.get(cname, ans = Qt.AlignVCenter | ALIGNMENT_MAP[self.alignment_map.get(cname,
'left')] 'left')]
return QVariant(ans) return (ans)
return NONE return None
def headerData(self, section, orientation, role): def headerData(self, section, orientation, role):
if role == Qt.ToolTipRole and orientation == Qt.Horizontal: 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: 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: if role != Qt.DisplayRole:
return NONE return None
if orientation == Qt.Horizontal: if orientation == Qt.Horizontal:
cname = self.column_map[section] cname = self.column_map[section]
text = self.headers[cname] text = self.headers[cname]
return QVariant(text) return (text)
else: else:
return QVariant(section+1) return (section+1)
def setData(self, index, value, role): def setData(self, index, value, role):
done = False done = False
@ -1612,7 +1611,7 @@ class DeviceBooksModel(BooksModel): # {{{
cname = self.column_map[col] cname = self.column_map[col]
if cname in ('size', 'timestamp', 'inlibrary'): if cname in ('size', 'timestamp', 'inlibrary'):
return False return False
val = unicode(value.toString()).strip() val = unicode(value or '').strip()
idx = self.map[row] idx = self.map[row]
if cname == 'collections': if cname == 'collections':
tags = [i.strip() for i in val.split(',')] tags = [i.strip() for i in val.split(',')]

View File

@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en'
import textwrap, os import textwrap, os
from collections import OrderedDict from collections import OrderedDict
from PyQt5.Qt import (Qt, QModelIndex, QAbstractItemModel, QVariant, QIcon, from PyQt5.Qt import (Qt, QModelIndex, QAbstractItemModel, QIcon,
QBrush) QBrush)
from calibre.gui2.preferences import ConfigWidgetBase, test_widget 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, from calibre.customize.ui import (initialized_plugins, is_disabled, enable_plugin,
disable_plugin, plugin_customization, add_plugin, disable_plugin, plugin_customization, add_plugin,
remove_plugin, NameConflict) 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) question_dialog, gprefs)
from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2.dialogs.confirm_delete import confirm
from calibre.utils.search_query_parser import SearchQueryParser from calibre.utils.search_query_parser import SearchQueryParser
@ -29,9 +29,9 @@ class PluginModel(QAbstractItemModel, SearchQueryParser): # {{{
QAbstractItemModel.__init__(self) QAbstractItemModel.__init__(self)
SearchQueryParser.__init__(self, ['all']) SearchQueryParser.__init__(self, ['all'])
self.show_only_user_plugins = show_only_user_plugins 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) 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._p = p
self.populate() self.populate()
@ -187,11 +187,11 @@ class PluginModel(QAbstractItemModel, SearchQueryParser): # {{{
def data(self, index, role): def data(self, index, role):
if not index.isValid(): if not index.isValid():
return NONE return None
if index.internalId() == 0: if index.internalId() == 0:
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
category = self.categories[index.row()] category = self.categories[index.row()]
return QVariant(_("%(plugin_type)s %(plugins)s")% return (_("%(plugin_type)s %(plugins)s")%
dict(plugin_type=category, plugins=_('plugins'))) dict(plugin_type=category, plugins=_('plugins')))
else: else:
plugin = self.index_to_plugin(index) plugin = self.index_to_plugin(index)
@ -205,14 +205,14 @@ class PluginModel(QAbstractItemModel, SearchQueryParser): # {{{
ans += _('\nCustomization: ')+c ans += _('\nCustomization: ')+c
if disabled: if disabled:
ans += _('\n\nThis plugin has been disabled') ans += _('\n\nThis plugin has been disabled')
return QVariant(ans) return (ans)
if role == Qt.DecorationRole: if role == Qt.DecorationRole:
return self.disabled_icon if disabled else self.icon return self.disabled_icon if disabled else self.icon
if role == Qt.ForegroundRole and disabled: if role == Qt.ForegroundRole and disabled:
return QVariant(QBrush(Qt.gray)) return (QBrush(Qt.gray))
if role == Qt.UserRole: if role == Qt.UserRole:
return plugin return plugin
return NONE return None
# }}} # }}}
@ -333,7 +333,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
index = self.plugin_view.currentIndex() index = self.plugin_view.currentIndex()
if index.isValid(): if index.isValid():
if not index.parent().isValid(): if not index.parent().isValid():
name = unicode(index.data().toString()) name = unicode(index.data() or '')
return error_dialog(self, _('Error'), '<p>'+ return error_dialog(self, _('Error'), '<p>'+
_('Select an actual plugin under <b>%s</b> to customize')%name, _('Select an actual plugin under <b>%s</b> to customize')%name,
show=True, show_copy_button=False) show=True, show_copy_button=False)

View File

@ -398,7 +398,10 @@ class SavedSearchBox(QComboBox): # {{{
class SearchBoxMixin(object): # {{{ 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, self.search.initialize('main_search_history', colorize=True,
help_text=_('Search (For Advanced Search click the button to the left)')) help_text=_('Search (For Advanced Search click the button to the left)'))
self.search.cleared.connect(self.search_box_cleared) self.search.cleared.connect(self.search_box_cleared)
@ -413,7 +416,7 @@ class SearchBoxMixin(object): # {{{
self.search.setMaximumWidth(self.width()-150) self.search.setMaximumWidth(self.width()-150)
self.action_focus_search = QAction(self) self.action_focus_search = QAction(self)
shortcuts = list( shortcuts = list(
map(lambda x:unicode(x.toString()), map(lambda x:unicode(x.toString(QKeySequence.PortableText)),
QKeySequence.keyBindings(QKeySequence.Find))) QKeySequence.keyBindings(QKeySequence.Find)))
shortcuts += ['/', 'Alt+S'] shortcuts += ['/', 'Alt+S']
self.keyboard.register_shortcut('start search', _('Start search'), self.keyboard.register_shortcut('start search', _('Start search'),
@ -478,7 +481,10 @@ class SearchBoxMixin(object): # {{{
class SavedSearchBoxMixin(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.saved_search.changed.connect(self.saved_searches_changed)
self.clear_button.clicked.connect(self.saved_search.clear) self.clear_button.clicked.connect(self.saved_search.clear)
self.save_search_button.clicked.connect( self.save_search_button.clicked.connect(

View File

@ -50,7 +50,7 @@ class SelectNames(QDialog): # {{{
@property @property
def names(self): def names(self):
for item in self._names.selectedItems(): for item in self._names.selectedItems():
yield unicode(item.data(Qt.DisplayRole).toString()) yield unicode(item.data(Qt.DisplayRole) or '')
@property @property
def match_type(self): def match_type(self):
@ -231,7 +231,7 @@ class CreateVirtualLibrary(QDialog): # {{{
return return
self.new_name = self.editing = self.vl_name.currentText() self.new_name = self.editing = self.vl_name.currentText()
self.original_index = dex 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) self.vl_text.setText(self.original_search)
def link_activated(self, url): def link_activated(self, url):
@ -308,7 +308,10 @@ class SearchRestrictionMixin(object):
no_restriction = _('<None>') no_restriction = _('<None>')
def __init__(self): def __init__(self, *args, **kwargs):
pass
def init_search_restirction_mixin(self):
self.checked = QIcon(I('ok.png')) self.checked = QIcon(I('ok.png'))
self.empty = QIcon(I('blank.png')) self.empty = QIcon(I('blank.png'))
self.current_search_action = QAction(self.empty, _('*current search'), self) self.current_search_action = QAction(self.empty, _('*current search'), self)

View File

@ -8,9 +8,8 @@ __docformat__ = 'restructuredtext en'
from operator import attrgetter 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.db.search import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH
from calibre.utils.config_base import prefs from calibre.utils.config_base import prefs
from calibre.utils.icu import sort_key from calibre.utils.icu import sort_key
@ -67,26 +66,26 @@ class BooksModel(QAbstractItemModel):
def headerData(self, section, orientation, role): def headerData(self, section, orientation, role):
if role != Qt.DisplayRole: if role != Qt.DisplayRole:
return NONE return None
text = '' text = ''
if orientation == Qt.Horizontal: if orientation == Qt.Horizontal:
if section < len(self.HEADERS): if section < len(self.HEADERS):
text = self.HEADERS[section] text = self.HEADERS[section]
return QVariant(text) return (text)
else: else:
return QVariant(section+1) return (section+1)
def data(self, index, role): def data(self, index, role):
row, col = index.row(), index.column() row, col = index.row(), index.column()
result = self.books[row] result = self.books[row]
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
if col == 0: if col == 0:
return QVariant(result.title) return (result.title)
elif col == 1: elif col == 1:
return QVariant(result.author) return (result.author)
elif col == 2: elif col == 2:
return QVariant(result.formats) return (result.formats)
return NONE return None
def data_as_text(self, result, col): def data_as_text(self, result, col):
text = '' text = ''

View File

@ -10,11 +10,11 @@ __docformat__ = 'restructuredtext en'
import traceback, cPickle, copy, os 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) QMimeData, QModelIndex, pyqtSignal, QObject)
from calibre.constants import config_dir 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.db.categories import Tag
from calibre.utils.config import tweaks from calibre.utils.config import tweaks
from calibre.utils.icu import sort_key, lower, strcmp, collation_order from calibre.utils.icu import sort_key, lower, strcmp, collation_order
@ -31,7 +31,7 @@ def bf():
if _bf is None: if _bf is None:
_bf = QFont() _bf = QFont()
_bf.setBold(True) _bf.setBold(True)
_bf = QVariant(_bf) _bf = (_bf)
return _bf return _bf
class TagTreeItem(object): # {{{ class TagTreeItem(object): # {{{
@ -48,7 +48,7 @@ class TagTreeItem(object): # {{{
self.id_set = set() self.id_set = set()
self.is_gst = False self.is_gst = False
self.boxed = 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: if self.parent is not None:
self.parent.append(self) self.parent.append(self)
@ -58,7 +58,7 @@ class TagTreeItem(object): # {{{
self.type = self.TAG if category_icon is None else self.CATEGORY self.type = self.TAG if category_icon is None else self.CATEGORY
if self.type == 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.py_name = data
self.category_key = category_key self.category_key = category_key
self.temporary = temporary self.temporary = temporary
@ -67,7 +67,7 @@ class TagTreeItem(object): # {{{
['news', 'search', 'identifiers', 'languages'], ['news', 'search', 'identifiers', 'languages'],
is_searchable=category_key not in ['search']) is_searchable=category_key not in ['search'])
elif self.type == self.TAG: elif self.type == self.TAG:
self.icon_state_map[0] = QVariant(data.icon) self.icon_state_map[0] = (data.icon)
self.tag = data self.tag = data
self.tooltip = (tooltip + ' ') if tooltip else '' self.tooltip = (tooltip + ' ') if tooltip else ''
@ -80,8 +80,8 @@ class TagTreeItem(object): # {{{
if self.type == self.ROOT: if self.type == self.ROOT:
return 'ROOT' return 'ROOT'
if self.type == self.CATEGORY: if self.type == self.CATEGORY:
return 'CATEGORY:'+str(QVariant.toString( return 'CATEGORY:'+str(
self.name))+':%d'%len(getattr(self, self.name)+':%d'%len(getattr(self,
'children', [])) 'children', []))
return 'TAG: %s'%self.tag.name return 'TAG: %s'%self.tag.name
@ -101,13 +101,13 @@ class TagTreeItem(object): # {{{
return self.tag_data(role) return self.tag_data(role)
if self.type == self.CATEGORY: if self.type == self.CATEGORY:
return self.category_data(role) return self.category_data(role)
return NONE return None
def category_data(self, role): def category_data(self, role):
if role == Qt.DisplayRole: 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: if role == Qt.EditRole:
return QVariant(self.py_name) return (self.py_name)
if role == Qt.DecorationRole: if role == Qt.DecorationRole:
if self.tag.state: if self.tag.state:
return self.icon_state_map[self.tag.state] return self.icon_state_map[self.tag.state]
@ -115,8 +115,8 @@ class TagTreeItem(object): # {{{
if role == Qt.FontRole: if role == Qt.FontRole:
return bf() return bf()
if role == Qt.ToolTipRole and self.tooltip is not None: if role == Qt.ToolTipRole and self.tooltip is not None:
return QVariant(self.tooltip) return (self.tooltip)
return NONE return None
def tag_data(self, role): def tag_data(self, role):
tag = self.tag tag = self.tag
@ -136,24 +136,24 @@ class TagTreeItem(object): # {{{
count = len(self.id_set) count = len(self.id_set)
count = count if count > 0 else tag.count count = count if count > 0 else tag.count
if count == 0: if count == 0:
return QVariant('%s'%(name)) return ('%s'%(name))
else: else:
return QVariant('[%d] %s'%(count, name)) return ('[%d] %s'%(count, name))
if role == Qt.EditRole: if role == Qt.EditRole:
return QVariant(tag.original_name) return (tag.original_name)
if role == Qt.DecorationRole: if role == Qt.DecorationRole:
return self.icon_state_map[tag.state] return self.icon_state_map[tag.state]
if role == Qt.ToolTipRole: if role == Qt.ToolTipRole:
if tt_author: if tt_author:
if tag.tooltip is not None: if tag.tooltip is not None:
return QVariant('(%s) %s'%(tag.name, tag.tooltip)) return ('(%s) %s'%(tag.name, tag.tooltip))
else: else:
return QVariant(tag.name) return (tag.name)
if tag.tooltip: if tag.tooltip:
return QVariant(self.tooltip + tag.tooltip) return (self.tooltip + tag.tooltip)
else: else:
return QVariant(self.tooltip) return (self.tooltip)
return NONE return None
def toggle(self, set_to=None): def toggle(self, set_to=None):
''' '''
@ -940,7 +940,7 @@ class TagsModel(QAbstractItemModel): # {{{
def data(self, index, role): def data(self, index, role):
if not index.isValid(): if not index.isValid():
return NONE return None
item = self.get_node(index) item = self.get_node(index)
return item.data(role) 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 # 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 # working with the last item and that item is deleted, in which case
# we position at the parent label # we position at the parent label
val = unicode(value.toString()).strip() val = unicode(value or '').strip()
if not val: if not val:
error_dialog(self.gui_parent, _('Item is blank'), error_dialog(self.gui_parent, _('Item is blank'),
_('An item cannot be set to nothing. Delete it instead.')).exec_() _('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'), error_dialog(self.gui_parent, _('Duplicate search name'),
_('The saved search name %s is already used.')%val).exec_() _('The saved search name %s is already used.')%val).exec_()
return False 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 item.tag.name = val
self.search_item_renamed.emit() # Does a refresh self.search_item_renamed.emit() # Does a refresh
else: else:
@ -1079,7 +1079,7 @@ class TagsModel(QAbstractItemModel): # {{{
self.db.prefs.set('user_categories', user_cats) self.db.prefs.set('user_categories', user_cats)
def headerData(self, *args): def headerData(self, *args):
return NONE return None
def flags(self, index, *args): def flags(self, index, *args):
ans = Qt.ItemIsEnabled|Qt.ItemIsEditable ans = Qt.ItemIsEnabled|Qt.ItemIsEditable

View File

@ -25,7 +25,10 @@ from calibre.gui2.dialogs.edit_authors_dialog import EditAuthorsDialog
class TagBrowserMixin(object): # {{{ 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.library_view.model().count_changed_signal.connect(self.tags_view.recount)
self.tags_view.set_database(db, self.alter_tb) self.tags_view.set_database(db, self.alter_tb)
self.tags_view.tags_marked.connect(self.search.set_search_string) self.tags_view.tags_marked.connect(self.search.set_search_string)

View File

@ -245,7 +245,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
_('&Donate to support calibre'), self) _('&Donate to support calibre'), self)
for st in self.istores.values(): for st in self.istores.values():
st.do_genesis() st.do_genesis()
MainWindowMixin.__init__(self, db) MainWindowMixin.init_main_window_mixin(self, db)
# Jobs Button {{{ # Jobs Button {{{
self.job_manager = JobManager() self.job_manager = JobManager()
@ -254,10 +254,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
self.jobs_button.initialize(self.jobs_dialog, self.job_manager) self.jobs_button.initialize(self.jobs_dialog, self.job_manager)
# }}} # }}}
LayoutMixin.__init__(self) LayoutMixin.init_layout_mixin(self)
EmailMixin.__init__(self) DeviceMixin.init_device_mixin(self)
EbookDownloadMixin.__init__(self)
DeviceMixin.__init__(self)
self.progress_indicator = ProgressIndicator(self) self.progress_indicator = ProgressIndicator(self)
self.progress_indicator.pos = (0, 20) 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) self.eject_action.triggered.connect(self.device_manager.umount_device)
#################### Update notification ################### #################### Update notification ###################
UpdateMixin.__init__(self, opts) UpdateMixin.init_update_mixin(self, opts)
####################### Search boxes ######################## ####################### Search boxes ########################
SearchRestrictionMixin.__init__(self) SearchRestrictionMixin.init_search_restirction_mixin(self)
SavedSearchBoxMixin.__init__(self) SavedSearchBoxMixin.init_saved_seach_box_mixin(self)
####################### Library view ######################## ####################### Library view ########################
LibraryViewMixin.__init__(self, db) LibraryViewMixin.init_library_view_mixin(self, db)
SearchBoxMixin.__init__(self) # Requires current_db SearchBoxMixin.init_search_box_mixin(self) # Requires current_db
if show_gui: if show_gui:
self.show() self.show()
@ -369,7 +367,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
type=Qt.QueuedConnection) type=Qt.QueuedConnection)
########################### Tags Browser ############################## ########################### Tags Browser ##############################
TagBrowserMixin.__init__(self, db) TagBrowserMixin.init_tag_browser_mixin(self, db)
######################### Search Restriction ########################## ######################### Search Restriction ##########################
if db.prefs['virtual_lib_on_startup']: if db.prefs['virtual_lib_on_startup']:
@ -378,7 +376,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
########################### Cover Flow ################################ ########################### Cover Flow ################################
CoverFlowMixin.__init__(self) CoverFlowMixin.init_cover_flow_mixin(self)
self._calculated_available_height = min(max_available_height()-15, self._calculated_available_height = min(max_available_height()-15,
self.height()) self.height())

View File

@ -134,7 +134,10 @@ class UpdateNotification(QDialog):
class UpdateMixin(object): 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 self.last_newest_calibre_version = NO_CALIBRE_UPDATE
if not opts.no_update_check: if not opts.no_update_check:
self.update_checker = CheckForUpdates(self) self.update_checker = CheckForUpdates(self)

View File

@ -8,11 +8,10 @@ __docformat__ = 'restructuredtext en'
import copy, zipfile 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 QModelIndex, pyqtSignal, QPixmap
from calibre.utils.search_query_parser import SearchQueryParser from calibre.utils.search_query_parser import SearchQueryParser
from calibre.gui2 import NONE
from calibre.utils.localization import get_language from calibre.utils.localization import get_language
from calibre.web.feeds.recipes.collection import \ from calibre.web.feeds.recipes.collection import \
get_builtin_recipe_collection, get_custom_recipe_collection, \ get_builtin_recipe_collection, get_custom_recipe_collection, \
@ -41,7 +40,7 @@ class NewsTreeItem(object):
self.children.append(child) self.children.append(child)
def data(self, role): def data(self, role):
return NONE return None
def flags(self): def flags(self):
return Qt.ItemIsEnabled|Qt.ItemIsSelectable return Qt.ItemIsEnabled|Qt.ItemIsSelectable
@ -65,16 +64,16 @@ class NewsCategory(NewsTreeItem):
self.cdata = get_language(self.category) self.cdata = get_language(self.category)
self.bold_font = QFont() self.bold_font = QFont()
self.bold_font.setBold(True) self.bold_font.setBold(True)
self.bold_font = QVariant(self.bold_font) self.bold_font = (self.bold_font)
def data(self, role): def data(self, role):
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
return QVariant(self.cdata + ' [%d]'%len(self.children)) return (self.cdata + ' [%d]'%len(self.children))
elif role == Qt.FontRole: elif role == Qt.FontRole:
return self.bold_font return self.bold_font
elif role == Qt.ForegroundRole and self.category == _('Scheduled'): elif role == Qt.ForegroundRole and self.category == _('Scheduled'):
return QVariant(QColor(0, 255, 0)) return (QColor(0, 255, 0))
return NONE return None
def flags(self): def flags(self):
return Qt.ItemIsEnabled return Qt.ItemIsEnabled
@ -106,7 +105,7 @@ class NewsItem(NewsTreeItem):
def data(self, role): def data(self, role):
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
return QVariant(self.title) return (self.title)
if role == Qt.DecorationRole: if role == Qt.DecorationRole:
if self.icon is None: if self.icon is None:
icon = '%s.png'%self.urn[8:] icon = '%s.png'%self.urn[8:]
@ -118,11 +117,11 @@ class NewsItem(NewsTreeItem):
except: except:
pass pass
if not p.isNull(): if not p.isNull():
self.icon = QVariant(QIcon(p)) self.icon = (QIcon(p))
else: else:
self.icon = self.default_icon self.icon = self.default_icon
return self.icon return self.icon
return NONE return None
def __cmp__(self, other): def __cmp__(self, other):
return cmp(self.title.lower(), getattr(other, 'title', '').lower()) return cmp(self.title.lower(), getattr(other, 'title', '').lower())
@ -135,8 +134,8 @@ class RecipeModel(QAbstractItemModel, SearchQueryParser):
def __init__(self, *args): def __init__(self, *args):
QAbstractItemModel.__init__(self, *args) QAbstractItemModel.__init__(self, *args)
SearchQueryParser.__init__(self, locations=['all']) SearchQueryParser.__init__(self, locations=['all'])
self.default_icon = QVariant(QIcon(I('news.png'))) self.default_icon = (QIcon(I('news.png')))
self.custom_icon = QVariant(QIcon(I('user_profile.png'))) self.custom_icon = (QIcon(I('user_profile.png')))
self.builtin_recipe_collection = get_builtin_recipe_collection() self.builtin_recipe_collection = get_builtin_recipe_collection()
self.scheduler_config = SchedulerConfig() self.scheduler_config = SchedulerConfig()
try: try:
@ -300,12 +299,12 @@ class RecipeModel(QAbstractItemModel, SearchQueryParser):
def data(self, index, role): def data(self, index, role):
if not index.isValid(): if not index.isValid():
return NONE return None
item = index.internalPointer() item = index.internalPointer()
return item.data(role) return item.data(role)
def headerData(self, *args): def headerData(self, *args):
return NONE return None
def flags(self, index): def flags(self, index):
if not index.isValid(): if not index.isValid():