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
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 {

View File

@ -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,

View File

@ -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()):

View File

@ -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',

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>'
__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):

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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'))

View File

@ -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

View File

@ -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):

View File

@ -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:

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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__)

View File

@ -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 <b>edit</b> me<br><br>"))
return NONE
# return (_("Double click to <b>edit</b> me<br><br>"))
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 <b>edit</b> me<br><br>"))
return (_("Double click to <b>edit</b> me<br><br>"))
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(',')]

View File

@ -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'), '<p>'+
_('Select an actual plugin under <b>%s</b> to customize')%name,
show=True, show_copy_button=False)

View File

@ -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(

View File

@ -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 = _('<None>')
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)

View File

@ -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 = ''

View File

@ -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

View File

@ -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)

View File

@ -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())

View File

@ -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)

View File

@ -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():