def setup_store_checks(self): first_run = self.config.get('first_run', True) # Add check boxes for each store so the user # can disable searching specific stores on a # per search basis. existing = {} for n in self.store_checks: existing[n] = self.store_checks[n].isChecked() self.store_checks = {} stores_check_widget = QWidget() store_list_layout = QGridLayout() stores_check_widget.setLayout(store_list_layout) icon = QIcon(I('donate.png')) for i, x in enumerate(sorted(self.gui.istores.keys(), key=lambda x: x.lower())): cbox = QCheckBox(x) cbox.setChecked(existing.get(x, first_run)) store_list_layout.addWidget(cbox, i, 0, 1, 1) if self.gui.istores[x].base_plugin.affiliate: iw = QLabel(self) iw.setToolTip('<p>' + _('Buying from this store supports the calibre developer: %s</p>') % self.gui.istores[x].base_plugin.author + '</p>') iw.setPixmap(icon.pixmap(16, 16)) store_list_layout.addWidget(iw, i, 1, 1, 1) self.store_checks[x] = cbox store_list_layout.setRowStretch(store_list_layout.rowCount(), 10) self.store_list.setWidget(stores_check_widget) self.config['first_run'] = False
def slotEditUser(self, item=None): if not item: item = self.ui.userList.currentItem() self.ui.userList.setCurrentItem(item) user = item.getUser() if user.uid > -1: self.ui.userIDCheck.setChecked(True) self.ui.userID.setValue(user.uid) self.ui.username.setText(user.username) self.ui.realname.setText(user.realname) self.ui.pass1.setText(user.passwd) self.ui.pass2.setText(user.passwd) if "wheel" in user.groups: self.ui.admin.setChecked(True) else: self.ui.admin.setChecked(False) self.ui.noPass.setChecked(user.no_password) self.edititemindex = self.ui.userList.currentRow() self.ui.createButton.setText(_("Update")) icon = QIcon() icon.addPixmap(QPixmap(":/gui/pics/tick.png"), QIcon.Normal, QIcon.Off) self.ui.createButton.setIcon(icon) self.ui.cancelButton.setVisible(self.ui.createButton.isVisible())
class CompletionCandidate: def __init__(self, place_id, url, title, substrings): self.value = url self.place_id = place_id def get_positions(text): ans = set() text = text.lower() for ss in substrings: idx = text.find(ss.lower()) if idx > -1: ans |= set(range(idx, idx + len(ss))) return sorted(ans) self.left = make_highlighted_text(url, get_positions(url)) self.right = make_highlighted_text(title, get_positions(title)) self._icon = None def adjust_size_hint(self, option, ans): ans.setHeight(max(option.decorationSize.height() + 6, ans.height())) @property def icon(self): if self._icon is None: self._icon = QIcon() url = places.favicon_url(self.place_id) if url is not None: f = QApplication.instance().disk_cache.data(QUrl(url)) if f is not None: with closing(f): raw = f.readAll() p = QPixmap() p.loadFromData(raw) if not p.isNull(): self._icon.addPixmap(p) return self._icon def __repr__(self): return self.value def draw_item(self, painter, style, option): option.features |= option.HasDecoration option.icon = self.icon text_rect = style.subElementRect(style.SE_ItemViewItemText, option, None) x, y = text_rect.x(), text_rect.y() y += (text_rect.height() - self.left.size().height()) // 2 if not option.icon.isNull(): icon_rect = style.subElementRect(style.SE_ItemViewItemDecoration, option, None) icon_rect.setTop(y), icon_rect.setBottom(text_rect.bottom()) option.icon.paint(painter, icon_rect) option.icon = QIcon() width = (text_rect.width() // 2) - 10 painter.setClipRect(x, text_rect.y(), width, text_rect.height()) painter.drawStaticText(QPoint(x, y), self.left) painter.setClipRect(text_rect) x += width + 20 painter.drawStaticText(QPoint(x, y), self.right)
def load_menu(self): self.store_list_menu.clear() icon = QIcon() icon.addFile(I('donate.png'), QSize(16, 16)) for n, p in sorted(self.gui.istores.items(), key=lambda x: x[0].lower()): if p.base_plugin.affiliate: self.store_list_menu.addAction(icon, n, partial(self.open_store, n)) else: self.store_list_menu.addAction(n, partial(self.open_store, n))
def finalize_entry(entry): icon_path = entry.get('Icon') if icon_path: ic = QIcon(icon_path) if not ic.isNull(): pmap = ic.pixmap(48, 48) if not pmap.isNull(): entry['icon_data'] = pixmap_to_data(pmap) entry['MimeType'] = tuple(entry['MimeType']) return entry
def slotAdvanced(self): icon_path = None if self.ui.scrollArea.isVisible(): icon_path = ":/gui/pics/expand.png" self.time_line.start() else: self.ui.scrollArea.show() icon_path = ":/gui/pics/collapse.png" self.time_line.start() icon = QIcon() icon.addPixmap(QPixmap(icon_path), QIcon.Normal, QIcon.Off) self.ui.addMoreUsers.setIcon(icon) self.checkUsers()
def cached_emblem(self, cache, name, raw_icon=None): ans = cache.get(name, False) if ans is not False: return ans sz = self.emblem_size ans = None if raw_icon is not None: ans = raw_icon.pixmap(sz, sz) elif name == ':ondevice': ans = QIcon(I('ok.png')).pixmap(sz, sz) elif name: pmap = QIcon(os.path.join(config_dir, 'cc_icons', name)).pixmap(sz, sz) if not pmap.isNull(): ans = pmap cache[name] = ans return ans
def slotDeleteUser(self): if self.ui.userList.currentRow() == self.edititemindex: self.resetWidgets() self.ui.autoLogin.setCurrentIndex(0) _cur = self.ui.userList.currentRow() item = self.ui.userList.item(_cur).getUser() if item.uid in self.used_ids: self.used_ids.remove(item.uid) self.ui.userList.takeItem(_cur) self.ui.autoLogin.removeItem(_cur + 1) self.ui.createButton.setText(_("Add")) icon = QIcon() icon.addPixmap(QPixmap(":/gui/pics/user-group-new.png"), QIcon.Normal, QIcon.Off) self.ui.createButton.setIcon(icon) self.ui.cancelButton.hide() self.checkUsers()
def resetWidgets(self): # clear all self.edititemindex = None self.ui.username.clear() self.ui.realname.clear() self.ui.pass1.clear() self.ui.pass2.clear() self.ui.admin.setChecked(False) self.ui.noPass.setChecked(False) self.ui.userIDCheck.setChecked(False) self.ui.createButton.setEnabled(False) if self.ui.cancelButton.isVisible(): self.ui.cancelButton.setHidden(self.sender() == self.ui.cancelButton) self.checkUsers() self.ui.createButton.setText(_("Add")) icon = QIcon() icon.addPixmap(QPixmap(":/gui/pics/user-group-new.png"), QIcon.Normal, QIcon.Off) self.ui.createButton.setIcon(icon)
def change_icon(self): ci = self.plist.currentItem() if ci is None: return error_dialog(self, _('No selection'), _( 'No application selected'), show=True) paths = choose_images(self, 'choose-new-icon-for-open-with-program', _( 'Choose new icon')) if paths: ic = QIcon(paths[0]) if ic.isNull(): return error_dialog(self, _('Invalid icon'), _( 'Could not load image from %s') % paths[0], show=True) pmap = ic.pixmap(48, 48) if not pmap.isNull(): entry = ci.data(ENTRY_ROLE) entry['icon_data'] = pixmap_to_data(pmap) ci.setData(ENTRY_ROLE, entry) self.update_stored_config() ci.setIcon(ic)
def __init__(self, title, msg=u'\u00a0', min=0, max=99, parent=None, cancelable=True, icon=None): QDialog.__init__(self, parent) if icon is None: self.l = l = QVBoxLayout(self) else: self.h = h = QHBoxLayout(self) self.icon = i = QLabel(self) if not isinstance(icon, QIcon): icon = QIcon(I(icon)) i.setPixmap(icon.pixmap(64)) h.addWidget(i, alignment=Qt.AlignTop | Qt.AlignHCenter) self.l = l = QVBoxLayout() h.addLayout(l) self.setWindowIcon(icon) self.title_label = t = QLabel(title) self.setWindowTitle(title) t.setStyleSheet('QLabel { font-weight: bold }'), t.setAlignment(Qt.AlignCenter), t.setTextFormat(Qt.PlainText) l.addWidget(t) self.bar = b = QProgressBar(self) b.setMinimum(min), b.setMaximum(max), b.setValue(min) l.addWidget(b) self.message = m = QLabel(self) fm = QFontMetrics(self.font()) m.setAlignment(Qt.AlignCenter), m.setMinimumWidth(fm.averageCharWidth() * 80), m.setTextFormat(Qt.PlainText) l.addWidget(m) self.msg = msg self.button_box = bb = QDialogButtonBox(QDialogButtonBox.Abort, self) bb.rejected.connect(self._canceled) l.addWidget(bb) self.setWindowModality(Qt.ApplicationModal) self.canceled = False if not cancelable: bb.setVisible(False) self.cancelable = cancelable self.resize(self.sizeHint())
def icon(self): if self._icon is None: self._icon = QIcon() url = places.favicon_url(self.place_id) if url is not None: f = QApplication.instance().disk_cache.data(QUrl(url)) if f is not None: with closing(f): raw = f.readAll() p = QPixmap() p.loadFromData(raw) if not p.isNull(): self._icon.addPixmap(p) return self._icon
def __init__(self, plugins): QAbstractItemModel.__init__(self) self.NO_DRM_ICON = QIcon(I('ok.png')) self.DONATE_ICON = QIcon() self.DONATE_ICON.addFile(I('donate.png'), QSize(16, 16)) self.all_matches = plugins self.matches = plugins self.filter = '' self.search_filter = SearchFilter(self.all_matches) self.sort_col = 1 self.sort_order = Qt.AscendingOrder
def icon_data_for_filename(fname, size=64): ''' Return the file type icon (as bytes) for the given filename ''' raw = b'' if fname: if not hasattr(icon_data_for_filename, 'md'): icon_data_for_filename.md = QMimeDatabase() for mt in icon_data_for_filename.md.mimeTypesForFileName(fname): icname = mt.iconName() if icname: ic = QIcon.fromTheme(icname) if not ic.isNull(): raw = icon_to_data(ic) if raw: break return raw
def __init__(self, parent): QDialog.__init__(self, parent) self.setAttribute(Qt.WA_DeleteOnClose, False) self.queue = [] self.do_pop.connect(self.pop, type=Qt.QueuedConnection) self._layout = l = QGridLayout() self.setLayout(l) self.icon = QIcon(I('dialog_error.png')) self.setWindowIcon(self.icon) self.icon_label = QLabel() self.icon_label.setPixmap(self.icon.pixmap(68, 68)) self.icon_label.setMaximumSize(QSize(68, 68)) self.msg_label = QLabel('<p> ') self.msg_label.setStyleSheet('QLabel { margin-top: 1ex; }') self.msg_label.setWordWrap(True) self.msg_label.setTextFormat(Qt.RichText) self.det_msg = QPlainTextEdit(self) self.det_msg.setVisible(False) self.bb = QDialogButtonBox(QDialogButtonBox.Close, parent=self) self.bb.accepted.connect(self.accept) self.bb.rejected.connect(self.reject) self.ctc_button = self.bb.addButton(_('&Copy to clipboard'), self.bb.ActionRole) self.ctc_button.clicked.connect(self.copy_to_clipboard) self.retry_button = self.bb.addButton(_('&Retry'), self.bb.ActionRole) self.retry_button.clicked.connect(self.retry) self.retry_func = None self.show_det_msg = _('Show &details') self.hide_det_msg = _('Hide &details') self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole) self.det_msg_toggle.clicked.connect(self.toggle_det_msg) self.det_msg_toggle.setToolTip( _('Show detailed information about this error')) self.suppress = QCheckBox(self) l.addWidget(self.icon_label, 0, 0, 1, 1) l.addWidget(self.msg_label, 0, 1, 1, 1) l.addWidget(self.det_msg, 1, 0, 1, 2) l.addWidget(self.suppress, 2, 0, 1, 2, Qt.AlignLeft|Qt.AlignBottom) l.addWidget(self.bb, 3, 0, 1, 2, Qt.AlignRight|Qt.AlignBottom) l.setColumnStretch(1, 100) self.setModal(False) self.suppress.setVisible(False) self.do_resize()
def slotCheckCD(self): if self.check_media_stop: self.check_media_stop = False self.ui.progressBar.show() icon = QIcon() icon.addPixmap(QPixmap(":/gui/pics/dialog-error.png"), QIcon.Normal, QIcon.Off) self.ui.checkButton.setIcon(icon) self.ui.checkButton.setText("") self.checkMedia() else: self.check_media_stop = True self.ui.progressBar.show() icon = QIcon() icon.addPixmap(QPixmap(":/gui/pics/task-accepted.png"), QIcon.Normal, QIcon.Off) self.ui.checkButton.setIcon(icon) self.ui.checkButton.setText(_("Validate"))
def contextMenuEvent(self, event): if self.item != None: menu = QMenu(self.parent()) self.actionUpdate = QtWidgets.QAction(self.parent()) icon = QIcon() icon.addPixmap(QPixmap(":/icons/16x16/update"), QIcon.Normal, QIcon.Off) self.actionUpdate.setIcon(icon) self.actionUpdate.setObjectName(self.item.name) self.actionUpdate.setText("Update") self.actionUpdate.triggered.connect(self.onUpdate) menu.addAction(self.actionUpdate) self.actionDelete = QtWidgets.QAction(self.parent()) icon = QIcon() icon.addPixmap(QPixmap(":/icons/16x16/delete"), QIcon.Normal, QIcon.Off) self.actionDelete.setIcon(icon) self.actionDelete.setObjectName(self.item.name) self.actionDelete.setText("Supprimer") self.actionDelete.triggered.connect(self.onDelete) menu.addAction(self.actionDelete) menu.exec_(self.mapToGlobal(event.pos()))
def setup_ui(self): self.l = l = QGridLayout(self) self.setLayout(l) self.la1 = la = QLabel(_('&Existing images in the book')) la.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) l.addWidget(la, 0, 0, 1, 2) if self.for_browsing: la.setVisible(False) self.view = v = QListView(self) v.setViewMode(v.IconMode) v.setFlow(v.LeftToRight) v.setSpacing(4) v.setResizeMode(v.Adjust) v.setUniformItemSizes(True) pi = plugins['progress_indicator'][0] if hasattr(pi, 'set_no_activate_on_click'): pi.set_no_activate_on_click(v) v.activated.connect(self.activated) v.doubleClicked.connect(self.activated) self.d = ImageDelegate(v) v.setItemDelegate(self.d) self.model = Images(self.view) self.fm = fm = QSortFilterProxyModel(self.view) self.fm.setDynamicSortFilter(self.for_browsing) fm.setSourceModel(self.model) fm.setFilterCaseSensitivity(False) v.setModel(fm) l.addWidget(v, 1, 0, 1, 2) v.pressed.connect(self.pressed) la.setBuddy(v) self.filter = f = QLineEdit(self) f.setPlaceholderText(_('Search for image by file name')) l.addWidget(f, 2, 0) self.cb = b = QToolButton(self) b.setIcon(QIcon(I('clear_left.png'))) b.clicked.connect(f.clear) l.addWidget(b, 2, 1) f.textChanged.connect(self.filter_changed) if self.for_browsing: self.bb.clear() self.bb.addButton(self.bb.Close) b = self.refresh_button = self.bb.addButton( _('&Refresh'), self.bb.ActionRole) b.clicked.connect(self.refresh) b.setIcon(QIcon(I('view-refresh.png'))) b.setToolTip(_('Refresh the displayed images')) self.setAttribute(Qt.WA_DeleteOnClose, False) else: b = self.import_button = self.bb.addButton(_('&Import image'), self.bb.ActionRole) b.clicked.connect(self.import_image) b.setIcon(QIcon(I('view-image.png'))) b.setToolTip(_('Import an image from elsewhere in your computer')) b = self.paste_button = self.bb.addButton(_('&Paste image'), self.bb.ActionRole) b.clicked.connect(self.paste_image) b.setIcon(QIcon(I('edit-paste.png'))) b.setToolTip(_('Paste an image from the clipboard')) self.fullpage = f = QCheckBox(_('Full page image'), self) f.setToolTip( _('Insert the image so that it takes up an entire page when viewed in a reader' )) f.setChecked(tprefs['insert_full_screen_image']) self.preserve_aspect_ratio = a = QCheckBox( _('Preserve aspect ratio')) a.setToolTip( _('Preserve the aspect ratio of the inserted image when rendering it full paged' )) a.setChecked(tprefs['preserve_aspect_ratio_when_inserting_image']) f.toggled.connect( lambda: (tprefs.set('insert_full_screen_image', f.isChecked()), a.setVisible(f.isChecked()))) a.toggled.connect(lambda: tprefs.set( 'preserve_aspect_ratio_when_inserting_image', a.isChecked())) a.setVisible(f.isChecked()) h = QHBoxLayout() l.addLayout(h, 3, 0, 1, -1) h.addWidget(f), h.addStretch(10), h.addWidget(a) l.addWidget(self.bb, 4, 0, 1, 2)
class MessageBox(QDialog): # {{{ ERROR = 0 WARNING = 1 INFO = 2 QUESTION = 3 resize_needed = pyqtSignal() def setup_ui(self): self.setObjectName("Dialog") self.resize(497, 235) self.gridLayout = l = QGridLayout(self) l.setObjectName("gridLayout") self.icon_label = la = QLabel('') la.setMaximumSize(QSize(68, 68)) la.setScaledContents(True) la.setObjectName("icon_label") l.addWidget(la) self.msg = la = QLabel(self) la.setWordWrap(True), la.setMinimumWidth(400) la.setOpenExternalLinks(True) la.setObjectName("msg") l.addWidget(la, 0, 1, 1, 1) self.det_msg = dm = QPlainTextEdit(self) dm.setReadOnly(True) dm.setObjectName("det_msg") l.addWidget(dm, 1, 0, 1, 2) self.bb = bb = QDialogButtonBox(self) bb.setStandardButtons(QDialogButtonBox.Ok) bb.setObjectName("bb") bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) l.addWidget(bb, 3, 0, 1, 2) self.toggle_checkbox = tc = QCheckBox(self) tc.setObjectName("toggle_checkbox") l.addWidget(tc, 2, 0, 1, 2) def __init__(self, type_, title, msg, det_msg='', q_icon=None, show_copy_button=True, parent=None, default_yes=True, yes_text=None, no_text=None, yes_icon=None, no_icon=None): QDialog.__init__(self, parent) if q_icon is None: icon = { self.ERROR : 'error', self.WARNING: 'warning', self.INFO: 'information', self.QUESTION: 'question', }[type_] icon = 'dialog_%s.png'%icon self.icon = QIcon(I(icon)) else: self.icon = q_icon if isinstance(q_icon, QIcon) else QIcon(I(q_icon)) self.setup_ui() self.setWindowTitle(title) self.setWindowIcon(self.icon) self.icon_label.setPixmap(self.icon.pixmap(128, 128)) self.msg.setText(msg) self.det_msg.setPlainText(det_msg) self.det_msg.setVisible(False) self.toggle_checkbox.setVisible(False) if show_copy_button: self.ctc_button = self.bb.addButton(_('&Copy to clipboard'), self.bb.ActionRole) self.ctc_button.clicked.connect(self.copy_to_clipboard) self.show_det_msg = _('Show &details') self.hide_det_msg = _('Hide &details') self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole) self.det_msg_toggle.clicked.connect(self.toggle_det_msg) self.det_msg_toggle.setToolTip( _('Show detailed information about this error')) self.copy_action = QAction(self) self.addAction(self.copy_action) self.copy_action.setShortcuts(QKeySequence.Copy) self.copy_action.triggered.connect(self.copy_to_clipboard) self.is_question = type_ == self.QUESTION if self.is_question: self.bb.setStandardButtons(self.bb.Yes|self.bb.No) self.bb.button(self.bb.Yes if default_yes else self.bb.No ).setDefault(True) self.default_yes = default_yes if yes_text is not None: self.bb.button(self.bb.Yes).setText(yes_text) if no_text is not None: self.bb.button(self.bb.No).setText(no_text) if yes_icon is not None: self.bb.button(self.bb.Yes).setIcon(yes_icon if isinstance(yes_icon, QIcon) else QIcon(I(yes_icon))) if no_icon is not None: self.bb.button(self.bb.No).setIcon(no_icon if isinstance(no_icon, QIcon) else QIcon(I(no_icon))) else: self.bb.button(self.bb.Ok).setDefault(True) if not det_msg: self.det_msg_toggle.setVisible(False) self.resize_needed.connect(self.do_resize, type=Qt.QueuedConnection) self.do_resize() def sizeHint(self): ans = QDialog.sizeHint(self) ans.setWidth(max(min(ans.width(), 500), self.bb.sizeHint().width() + 100)) ans.setHeight(min(ans.height(), 500)) return ans def toggle_det_msg(self, *args): vis = self.det_msg.isVisible() self.det_msg.setVisible(not vis) self.det_msg_toggle.setText(self.show_det_msg if vis else self.hide_det_msg) self.resize_needed.emit() def do_resize(self): self.resize(self.sizeHint()) def copy_to_clipboard(self, *args): QApplication.clipboard().setText( 'calibre, version %s\n%s: %s\n\n%s' % (__version__, unicode(self.windowTitle()), unicode(self.msg.text()), unicode(self.det_msg.toPlainText()))) if hasattr(self, 'ctc_button'): self.ctc_button.setText(_('Copied')) def showEvent(self, ev): ret = QDialog.showEvent(self, ev) if self.is_question: try: self.bb.button(self.bb.Yes if self.default_yes else self.bb.No ).setFocus(Qt.OtherFocusReason) except: pass # Buttons were changed else: self.bb.button(self.bb.Ok).setFocus(Qt.OtherFocusReason) return ret def set_details(self, msg): if not msg: msg = '' self.det_msg.setPlainText(msg) self.det_msg_toggle.setText(self.show_det_msg) self.det_msg_toggle.setVisible(bool(msg)) self.det_msg.setVisible(False) self.resize_needed.emit()
class Matches(QAbstractItemModel): HEADERS = [_('Enabled'), _('Name'), _('No DRM'), _('Headquarters'), _('Affiliate'), _('Formats')] HTML_COLS = [1] def __init__(self, plugins): QAbstractItemModel.__init__(self) self.NO_DRM_ICON = QIcon(I('ok.png')) self.DONATE_ICON = QIcon() self.DONATE_ICON.addFile(I('donate.png'), QSize(16, 16)) self.all_matches = plugins self.matches = plugins self.filter = '' self.search_filter = SearchFilter(self.all_matches) self.sort_col = 1 self.sort_order = Qt.AscendingOrder def get_plugin(self, index): row = index.row() if row < len(self.matches): return self.matches[row] else: return None def search(self, filter): self.filter = filter.strip() if not self.filter: self.matches = self.all_matches else: try: self.matches = list(self.search_filter.parse(self.filter)) except: self.matches = self.all_matches self.layoutChanged.emit() self.sort(self.sort_col, self.sort_order) def enable_all(self): for i in xrange(len(self.matches)): index = self.createIndex(i, 0) data = (True) self.setData(index, data, Qt.CheckStateRole) def enable_none(self): for i in xrange(len(self.matches)): index = self.createIndex(i, 0) data = (False) self.setData(index, data, Qt.CheckStateRole) def enable_invert(self): for i in xrange(len(self.matches)): self.toggle_plugin(self.createIndex(i, 0)) def toggle_plugin(self, index): new_index = self.createIndex(index.row(), 0) data = (is_disabled(self.get_plugin(index))) self.setData(new_index, data, Qt.CheckStateRole) def index(self, row, column, parent=QModelIndex()): return self.createIndex(row, column) def parent(self, index): if not index.isValid() or index.internalId() == 0: return QModelIndex() return self.createIndex(0, 0) def rowCount(self, *args): return len(self.matches) def columnCount(self, *args): return len(self.HEADERS) def headerData(self, section, orientation, role): if role != Qt.DisplayRole: return None text = '' if orientation == Qt.Horizontal: if section < len(self.HEADERS): text = self.HEADERS[section] return (text) else: return (section+1) def data(self, index, role): row, col = index.row(), index.column() result = self.matches[row] if role in (Qt.DisplayRole, Qt.EditRole): if col == 1: return ('<b>%s</b><br><i>%s</i>' % (result.name, result.description)) elif col == 3: return (result.headquarters) elif col == 5: return (', '.join(result.formats).upper()) elif role == Qt.DecorationRole: if col == 2: if result.drm_free_only: return (self.NO_DRM_ICON) if col == 4: if result.affiliate: return (self.DONATE_ICON) elif role == Qt.CheckStateRole: if col == 0: if is_disabled(result): return Qt.Unchecked return Qt.Checked elif role == Qt.ToolTipRole: if col == 0: if is_disabled(result): return ('<p>' + _('This store is currently disabled and cannot be used in other parts of calibre.') + '</p>') else: return ('<p>' + _('This store is currently enabled and can be used in other parts of calibre.') + '</p>') elif col == 1: return ('<p>%s</p>' % result.description) elif col == 2: if result.drm_free_only: return ('<p>' + _('This store only distributes e-books without DRM.') + '</p>') else: return ('<p>' + _('This store distributes e-books with DRM. It may have some titles without DRM, but you will need to check on a per title basis.') + '</p>') # noqa elif col == 3: return ('<p>' + _('This store is headquartered in %s. This is a good indication of what market the store caters to. However, this does not necessarily mean that the store is limited to that market only.') % result.headquarters + '</p>') # noqa elif col == 4: if result.affiliate: return ('<p>' + _('Buying from this store supports the calibre developer: %s.') % result.author + '</p>') elif col == 5: return ('<p>' + _('This store distributes e-books in the following formats: %s') % ', '.join(result.formats) + '</p>') return None def setData(self, index, data, role): if not index.isValid(): return False col = index.column() if col == 0: if bool(data): enable_plugin(self.get_plugin(index)) else: disable_plugin(self.get_plugin(index)) self.dataChanged.emit(self.index(index.row(), 0), self.index(index.row(), self.columnCount() - 1)) return True def flags(self, index): if index.column() == 0: return QAbstractItemModel.flags(self, index) | Qt.ItemIsUserCheckable return QAbstractItemModel.flags(self, index) def data_as_text(self, match, col): text = '' if col == 0: text = 'b' if is_disabled(match) else 'a' elif col == 1: text = match.name elif col == 2: text = 'a' if getattr(match, 'drm_free_only', True) else 'b' elif col == 3: text = getattr(match, 'headquarters', '') elif col == 4: text = 'a' if getattr(match, 'affiliate', False) else 'b' return text def sort(self, col, order, reset=True): self.sort_col = col self.sort_order = order if not self.matches: return descending = order == Qt.DescendingOrder self.matches.sort(None, lambda x: sort_key(unicode(self.data_as_text(x, col))), descending) if reset: self.beginResetModel(), self.endResetModel()
def __init__(self, gui, initial_plugin=None, close_after_initial=False): QDialog.__init__(self, gui) self.gui = gui self.must_restart = False self.do_restart = False self.committed = False self.close_after_initial = close_after_initial self.resize(930, 720) nh, nw = min_available_height() - 25, available_width() - 10 if nh < 0: nh = 800 if nw < 0: nw = 600 nh = min(self.height(), nh) nw = min(self.width(), nw) self.resize(nw, nh) geom = gprefs.get('preferences dialog geometry', None) if geom is not None: self.restoreGeometry(geom) # Center if islinux: self.move(gui.rect().center() - self.rect().center()) self.setWindowModality(Qt.ApplicationModal) self.setWindowTitle(__appname__ + ' - ' + _('Preferences')) self.setWindowIcon(QIcon(I('config.png'))) self.l = l = QVBoxLayout(self) self.stack = QStackedWidget(self) self.bb = QDialogButtonBox(QDialogButtonBox.Close | QDialogButtonBox.Apply | QDialogButtonBox.Discard | QDialogButtonBox.RestoreDefaults) self.bb.button(self.bb.Apply).clicked.connect(self.accept) self.bb.button(self.bb.Discard).clicked.connect(self.reject) self.bb.button(self.bb.RestoreDefaults).setIcon( QIcon(I('clear_left.png'))) self.bb.button(self.bb.RestoreDefaults).clicked.connect( self.restore_defaults) self.wizard_button = self.bb.addButton(_('Run Welcome &wizard'), self.bb.ActionRole) self.wizard_button.setIcon(QIcon(I('wizard.png'))) self.wizard_button.clicked.connect(self.run_wizard, type=Qt.QueuedConnection) self.wizard_button.setAutoDefault(False) self.bb.rejected.connect(self.reject) self.browser = Browser(self) self.browser.show_plugin.connect(self.show_plugin) self.stack.addWidget(self.browser) self.scroll_area = QScrollArea(self) self.stack.addWidget(self.scroll_area) self.scroll_area.setWidgetResizable(True) self.setContextMenuPolicy(Qt.NoContextMenu) self.title_bar = TitleBar(self) for ac, tt in [(self.bb.Apply, _('Save changes')), (self.bb.Discard, _('Cancel and return to overview'))]: self.bb.button(ac).setToolTip(tt) l.addWidget(self.title_bar), l.addWidget(self.stack), l.addWidget( self.bb) if initial_plugin is not None: category, name = initial_plugin[:2] plugin = get_plugin(category, name) if plugin is not None: self.show_plugin(plugin) if len(initial_plugin) > 2: w = self.findChild(QWidget, initial_plugin[2]) if w is not None: for c in self.showing_widget.children(): if isinstance(c, QTabWidget): idx = c.indexOf(w) if idx > -1: c.setCurrentIndex(idx) break else: self.hide_plugin()
def __init__(self, type_, title, msg, opts, det_msg='', q_icon=None, show_copy_button=True, parent=None, default_yes=True): QDialog.__init__(self, parent) if q_icon is None: icon = { self.ERROR: 'error', self.WARNING: 'warning', self.INFO: 'information', self.QUESTION: 'question', }[type_] icon = 'dialog_%s.png' % icon self.icon = QIcon(I(icon)) else: self.icon = q_icon self.setupUi(self) self.setWindowTitle(title) self.setWindowIcon(opts.icon) #self.icon_label.setPixmap(self.icon.pixmap(self.COVER_SIZE, self.COVER_SIZE)) self.icon_label.setPixmap(self.icon.pixmap(COVER_ICON_SIZE)) self.msg.setText(msg) self.msg.setOpenExternalLinks(True) self.det_msg.setPlainText(det_msg) self.det_msg.setVisible(False) self.toggle_checkbox.setVisible(False) if show_copy_button: self.ctc_button = self.bb.addButton(_('&Copy to clipboard'), self.bb.ActionRole) self.ctc_button.clicked.connect(self.copy_to_clipboard) self.show_det_msg = _('Show &details') self.hide_det_msg = _('Hide &details') self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole) self.det_msg_toggle.clicked.connect(self.toggle_det_msg) self.det_msg_toggle.setToolTip( _('Show detailed information')) self.copy_action = QAction(self) self.addAction(self.copy_action) self.copy_action.setShortcuts(QKeySequence.Copy) self.copy_action.triggered.connect(self.copy_to_clipboard) self.is_question = type_ == self.QUESTION if self.is_question: self.bb.setStandardButtons(self.bb.Yes | self.bb.No) self.bb.button(self.bb.Yes if default_yes else self.bb.No ).setDefault(True) self.default_yes = default_yes else: self.bb.button(self.bb.Ok).setDefault(True) if not det_msg: self.det_msg_toggle.setVisible(False) self.do_resize()
def __init__(self, parent=None): QTextEdit.__init__(self, parent) self.setTabChangesFocus(True) self.document().setDefaultStyleSheet(css()) font = self.font() f = QFontInfo(font) delta = tweaks['change_book_details_font_size_by'] + 1 if delta: font.setPixelSize(f.pixelSize() + delta) self.setFont(font) f = QFontMetrics(self.font()) self.em_size = f.horizontalAdvance('m') self.base_url = None self._parent = weakref.ref(parent) self.comments_pat = re.compile(r'<!--.*?-->', re.DOTALL) extra_shortcuts = { 'bold': 'Bold', 'italic': 'Italic', 'underline': 'Underline', } for rec in ( ('bold', 'format-text-bold', _('Bold'), True), ('italic', 'format-text-italic', _('Italic'), True), ('underline', 'format-text-underline', _('Underline'), True), ('strikethrough', 'format-text-strikethrough', _('Strikethrough'), True), ('superscript', 'format-text-superscript', _('Superscript'), True), ('subscript', 'format-text-subscript', _('Subscript'), True), ('ordered_list', 'format-list-ordered', _('Ordered list'), True), ('unordered_list', 'format-list-unordered', _('Unordered list'), True), ('align_left', 'format-justify-left', _('Align left'), True), ('align_center', 'format-justify-center', _('Align center'), True), ('align_right', 'format-justify-right', _('Align right'), True), ('align_justified', 'format-justify-fill', _('Align justified'), True), ( 'undo', 'edit-undo', _('Undo'), ), ( 'redo', 'edit-redo', _('Redo'), ), ( 'remove_format', 'edit-clear', _('Remove formatting'), ), ( 'copy', 'edit-copy', _('Copy'), ), ( 'paste', 'edit-paste', _('Paste'), ), ( 'paste_and_match_style', 'edit-paste', _('Paste and match style'), ), ( 'cut', 'edit-cut', _('Cut'), ), ( 'indent', 'format-indent-more', _('Increase indentation'), ), ( 'outdent', 'format-indent-less', _('Decrease indentation'), ), ( 'select_all', 'edit-select-all', _('Select all'), ), ('color', 'format-text-color', _('Foreground color')), ('background', 'format-fill-color', _('Background color')), ( 'insert_link', 'insert-link', _('Insert link or image'), ), ( 'insert_hr', 'format-text-hr', _('Insert separator'), ), ('clear', 'trash', _('Clear')), ): name, icon, text = rec[:3] checkable = len(rec) == 4 ac = QAction(QIcon(I(icon + '.png')), text, self) if checkable: ac.setCheckable(checkable) setattr(self, 'action_' + name, ac) ss = extra_shortcuts.get(name) if ss is not None: ac.setShortcut(QKeySequence(getattr(QKeySequence, ss))) ac.triggered.connect(getattr(self, 'do_' + name)) self.action_block_style = QAction(QIcon(I('format-text-heading.png')), _('Style text block'), self) self.action_block_style.setToolTip(_('Style the selected text block')) self.block_style_menu = QMenu(self) self.action_block_style.setMenu(self.block_style_menu) self.block_style_actions = [] h = _('Heading {0}') for text, name in ( (_('Normal'), 'p'), (h.format(1), 'h1'), (h.format(2), 'h2'), (h.format(3), 'h3'), (h.format(4), 'h4'), (h.format(5), 'h5'), (h.format(6), 'h6'), (_('Blockquote'), 'blockquote'), ): ac = QAction(text, self) self.block_style_menu.addAction(ac) ac.block_name = name ac.setCheckable(True) self.block_style_actions.append(ac) ac.triggered.connect(self.do_format_block) self.setHtml('') self.copyAvailable.connect(self.update_clipboard_actions) self.update_clipboard_actions(False) self.selectionChanged.connect(self.update_selection_based_actions) self.update_selection_based_actions() connect_lambda(self.undoAvailable, self, lambda self, yes: self.action_undo.setEnabled(yes)) connect_lambda(self.redoAvailable, self, lambda self, yes: self.action_redo.setEnabled(yes)) self.action_undo.setEnabled(False), self.action_redo.setEnabled(False) self.textChanged.connect(self.update_cursor_position_actions) self.cursorPositionChanged.connect(self.update_cursor_position_actions) self.textChanged.connect(self.data_changed) self.update_cursor_position_actions()
class MessageBox(QDialog): # {{{ ERROR = 0 WARNING = 1 INFO = 2 QUESTION = 3 resize_needed = pyqtSignal() def setup_ui(self): self.setObjectName("Dialog") self.resize(497, 235) self.gridLayout = l = QGridLayout(self) l.setObjectName("gridLayout") self.icon_label = la = QLabel('') la.setMaximumSize(QSize(68, 68)) la.setScaledContents(True) la.setObjectName("icon_label") l.addWidget(la) self.msg = la = QLabel(self) la.setWordWrap(True), la.setMinimumWidth(400) la.setOpenExternalLinks(True) la.setObjectName("msg") l.addWidget(la, 0, 1, 1, 1) self.det_msg = dm = QPlainTextEdit(self) dm.setReadOnly(True) dm.setObjectName("det_msg") l.addWidget(dm, 1, 0, 1, 2) self.bb = bb = QDialogButtonBox(self) bb.setStandardButtons(QDialogButtonBox.Ok) bb.setObjectName("bb") bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) l.addWidget(bb, 3, 0, 1, 2) self.toggle_checkbox = tc = QCheckBox(self) tc.setObjectName("toggle_checkbox") l.addWidget(tc, 2, 0, 1, 2) def __init__(self, type_, title, msg, det_msg='', q_icon=None, show_copy_button=True, parent=None, default_yes=True, yes_text=None, no_text=None, yes_icon=None, no_icon=None): QDialog.__init__(self, parent) if q_icon is None: icon = { self.ERROR: 'error', self.WARNING: 'warning', self.INFO: 'information', self.QUESTION: 'question', }[type_] icon = 'dialog_%s.png' % icon self.icon = QIcon(I(icon)) else: self.icon = q_icon if isinstance(q_icon, QIcon) else QIcon( I(q_icon)) self.setup_ui() self.setWindowTitle(title) self.setWindowIcon(self.icon) self.icon_label.setPixmap(self.icon.pixmap(128, 128)) self.msg.setText(msg) self.det_msg.setPlainText(det_msg) self.det_msg.setVisible(False) self.toggle_checkbox.setVisible(False) if show_copy_button: self.ctc_button = self.bb.addButton(_('&Copy to clipboard'), self.bb.ActionRole) self.ctc_button.clicked.connect(self.copy_to_clipboard) self.show_det_msg = _('Show &details') self.hide_det_msg = _('Hide &details') self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole) self.det_msg_toggle.clicked.connect(self.toggle_det_msg) self.det_msg_toggle.setToolTip( _('Show detailed information about this error')) self.copy_action = QAction(self) self.addAction(self.copy_action) self.copy_action.setShortcuts(QKeySequence.Copy) self.copy_action.triggered.connect(self.copy_to_clipboard) self.is_question = type_ == self.QUESTION if self.is_question: self.bb.setStandardButtons(self.bb.Yes | self.bb.No) self.bb.button( self.bb.Yes if default_yes else self.bb.No).setDefault(True) self.default_yes = default_yes if yes_text is not None: self.bb.button(self.bb.Yes).setText(yes_text) if no_text is not None: self.bb.button(self.bb.No).setText(no_text) if yes_icon is not None: self.bb.button(self.bb.Yes).setIcon(yes_icon if isinstance( yes_icon, QIcon) else QIcon(I(yes_icon))) if no_icon is not None: self.bb.button(self.bb.No).setIcon(no_icon if isinstance( no_icon, QIcon) else QIcon(I(no_icon))) else: self.bb.button(self.bb.Ok).setDefault(True) if not det_msg: self.det_msg_toggle.setVisible(False) self.resize_needed.connect(self.do_resize, type=Qt.QueuedConnection) self.do_resize() def sizeHint(self): ans = QDialog.sizeHint(self) ans.setWidth( max(min(ans.width(), 500), self.bb.sizeHint().width() + 100)) ans.setHeight(min(ans.height(), 500)) return ans def toggle_det_msg(self, *args): vis = self.det_msg.isVisible() self.det_msg.setVisible(not vis) self.det_msg_toggle.setText( self.show_det_msg if vis else self.hide_det_msg) self.resize_needed.emit() def do_resize(self): self.resize(self.sizeHint()) def copy_to_clipboard(self, *args): QApplication.clipboard().setText( 'calibre, version %s\n%s: %s\n\n%s' % (__version__, unicode(self.windowTitle()), unicode( self.msg.text()), unicode(self.det_msg.toPlainText()))) if hasattr(self, 'ctc_button'): self.ctc_button.setText(_('Copied')) def showEvent(self, ev): ret = QDialog.showEvent(self, ev) if self.is_question: try: self.bb.button( self.bb.Yes if self.default_yes else self.bb.No).setFocus( Qt.OtherFocusReason) except: pass # Buttons were changed else: self.bb.button(self.bb.Ok).setFocus(Qt.OtherFocusReason) return ret def set_details(self, msg): if not msg: msg = '' self.det_msg.setPlainText(msg) self.det_msg_toggle.setText(self.show_det_msg) self.det_msg_toggle.setVisible(bool(msg)) self.det_msg.setVisible(False) self.resize_needed.emit()
def __init__(self, parent=None): QWidget.__init__(self, parent) self.l = gl = QGridLayout(self) self.changed = False self.bars = b = QComboBox(self) b.addItem(_('Choose which toolbar you want to customize')) ft = _('Tools for %s editors') for name, text in ( ( 'global_book_toolbar', _('Book wide actions'), ), ( 'global_tools_toolbar', _('Book wide tools'), ), ( 'global_plugins_toolbar', _('Book wide tools from third party plugins'), ), ('editor_common_toolbar', ft % _('all')), ( 'editor_html_toolbar', ft % 'HTML', ), ( 'editor_css_toolbar', ft % 'CSS', ), ( 'editor_xml_toolbar', ft % 'XML', ), ( 'editor_format_toolbar', _('Text formatting actions'), ), ): b.addItem(text, name) self.la = la = QLabel(_('&Toolbar to customize:')) la.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) la.setBuddy(b) gl.addWidget(la), gl.addWidget(b, 0, 1) self.sl = l = QGridLayout() gl.addLayout(l, 1, 0, 1, -1) self.gb1 = gb1 = QGroupBox(_('A&vailable actions'), self) self.gb2 = gb2 = QGroupBox(_('&Current actions'), self) gb1.setFlat(True), gb2.setFlat(True) gb1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) gb2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) l.addWidget(gb1, 0, 0, -1, 1), l.addWidget(gb2, 0, 2, -1, 1) self.available, self.current = ToolbarList(self), ToolbarList(self) self.ub = b = QToolButton(self) connect_lambda(b.clicked, self, lambda self: self.move(up=True)) b.setToolTip(_('Move selected action up')), b.setIcon( QIcon(I('arrow-up.png'))) self.db = b = QToolButton(self) connect_lambda(b.clicked, self, lambda self: self.move(up=False)) b.setToolTip(_('Move selected action down')), b.setIcon( QIcon(I('arrow-down.png'))) self.gl1 = gl1 = QVBoxLayout() gl1.addWidget(self.available), gb1.setLayout(gl1) self.gl2 = gl2 = QGridLayout() gl2.addWidget(self.current, 0, 0, -1, 1) gl2.addWidget(self.ub, 0, 1), gl2.addWidget(self.db, 2, 1) gb2.setLayout(gl2) self.lb = b = QToolButton(self) b.setToolTip(_('Add selected actions to the toolbar')), b.setIcon( QIcon(I('forward.png'))) l.addWidget(b, 1, 1), b.clicked.connect(self.add_action) self.rb = b = QToolButton(self) b.setToolTip(_('Remove selected actions from the toolbar')), b.setIcon( QIcon(I('back.png'))) l.addWidget(b, 3, 1), b.clicked.connect(self.remove_action) self.si = QSpacerItem(20, 10, hPolicy=QSizePolicy.Preferred, vPolicy=QSizePolicy.Expanding) l.setRowStretch(0, 10), l.setRowStretch(2, 10), l.setRowStretch(4, 10) l.addItem(self.si, 4, 1) self.read_settings() self.toggle_visibility(False) self.bars.currentIndexChanged.connect(self.bar_changed) self.toolbar_icon_size = ics = QSpinBox(self) ics.setMinimum(16), ics.setMaximum(128), ics.setSuffix( ' px'), ics.setValue(tprefs['toolbar_icon_size']) ics.setToolTip('<p>' + _('Adjust the size of icons on all toolbars')) self.h = h = QHBoxLayout() gl.addLayout(h, gl.rowCount(), 0, 1, -1) self.toolbar_icon_size_label = la = QLabel(_('Toolbar &icon size:')) la.setBuddy(ics) h.addWidget(la), h.addWidget(ics), h.addStretch(10)
def __init__(self, gui, row, toggle_shortcut): self.is_pane = gprefs.get('quickview_is_pane', False) if not self.is_pane: QDialog.__init__(self, gui, flags=Qt.Widget) else: QDialog.__init__(self, gui) Ui_Quickview.__init__(self) self.setupUi(self) self.isClosed = False self.current_book = None self.closed_by_button = False if self.is_pane: self.main_grid_layout.setContentsMargins(0, 0, 0, 0) else: self.setWindowIcon(self.windowIcon()) self.books_table_column_widths = None try: self.books_table_column_widths = \ gprefs.get('quickview_dialog_books_table_widths', None) if not self.is_pane: geom = gprefs.get('quickview_dialog_geometry', None) if geom: QApplication.instance().safe_restore_geometry( self, QByteArray(geom)) except: pass self.view = gui.library_view self.db = self.view.model().db self.gui = gui self.is_closed = False self.current_book_id = None # the db id of the book used to fill the lh pane self.current_column = None # current logical column in books list self.current_key = None # current lookup key in books list self.last_search = None self.no_valid_items = False self.follow_library_view = True self.apply_vls.setCheckState( Qt.Checked if gprefs['qv_respects_vls'] else Qt.Unchecked) self.apply_vls.stateChanged.connect(self.vl_box_changed) self.fm = self.db.field_metadata self.items.setSelectionMode(QAbstractItemView.SingleSelection) self.items.currentTextChanged.connect(self.item_selected) self.items.setProperty('highlight_current_item', 150) self.items.itemDoubleClicked.connect(self.item_doubleclicked) self.items.setContextMenuPolicy(Qt.CustomContextMenu) self.items.customContextMenuRequested.connect( self.show_item_context_menu) focus_filter = WidgetFocusFilter(self.items) focus_filter.focus_entered_signal.connect(self.focus_entered) self.items.installEventFilter(focus_filter) self.tab_pressed_signal.connect(self.tab_pressed) return_filter = BooksTableFilter(self.books_table) return_filter.return_pressed_signal.connect(self.return_pressed) self.books_table.installEventFilter(return_filter) focus_filter = WidgetFocusFilter(self.books_table) focus_filter.focus_entered_signal.connect(self.focus_entered) self.books_table.installEventFilter(focus_filter) self.close_button.clicked.connect(self.close_button_clicked) self.refresh_button.clicked.connect(self.refill) self.tab_order_widgets = [ self.items, self.books_table, self.lock_qv, self.dock_button, self.refresh_button, self.close_button ] for idx, widget in enumerate(self.tab_order_widgets): widget.installEventFilter( WidgetTabFilter(widget, idx, self.tab_pressed_signal)) self.books_table.setSelectionBehavior(QAbstractItemView.SelectRows) self.books_table.setSelectionMode(QAbstractItemView.SingleSelection) self.books_table.setProperty('highlight_current_item', 150) # Set up the books table columns self.add_columns_to_widget() self.books_table_header_height = self.books_table.height() self.books_table.cellDoubleClicked.connect(self.book_doubleclicked) self.books_table.currentCellChanged.connect( self.books_table_cell_changed) self.books_table.cellClicked.connect( self.books_table_set_search_string) self.books_table.cellActivated.connect( self.books_table_set_search_string) self.books_table.sortByColumn(0, Qt.AscendingOrder) # get the standard table row height. Do this here because calling # resizeRowsToContents can word wrap long cell contents, creating # double-high rows self.books_table.setRowCount(1) self.books_table.setItem(0, 0, TableItem('A', '')) self.books_table.resizeRowsToContents() self.books_table_row_height = self.books_table.rowHeight(0) self.books_table.setRowCount(0) # Add the data self.refresh(row) self.view.clicked.connect(self.slave) self.view.selectionModel().currentColumnChanged.connect( self.column_slave) QCoreApplication.instance().aboutToQuit.connect(self.save_state) self.view.model().new_bookdisplay_data.connect(self.book_was_changed) self.close_button.setDefault(False) self.close_button_tooltip = _( 'The Quickview shortcut ({0}) shows/hides the Quickview panel') if self.is_pane: self.dock_button.setText(_('Undock')) self.dock_button.setToolTip( _('Show the Quickview panel in its own floating window')) self.dock_button.setIcon(QIcon(I('arrow-up.png'))) # Remove the ampersands from the buttons because shortcuts exist. self.lock_qv.setText(_('Lock Quickview contents')) self.refresh_button.setText(_('Refresh')) self.gui.quickview_splitter.add_quickview_dialog(self) self.close_button.setVisible(False) else: self.dock_button.setToolTip( _('Embed the quickview panel into the main calibre window')) self.dock_button.setIcon(QIcon(I('arrow-down.png'))) self.set_focus() self.books_table.horizontalHeader().sectionResized.connect( self.section_resized) self.dock_button.clicked.connect(self.show_as_pane_changed) self.view.model().search_done.connect(self.check_for_no_items) # Enable the refresh button only when QV is locked self.refresh_button.setEnabled(False) self.lock_qv.stateChanged.connect(self.lock_qv_changed) self.view_icon = QIcon(I('view.png')) self.view_plugin = self.gui.iactions['View'] self.edit_metadata_icon = QIcon(I('edit_input.png')) self.quickview_icon = QIcon(I('quickview.png')) self.select_book_icon = QIcon(I('library.png')) self.search_icon = QIcon(I('search.png')) self.books_table.setContextMenuPolicy(Qt.CustomContextMenu) self.books_table.customContextMenuRequested.connect( self.show_context_menu) # Add the quickview toggle as a shortcut for the close button # Don't add it if it identical to the current &X shortcut because that # breaks &X if (not self.is_pane and toggle_shortcut and self.close_button.shortcut() != toggle_shortcut): toggle_sc = QShortcut(toggle_shortcut, self.close_button) toggle_sc.activated.connect(lambda: self.close_button_clicked()) toggle_sc.setEnabled(True) self.close_button.setToolTip( _('Alternate shortcut: ') + toggle_shortcut.toString())
def __init__(self, parent=None): QAbstractItemModel.__init__(self, parent) self.categories = ( (_('Favorites'), ()), # {{{ (_('European scripts'), ( (_('Armenian'), (0x530, 0x58F)), (_('Armenian ligatures'), (0xFB13, 0xFB17)), (_('Coptic'), (0x2C80, 0x2CFF)), (_('Coptic in Greek block'), (0x3E2, 0x3EF)), (_('Cypriot syllabary'), (0x10800, 0x1083F)), (_('Cyrillic'), (0x400, 0x4FF)), (_('Cyrillic supplement'), (0x500, 0x52F)), (_('Cyrillic extended A'), (0x2DE0, 0x2DFF)), (_('Cyrillic extended B'), (0xA640, 0xA69F)), (_('Georgian'), (0x10A0, 0x10FF)), (_('Georgian supplement'), (0x2D00, 0x2D2F)), (_('Glagolitic'), (0x2C00, 0x2C5F)), (_('Gothic'), (0x10330, 0x1034F)), (_('Greek and Coptic'), (0x370, 0x3FF)), (_('Greek extended'), (0x1F00, 0x1FFF)), (_('Latin, Basic & Latin-1 supplement'), (0x20, 0xFF)), (_('Latin extended A'), (0x100, 0x17F)), (_('Latin extended B'), (0x180, 0x24F)), (_('Latin extended C'), (0x2C60, 0x2C7F)), (_('Latin extended D'), (0xA720, 0xA7FF)), (_('Latin extended additional'), (0x1E00, 0x1EFF)), (_('Latin ligatures'), (0xFB00, 0xFB06)), (_('Fullwidth Latin letters'), (0xFF00, 0xFF5E)), (_('Linear B syllabary'), (0x10000, 0x1007F)), (_('Linear B ideograms'), (0x10080, 0x100FF)), (_('Ogham'), (0x1680, 0x169F)), (_('Old italic'), (0x10300, 0x1032F)), (_('Phaistos disc'), (0x101D0, 0x101FF)), (_('Runic'), (0x16A0, 0x16FF)), (_('Shavian'), (0x10450, 0x1047F)), )), (_('Phonetic symbols'), ( (_('IPA extensions'), (0x250, 0x2AF)), (_('Phonetic extensions'), (0x1D00, 0x1D7F)), (_('Phonetic extensions supplement'), (0x1D80, 0x1DBF)), (_('Modifier tone letters'), (0xA700, 0xA71F)), (_('Spacing modifier letters'), (0x2B0, 0x2FF)), (_('Superscripts and subscripts'), (0x2070, 0x209F)), )), (_('Combining diacritics'), ( (_('Combining diacritical marks'), (0x300, 0x36F)), (_('Combining diacritical marks for symbols'), (0x20D0, 0x20FF)), (_('Combining diacritical marks supplement'), (0x1DC0, 0x1DFF)), (_('Combining half marks'), (0xFE20, 0xFE2F)), )), (_('African scripts'), ( (_('Bamum'), (0xA6A0, 0xA6FF)), (_('Bamum supplement'), (0x16800, 0x16A3F)), (_('Egyptian hieroglyphs'), (0x13000, 0x1342F)), (_('Ethiopic'), (0x1200, 0x137F)), (_('Ethiopic supplement'), (0x1380, 0x139F)), (_('Ethiopic extended'), (0x2D80, 0x2DDF)), (_('Ethiopic extended A'), (0xAB00, 0xAB2F)), (_('Meroitic cursive'), (0x109A0, 0x109FF)), (_('Meroitic hieroglyphs'), (0x10980, 0x1099F)), (_('N\'Ko'), (0x7C0, 0x7FF)), (_('Osmanya'), (0x10480, 0x104AF)), (_('Tifinagh'), (0x2D30, 0x2D7F)), (_('Vai'), (0xA500, 0xA63F)), )), (_('Middle Eastern scripts'), ( (_('Arabic'), (0x600, 0x6FF)), (_('Arabic supplement'), (0x750, 0x77F)), (_('Arabic extended A'), (0x8A0, 0x8FF)), (_('Arabic presentation forms A'), (0xFB50, 0xFDFF)), (_('Arabic presentation forms B'), (0xFE70, 0xFEFF)), (_('Avestan'), (0x10B00, 0x10B3F)), (_('Carian'), (0x102A0, 0x102DF)), (_('Cuneiform'), (0x12000, 0x123FF)), (_('Cuneiform numbers and punctuation'), (0x12400, 0x1247F)), (_('Hebrew'), (0x590, 0x5FF)), (_('Hebrew presentation forms'), (0xFB1D, 0xFB4F)), (_('Imperial Aramaic'), (0x10840, 0x1085F)), (_('Inscriptional Pahlavi'), (0x10B60, 0x10B7F)), (_('Inscriptional Parthian'), (0x10B40, 0x10B5F)), (_('Lycian'), (0x10280, 0x1029F)), (_('Lydian'), (0x10920, 0x1093F)), (_('Mandaic'), (0x840, 0x85F)), (_('Old Persian'), (0x103A0, 0x103DF)), (_('Old South Arabian'), (0x10A60, 0x10A7F)), (_('Phoenician'), (0x10900, 0x1091F)), (_('Samaritan'), (0x800, 0x83F)), (_('Syriac'), (0x700, 0x74F)), (_('Ugaritic'), (0x10380, 0x1039F)), )), (_('Central Asian scripts'), ( (_('Mongolian'), (0x1800, 0x18AF)), (_('Old Turkic'), (0x10C00, 0x10C4F)), (_('Phags-pa'), (0xA840, 0xA87F)), (_('Tibetan'), (0xF00, 0xFFF)), )), (_('South Asian scripts'), ( (_('Bengali'), (0x980, 0x9FF)), (_('Brahmi'), (0x11000, 0x1107F)), (_('Chakma'), (0x11100, 0x1114F)), (_('Devanagari'), (0x900, 0x97F)), (_('Devanagari extended'), (0xA8E0, 0xA8FF)), (_('Gujarati'), (0xA80, 0xAFF)), (_('Gurmukhi'), (0xA00, 0xA7F)), (_('Kaithi'), (0x11080, 0x110CF)), (_('Kannada'), (0xC80, 0xCFF)), (_('Kharoshthi'), (0x10A00, 0x10A5F)), (_('Lepcha'), (0x1C00, 0x1C4F)), (_('Limbu'), (0x1900, 0x194F)), (_('Malayalam'), (0xD00, 0xD7F)), (_('Meetei Mayek'), (0xABC0, 0xABFF)), (_('Meetei Mayek extensions'), (0xAAE0, 0xAAEF)), (_('Ol Chiki'), (0x1C50, 0x1C7F)), (_('Oriya'), (0xB00, 0xB7F)), (_('Saurashtra'), (0xA880, 0xA8DF)), (_('Sinhala'), (0xD80, 0xDFF)), (_('Sharada'), (0x11180, 0x111DF)), (_('Sora Sompeng'), (0x110D0, 0x110FF)), (_('Syloti Nagri'), (0xA800, 0xA82F)), (_('Takri'), (0x11680, 0x116CF)), (_('Tamil'), (0xB80, 0xBFF)), (_('Telugu'), (0xC00, 0xC7F)), (_('Thaana'), (0x780, 0x7BF)), (_('Vedic extensions'), (0x1CD0, 0x1CFF)), )), (_('Southeast Asian scripts'), ( (_('Balinese'), (0x1B00, 0x1B7F)), (_('Batak'), (0x1BC0, 0x1BFF)), (_('Buginese'), (0x1A00, 0x1A1F)), (_('Cham'), (0xAA00, 0xAA5F)), (_('Javanese'), (0xA980, 0xA9DF)), (_('Kayah Li'), (0xA900, 0xA92F)), (_('Khmer'), (0x1780, 0x17FF)), (_('Khmer symbols'), (0x19E0, 0x19FF)), (_('Lao'), (0xE80, 0xEFF)), (_('Myanmar'), (0x1000, 0x109F)), (_('Myanmar extended A'), (0xAA60, 0xAA7F)), (_('New Tai Lue'), (0x1980, 0x19DF)), (_('Rejang'), (0xA930, 0xA95F)), (_('Sundanese'), (0x1B80, 0x1BBF)), (_('Sundanese supplement'), (0x1CC0, 0x1CCF)), (_('Tai Le'), (0x1950, 0x197F)), (_('Tai Tham'), (0x1A20, 0x1AAF)), (_('Tai Viet'), (0xAA80, 0xAADF)), (_('Thai'), (0xE00, 0xE7F)), )), (_('Philippine scripts'), ( (_('Buhid'), (0x1740, 0x175F)), (_('Hanunoo'), (0x1720, 0x173F)), (_('Tagalog'), (0x1700, 0x171F)), (_('Tagbanwa'), (0x1760, 0x177F)), )), (_('East Asian scripts'), ( (_('Bopomofo'), (0x3100, 0x312F)), (_('Bopomofo extended'), (0x31A0, 0x31BF)), (_('CJK Unified ideographs'), (0x4E00, 0x9FFF)), (_('CJK Unified ideographs extension A'), (0x3400, 0x4DBF)), (_('CJK Unified ideographs extension B'), (0x20000, 0x2A6DF)), (_('CJK Unified ideographs extension C'), (0x2A700, 0x2B73F)), (_('CJK Unified ideographs extension D'), (0x2B740, 0x2B81F)), (_('CJK compatibility ideographs'), (0xF900, 0xFAFF)), (_('CJK compatibility ideographs supplement'), (0x2F800, 0x2FA1F)), (_('Kangxi radicals'), (0x2F00, 0x2FDF)), (_('CJK radicals supplement'), (0x2E80, 0x2EFF)), (_('CJK strokes'), (0x31C0, 0x31EF)), (_('Ideographic description characters'), (0x2FF0, 0x2FFF)), (_('Hiragana'), (0x3040, 0x309F)), (_('Katakana'), (0x30A0, 0x30FF)), (_('Katakana phonetic extensions'), (0x31F0, 0x31FF)), (_('Kana supplement'), (0x1B000, 0x1B0FF)), (_('Halfwidth Katakana'), (0xFF65, 0xFF9F)), (_('Kanbun'), (0x3190, 0x319F)), (_('Hangul syllables'), (0xAC00, 0xD7AF)), (_('Hangul Jamo'), (0x1100, 0x11FF)), (_('Hangul Jamo extended A'), (0xA960, 0xA97F)), (_('Hangul Jamo extended B'), (0xD7B0, 0xD7FF)), (_('Hangul compatibility Jamo'), (0x3130, 0x318F)), (_('Halfwidth Jamo'), (0xFFA0, 0xFFDC)), (_('Lisu'), (0xA4D0, 0xA4FF)), (_('Miao'), (0x16F00, 0x16F9F)), (_('Yi syllables'), (0xA000, 0xA48F)), (_('Yi radicals'), (0xA490, 0xA4CF)), )), (_('American scripts'), ( (_('Cherokee'), (0x13A0, 0x13FF)), (_('Deseret'), (0x10400, 0x1044F)), (_('Unified Canadian aboriginal syllabics'), (0x1400, 0x167F)), (_('UCAS extended'), (0x18B0, 0x18FF)), )), (_('Other'), ( (_('Alphabetic presentation forms'), (0xFB00, 0xFB4F)), (_('Halfwidth and Fullwidth forms'), (0xFF00, 0xFFEF)), )), (_('Punctuation'), ( (_('General punctuation'), (0x2000, 0x206F)), (_('ASCII punctuation'), (0x21, 0x7F)), (_('Cuneiform numbers and punctuation'), (0x12400, 0x1247F)), (_('Latin-1 punctuation'), (0xA1, 0xBF)), (_('Small form variants'), (0xFE50, 0xFE6F)), (_('Supplemental punctuation'), (0x2E00, 0x2E7F)), (_('CJK symbols and punctuation'), (0x3000, 0x303F)), (_('CJK compatibility forms'), (0xFE30, 0xFE4F)), (_('Fullwidth ASCII punctuation'), (0xFF01, 0xFF60)), (_('Vertical forms'), (0xFE10, 0xFE1F)), )), (_('Alphanumeric symbols'), ( (_('Arabic mathematical alphabetic symbols'), (0x1EE00, 0x1EEFF)), (_('Letterlike symbols'), (0x2100, 0x214F)), (_('Roman symbols'), (0x10190, 0x101CF)), (_('Mathematical alphanumeric symbols'), (0x1D400, 0x1D7FF)), (_('Enclosed alphanumerics'), (0x2460, 0x24FF)), (_('Enclosed alphanumeric supplement'), (0x1F100, 0x1F1FF)), (_('Enclosed CJK letters and months'), (0x3200, 0x32FF)), (_('Enclosed ideographic supplement'), (0x1F200, 0x1F2FF)), (_('CJK compatibility'), (0x3300, 0x33FF)), )), (_('Technical symbols'), ( (_('Miscellaneous technical'), (0x2300, 0x23FF)), (_('Control pictures'), (0x2400, 0x243F)), (_('Optical character recognition'), (0x2440, 0x245F)), )), (_('Numbers and digits'), ( (_('Aegean numbers'), (0x10100, 0x1013F)), (_('Ancient Greek numbers'), (0x10140, 0x1018F)), (_('Common Indic number forms'), (0xA830, 0xA83F)), (_('Counting rod numerals'), (0x1D360, 0x1D37F)), (_('Cuneiform numbers and punctuation'), (0x12400, 0x1247F)), (_('Fullwidth ASCII digits'), (0xFF10, 0xFF19)), (_('Number forms'), (0x2150, 0x218F)), (_('Rumi numeral symbols'), (0x10E60, 0x10E7F)), (_('Superscripts and subscripts'), (0x2070, 0x209F)), )), (_('Mathematical symbols'), ( (_('Arrows'), (0x2190, 0x21FF)), (_('Supplemental arrows A'), (0x27F0, 0x27FF)), (_('Supplemental arrows B'), (0x2900, 0x297F)), (_('Miscellaneous symbols and arrows'), (0x2B00, 0x2BFF)), (_('Mathematical alphanumeric symbols'), (0x1D400, 0x1D7FF)), (_('Letterlike symbols'), (0x2100, 0x214F)), (_('Mathematical operators'), (0x2200, 0x22FF)), (_('Miscellaneous mathematical symbols A'), (0x27C0, 0x27EF)), (_('Miscellaneous mathematical symbols B'), (0x2980, 0x29FF)), (_('Supplemental mathematical operators'), (0x2A00, 0x2AFF)), (_('Ceilings and floors'), (0x2308, 0x230B)), (_('Geometric shapes'), (0x25A0, 0x25FF)), (_('Box drawing'), (0x2500, 0x257F)), (_('Block elements'), (0x2580, 0x259F)), )), (_('Musical symbols'), ( (_('Musical symbols'), (0x1D100, 0x1D1FF)), (_('More musical symbols'), (0x2669, 0x266F)), (_('Ancient Greek musical notation'), (0x1D200, 0x1D24F)), (_('Byzantine musical symbols'), (0x1D000, 0x1D0FF)), )), (_('Game symbols'), ( (_('Chess'), (0x2654, 0x265F)), (_('Domino tiles'), (0x1F030, 0x1F09F)), (_('Draughts'), (0x26C0, 0x26C3)), (_('Japanese chess'), (0x2616, 0x2617)), (_('Mahjong tiles'), (0x1F000, 0x1F02F)), (_('Playing cards'), (0x1F0A0, 0x1F0FF)), (_('Playing card suits'), (0x2660, 0x2667)), )), (_('Other symbols'), ( (_('Alchemical symbols'), (0x1F700, 0x1F77F)), (_('Ancient symbols'), (0x10190, 0x101CF)), (_('Braille patterns'), (0x2800, 0x28FF)), (_('Currency symbols'), (0x20A0, 0x20CF)), (_('Combining diacritical marks for symbols'), (0x20D0, 0x20FF)), (_('Dingbats'), (0x2700, 0x27BF)), (_('Emoticons'), (0x1F600, 0x1F64F)), (_('Miscellaneous symbols'), (0x2600, 0x26FF)), (_('Miscellaneous symbols and arrows'), (0x2B00, 0x2BFF)), (_('Miscellaneous symbols and pictographs'), (0x1F300, 0x1F5FF)), (_('Yijing hexagram symbols'), (0x4DC0, 0x4DFF)), (_('Yijing mono and digrams'), (0x268A, 0x268F)), (_('Yijing trigrams'), (0x2630, 0x2637)), (_('Tai Xuan Jing symbols'), (0x1D300, 0x1D35F)), (_('Transport and map symbols'), (0x1F680, 0x1F6FF)), )), (_('Other'), ( (_('Specials'), (0xFFF0, 0xFFFF)), (_('Tags'), (0xE0000, 0xE007F)), (_('Variation selectors'), (0xFE00, 0xFE0F)), (_('Variation selectors supplement'), (0xE0100, 0xE01EF)), )), ) # }}} self.category_map = {} self.starts = [] for tlname, items in self.categories[1:]: for name, (start, end) in items: self.category_map[start] = (tlname, name) self.starts.append(start) self.starts.sort() self.bold_font = f = QApplication.font() f.setBold(True) self.fav_icon = QIcon(I('rating.png'))
def setup_ui(self): self.l = l = QGridLayout(self) self.setLayout(l) self.bb.setStandardButtons(self.bb.Close) self.rearrange_button = b = self.bb.addButton( _('Re-arrange favorites'), self.bb.ActionRole) b.setCheckable(True) b.setChecked(False) b.setVisible(False) b.setDefault(True) self.splitter = s = QSplitter(self) s.setFocusPolicy(Qt.NoFocus) s.setChildrenCollapsible(False) self.search = h = HistoryLineEdit2(self) h.setToolTip( textwrap.fill( _('Search for Unicode characters by using the English names or nicknames.' ' You can also search directly using a character code. For example, the following' ' searches will all yield the no-break space character: U+A0, nbsp, no-break' ))) h.initialize('charmap_search') h.setPlaceholderText(_('Search by name, nickname or character code')) self.search_button = b = QPushButton(_('&Search')) b.setFocusPolicy(Qt.NoFocus) h.returnPressed.connect(self.do_search) b.clicked.connect(self.do_search) self.clear_button = cb = QToolButton(self) cb.setIcon(QIcon(I('clear_left.png'))) cb.setFocusPolicy(Qt.NoFocus) cb.setText(_('Clear search')) cb.clicked.connect(self.clear_search) l.addWidget(h), l.addWidget(b, 0, 1), l.addWidget(cb, 0, 2) self.category_view = CategoryView(self) self.category_view.setFocusPolicy(Qt.NoFocus) l.addWidget(s, 1, 0, 1, 3) self.char_view = CharView(self) self.char_view.setFocusPolicy(Qt.NoFocus) self.rearrange_button.toggled[bool].connect( self.set_allow_drag_and_drop) self.category_view.category_selected.connect(self.show_chars) self.char_view.show_name.connect(self.show_char_info) self.char_view.char_selected.connect(self.char_selected) s.addWidget(self.category_view), s.addWidget(self.char_view) self.char_info = la = QLabel('\xa0') la.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) l.addWidget(la, 2, 0, 1, 3) self.rearrange_msg = la = QLabel( _('Drag and drop characters to re-arrange them. Click the "Re-arrange" button again when you are done.' )) la.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) la.setVisible(False) l.addWidget(la, 3, 0, 1, 3) self.h = h = QHBoxLayout() h.setContentsMargins(0, 0, 0, 0) self.match_any = mm = QCheckBox(_('Match any word')) mm.setToolTip( _('When searching return characters whose names match any of the specified words' )) mm.setChecked(tprefs.get('char_select_match_any', True)) connect_lambda( mm.stateChanged, self, lambda self: tprefs.set( 'char_select_match_any', self.match_any.isChecked())) h.addWidget(mm), h.addStretch(), h.addWidget(self.bb) l.addLayout(h, 4, 0, 1, 3) self.char_view.setFocus(Qt.OtherFocusReason)
def __init__(self, parent=None): self.initialized = False Dialog.__init__(self, _('Insert character'), 'charmap_dialog', parent) self.setWindowIcon(QIcon(I('character-set.png'))) self.setFocusProxy(parent)
def genesis(self, gui): self.gui = gui db = gui.library_view.model().db r = self.register try: self.icon_theme_title = json.loads(I('icon-theme.json', data=True))['name'] except Exception: self.icon_theme_title = _('Default icons') self.icon_theme.setText( _('Icon theme: <b>%s</b>') % self.icon_theme_title) self.commit_icon_theme = None self.icon_theme_button.clicked.connect(self.choose_icon_theme) r('gui_layout', config, restart_required=True, choices=[(_('Wide'), 'wide'), (_('Narrow'), 'narrow')]) r('ui_style', gprefs, restart_required=True, choices=[(_('System default'), 'system'), (_('Calibre style'), 'calibre')]) r('book_list_tooltips', gprefs) r('tag_browser_old_look', gprefs, restart_required=True) r('tag_browser_hide_empty_categories', gprefs) r('bd_show_cover', gprefs) r('bd_overlay_cover_size', gprefs) r('cover_grid_width', gprefs) r('cover_grid_height', gprefs) r('cover_grid_cache_size_multiple', gprefs) r('cover_grid_disk_cache_size', gprefs) r('cover_grid_spacing', gprefs) r('cover_grid_show_title', gprefs) r('cover_flow_queue_length', config, restart_required=True) r('cover_browser_reflections', gprefs) r('show_rating_in_cover_browser', gprefs) r('cover_browser_title_template', db.prefs) r('emblem_size', gprefs) r('emblem_position', gprefs, choices=[(_('Left'), 'left'), (_('Top'), 'top'), (_('Right'), 'right'), (_('Bottom'), 'bottom')]) r('book_list_extra_row_spacing', gprefs) self.cover_browser_title_template_button.clicked.connect( self.edit_cb_title_template) self.id_links_button.clicked.connect(self.edit_id_link_rules) def get_esc_lang(l): if l == 'en': return 'English' return get_language(l) lang = get_lang() if lang is None or lang not in available_translations(): lang = 'en' items = [(l, get_esc_lang(l)) for l in available_translations() if l != lang] if lang != 'en': items.append(('en', get_esc_lang('en'))) items.sort(cmp=lambda x, y: cmp(x[1].lower(), y[1].lower())) choices = [(y, x) for x, y in items] # Default language is the autodetected one choices = [(get_language(lang), lang)] + choices r('language', prefs, choices=choices, restart_required=True) r('show_avg_rating', config) r('disable_animations', config) r('systray_icon', config, restart_required=True) r('show_splash_screen', gprefs) r('disable_tray_notification', config) r('use_roman_numerals_for_series_number', config) r('separate_cover_flow', config, restart_required=True) r('cb_fullscreen', gprefs) r('cb_preserve_aspect_ratio', gprefs) choices = [(_('Off'), 'off'), (_('Small'), 'small'), (_('Medium'), 'medium'), (_('Large'), 'large')] r('toolbar_icon_size', gprefs, choices=choices) choices = [(_('If there is enough room'), 'auto'), (_('Always'), 'always'), (_('Never'), 'never')] r('toolbar_text', gprefs, choices=choices) choices = [(_('Disabled'), 'disable'), (_('By first letter'), 'first letter'), (_('Partitioned'), 'partition')] r('tags_browser_partition_method', gprefs, choices=choices) r('tags_browser_collapse_at', gprefs) r('default_author_link', gprefs) r('tag_browser_dont_collapse', gprefs, setting=CommaSeparatedList) self.search_library_for_author_button.clicked.connect( lambda: self.opt_default_author_link.setText('search-calibre')) choices = set([ k for k in db.field_metadata.all_field_keys() if (db.field_metadata[k]['is_category'] and (db.field_metadata[k]['datatype'] in ['text', 'series', 'enumeration']) and not db.field_metadata[k]['display'].get('is_names', False)) or (db.field_metadata[k]['datatype'] in ['composite'] and db.field_metadata[k]['display'].get('make_category', False)) ]) choices -= set( ['authors', 'publisher', 'formats', 'news', 'identifiers']) choices |= set(['search']) self.opt_categories_using_hierarchy.update_items_cache(choices) r('categories_using_hierarchy', db.prefs, setting=CommaSeparatedList, choices=sorted(list(choices), key=sort_key)) fm = db.field_metadata choices = sorted( ((fm[k]['name'], k) for k in fm.displayable_field_keys() if fm[k]['name']), key=lambda x: sort_key(x[0])) r('field_under_covers_in_grid', db.prefs, choices=choices) self.current_font = self.initial_font = None self.change_font_button.clicked.connect(self.change_font) self.display_model = DisplayedFields(self.gui.current_db, self.field_display_order) self.display_model.dataChanged.connect(self.changed_signal) self.field_display_order.setModel(self.display_model) self.df_up_button.clicked.connect(self.move_df_up) self.df_down_button.clicked.connect(self.move_df_down) self.edit_rules = EditRules(self.tabWidget) self.edit_rules.changed.connect(self.changed_signal) self.tabWidget.addTab(self.edit_rules, QIcon(I('format-fill-color.png')), _('Column coloring')) self.icon_rules = EditRules(self.tabWidget) self.icon_rules.changed.connect(self.changed_signal) self.tabWidget.addTab(self.icon_rules, QIcon(I('icon_choose.png')), _('Column icons')) self.grid_rules = EditRules(self.emblems_tab) self.grid_rules.changed.connect(self.changed_signal) self.emblems_tab.setLayout(QVBoxLayout()) self.emblems_tab.layout().addWidget(self.grid_rules) self.tabWidget.setCurrentIndex(0) keys = [ QKeySequence('F11', QKeySequence.PortableText), QKeySequence('Ctrl+Shift+F', QKeySequence.PortableText) ] keys = [unicode(x.toString(QKeySequence.NativeText)) for x in keys] self.fs_help_msg.setText( unicode(self.fs_help_msg.text()) % (_(' or ').join(keys))) self.size_calculated.connect(self.update_cg_cache_size, type=Qt.QueuedConnection) self.tabWidget.currentChanged.connect(self.tab_changed) l = self.cg_background_box.layout() self.cg_bg_widget = w = Background(self) l.addWidget(w, 0, 0, 3, 1) self.cover_grid_color_button = b = QPushButton(_('Change &color'), self) b.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) l.addWidget(b, 0, 1) b.clicked.connect(self.change_cover_grid_color) self.cover_grid_texture_button = b = QPushButton( _('Change &background image'), self) b.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) l.addWidget(b, 1, 1) b.clicked.connect(self.change_cover_grid_texture) self.cover_grid_default_appearance_button = b = QPushButton( _('Restore &default appearance'), self) b.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) l.addWidget(b, 2, 1) b.clicked.connect(self.restore_cover_grid_appearance) self.cover_grid_empty_cache.clicked.connect(self.empty_cache) self.cover_grid_open_cache.clicked.connect(self.open_cg_cache) self.cover_grid_smaller_cover.clicked.connect( partial(self.resize_cover, True)) self.cover_grid_larger_cover.clicked.connect( partial(self.resize_cover, False)) self.cover_grid_reset_size.clicked.connect(self.cg_reset_size) self.opt_cover_grid_disk_cache_size.setMinimum( self.gui.grid_view.thumbnail_cache.min_disk_cache) self.opt_cover_grid_disk_cache_size.setMaximum( self.gui.grid_view.thumbnail_cache.min_disk_cache * 100) self.opt_cover_grid_width.valueChanged.connect( self.update_aspect_ratio) self.opt_cover_grid_height.valueChanged.connect( self.update_aspect_ratio)
def __init__(self, parent, view, row, link_delegate): QDialog.__init__(self, parent) self.normal_brush = QBrush(Qt.white) self.marked_brush = QBrush(Qt.lightGray) self.marked = None self.gui = parent self.splitter = QSplitter(self) self._l = l = QVBoxLayout(self) self.setLayout(l) l.addWidget(self.splitter) self.cover = Cover(self, show_size=gprefs['bd_overlay_cover_size']) self.cover.resizeEvent = self.cover_view_resized self.cover.cover_changed.connect(self.cover_changed) self.cover.open_with_requested.connect(self.open_with) self.cover.choose_open_with_requested.connect(self.choose_open_with) self.cover_pixmap = None self.cover.sizeHint = self.details_size_hint self.splitter.addWidget(self.cover) self.details = Details(parent.book_details.book_info, self) self.details.anchor_clicked.connect(self.on_link_clicked) self.link_delegate = link_delegate self.details.setAttribute(Qt.WA_OpaquePaintEvent, False) palette = self.details.palette() self.details.setAcceptDrops(False) palette.setBrush(QPalette.Base, Qt.transparent) self.details.setPalette(palette) self.c = QWidget(self) self.c.l = l2 = QGridLayout(self.c) l2.setContentsMargins(0, 0, 0, 0) self.c.setLayout(l2) l2.addWidget(self.details, 0, 0, 1, -1) self.splitter.addWidget(self.c) self.fit_cover = QCheckBox(_('Fit &cover within view'), self) self.fit_cover.setChecked( gprefs.get('book_info_dialog_fit_cover', True)) self.hl = hl = QHBoxLayout() hl.setContentsMargins(0, 0, 0, 0) l2.addLayout(hl, l2.rowCount(), 0, 1, -1) hl.addWidget(self.fit_cover), hl.addStretch() self.clabel = QLabel( '<div style="text-align: right"><a href="calibre:conf" title="{}" style="text-decoration: none">{}</a>' .format(_('Configure this view'), _('Configure'))) self.clabel.linkActivated.connect(self.configure) hl.addWidget(self.clabel) self.previous_button = QPushButton(QIcon(I('previous.png')), _('&Previous'), self) self.previous_button.clicked.connect(self.previous) l2.addWidget(self.previous_button, l2.rowCount(), 0) self.next_button = QPushButton(QIcon(I('next.png')), _('&Next'), self) self.next_button.clicked.connect(self.next) l2.addWidget(self.next_button, l2.rowCount() - 1, 1) self.view = view self.path_to_book = None self.current_row = None self.refresh(row) self.view.model().new_bookdisplay_data.connect(self.slave) self.fit_cover.stateChanged.connect(self.toggle_cover_fit) self.ns = QShortcut(QKeySequence('Alt+Right'), self) self.ns.activated.connect(self.next) self.ps = QShortcut(QKeySequence('Alt+Left'), self) self.ps.activated.connect(self.previous) self.next_button.setToolTip( _('Next [%s]') % unicode_type(self.ns.key().toString(QKeySequence.NativeText))) self.previous_button.setToolTip( _('Previous [%s]') % unicode_type(self.ps.key().toString(QKeySequence.NativeText))) geom = QCoreApplication.instance().desktop().availableGeometry(self) screen_height = geom.height() - 100 screen_width = geom.width() - 100 self.resize(max(int(screen_width / 2), 700), screen_height) saved_layout = gprefs.get('book_info_dialog_layout', None) if saved_layout is not None: try: QApplication.instance().safe_restore_geometry( self, saved_layout[0]) self.splitter.restoreState(saved_layout[1]) except Exception: pass from calibre.gui2.ui import get_gui ema = get_gui().iactions['Edit Metadata'].menuless_qaction a = self.ema = QAction('edit metadata', self) a.setShortcut(ema.shortcut()) self.addAction(a) a.triggered.connect(self.edit_metadata)
def _initUi(self): app = Application.instance() icon = QIcon(app.findResource('Subtitles.png')) iconLabel = QLabel() iconLabel.setPixmap(icon.pixmap(128)) iconLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) appNameLabel = QLabel(self) appNameLabel.setText(app.applicationName()) appNameLabel.setAlignment(Qt.AlignHCenter | Qt.AlignTop) appNameLabel.setStyleSheet('font-weight: bold; font-size: 18pt') appNameLabel.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum) version_labels = self._createVersionLabels() licenseLabel = self._createSelectableLabel( 'Copyright © 2018–2019 Philip Belemezov<br>' 'Licensed under the <a href="about:blank">' 'GNU General Public License, version 3</a>.') licenseLabel.setStyleSheet('color: gray; font-size: 8pt') licenseLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) licenseLabel.setTextFormat(Qt.RichText) licenseLabel.setTextInteractionFlags(Qt.TextBrowserInteraction) licenseLabel.linkActivated.connect(self.showLicense) homepageLabel = self._createLinkLabel( text=self.tr("Homepage"), href="https://github.io/philipbel/subtitles") homepageLabel.setAlignment(Qt.AlignCenter) ackLabel = self._createLinkLabel(text=self.tr("Acknowledgements")) ackLabel.setAlignment(Qt.AlignCenter) ackLabel.linkActivated.connect(self.showAcknowledgements) linksLayout = QVBoxLayout() linksLayout.addWidget(homepageLabel) linksLayout.addSpacing(5) linksLayout.addWidget(ackLabel) versionInfoLayout = QFormLayout() versionInfoLayout.setFormAlignment(Qt.AlignHCenter) versionInfoLayout.setHorizontalSpacing(4) for name, value in version_labels: name.setText(name.text() + ':') versionInfoLayout.addRow(name, value) mainLayout = QVBoxLayout(self) mainLayout.setSpacing(0) mainLayout.addWidget(iconLabel) mainLayout.addWidget(appNameLabel) mainLayout.addSpacing(5) mainLayout.addLayout(versionInfoLayout) mainLayout.addSpacing(20) mainLayout.addLayout(linksLayout) mainLayout.addSpacing(20) mainLayout.addWidget(licenseLabel) if sys.platform != 'darwin': buttonBox = QDialogButtonBox(QDialogButtonBox.Close) buttonBox.setCenterButtons(True) buttonBox.button(QDialogButtonBox.Close).clicked.connect( self.reject) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) mainLayout.addSpacing(8) mainLayout.addWidget(line) mainLayout.addSpacing(8) mainLayout.addWidget(buttonBox)
def __init__(self, type_, title, msg, det_msg='', q_icon=None, show_copy_button=True, parent=None, default_yes=True, yes_text=None, no_text=None, yes_icon=None, no_icon=None): QDialog.__init__(self, parent) if q_icon is None: icon = { self.ERROR: 'error', self.WARNING: 'warning', self.INFO: 'information', self.QUESTION: 'question', }[type_] icon = 'dialog_%s.png' % icon self.icon = QIcon(I(icon)) else: self.icon = q_icon if isinstance(q_icon, QIcon) else QIcon( I(q_icon)) self.setup_ui() self.setWindowTitle(title) self.setWindowIcon(self.icon) self.icon_label.setPixmap(self.icon.pixmap(128, 128)) self.msg.setText(msg) self.det_msg.setPlainText(det_msg) self.det_msg.setVisible(False) self.toggle_checkbox.setVisible(False) if show_copy_button: self.ctc_button = self.bb.addButton(_('&Copy to clipboard'), self.bb.ActionRole) self.ctc_button.clicked.connect(self.copy_to_clipboard) self.show_det_msg = _('Show &details') self.hide_det_msg = _('Hide &details') self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole) self.det_msg_toggle.clicked.connect(self.toggle_det_msg) self.det_msg_toggle.setToolTip( _('Show detailed information about this error')) self.copy_action = QAction(self) self.addAction(self.copy_action) self.copy_action.setShortcuts(QKeySequence.Copy) self.copy_action.triggered.connect(self.copy_to_clipboard) self.is_question = type_ == self.QUESTION if self.is_question: self.bb.setStandardButtons(self.bb.Yes | self.bb.No) self.bb.button( self.bb.Yes if default_yes else self.bb.No).setDefault(True) self.default_yes = default_yes if yes_text is not None: self.bb.button(self.bb.Yes).setText(yes_text) if no_text is not None: self.bb.button(self.bb.No).setText(no_text) if yes_icon is not None: self.bb.button(self.bb.Yes).setIcon(yes_icon if isinstance( yes_icon, QIcon) else QIcon(I(yes_icon))) if no_icon is not None: self.bb.button(self.bb.No).setIcon(no_icon if isinstance( no_icon, QIcon) else QIcon(I(no_icon))) else: self.bb.button(self.bb.Ok).setDefault(True) if not det_msg: self.det_msg_toggle.setVisible(False) self.resize_needed.connect(self.do_resize, type=Qt.QueuedConnection) self.do_resize()
def __init__(self, gui, initial_panel=None): QDialog.__init__(self, gui) self.l = l = QGridLayout(self) self.setLayout(l) self.setWindowTitle(_('Preferences for Edit book')) self.setWindowIcon(QIcon(I('config.png'))) self.stacks = QStackedWidget(self) l.addWidget(self.stacks, 0, 1, 1, 1) self.categories_list = cl = QListWidget(self) cl.currentRowChanged.connect(self.stacks.setCurrentIndex) cl.clearPropertyFlags() cl.setViewMode(cl.IconMode) cl.setFlow(cl.TopToBottom) cl.setMovement(cl.Static) cl.setWrapping(False) cl.setSpacing(15) if get_lang()[:2] not in ('zh', 'ja'): cl.setWordWrap(True) l.addWidget(cl, 0, 0, 1, 1) self.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) self.rdb = b = bb.addButton(_('Restore all &defaults'), bb.ResetRole) b.setToolTip(_('Restore defaults for all preferences')) b.clicked.connect(self.restore_all_defaults) self.rcdb = b = bb.addButton(_('Restore ¤t defaults'), bb.ResetRole) b.setToolTip(_('Restore defaults for currently displayed preferences')) b.clicked.connect(self.restore_current_defaults) self.rconfs = b = bb.addButton(_('Restore c&onfirmations'), bb.ResetRole) b.setToolTip(_('Restore all disabled confirmation prompts')) b.clicked.connect(self.restore_confirmations) l.addWidget(bb, 1, 0, 1, 2) self.resize(800, 600) geom = tprefs.get('preferences_geom', None) if geom is not None: self.restoreGeometry(geom) self.keyboard_panel = ShortcutConfig(self) self.keyboard_panel.initialize(gui.keyboard) self.editor_panel = EditorSettings(self) self.integration_panel = IntegrationSettings(self) self.main_window_panel = MainWindowSettings(self) self.preview_panel = PreviewSettings(self) self.toolbars_panel = ToolbarSettings(self) for name, icon, panel in [ (_('Main window'), 'page.png', 'main_window'), (_('Editor settings'), 'modified.png', 'editor'), (_('Preview settings'), 'viewer.png', 'preview'), (_('Keyboard shortcuts'), 'keyboard-prefs.png', 'keyboard'), (_('Toolbars'), 'wizard.png', 'toolbars'), (_('Integration with calibre'), 'lt.png', 'integration'), ]: i = QListWidgetItem(QIcon(I(icon)), name, cl) cl.addItem(i) self.stacks.addWidget(getattr(self, panel + '_panel')) cl.setCurrentRow(0) cl.item(0).setSelected(True) w, h = cl.sizeHintForColumn(0), 0 for i in range(cl.count()): h = cl.sizeHintForRow(i) cl.item(i).setSizeHint(QSize(w, h)) cl.setMaximumWidth(cl.sizeHintForColumn(0) + 35) cl.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
def context_menu_handler(self, action=None, category=None, key=None, index=None, search_state=None, use_vl=None): if not action: return try: if action == 'set_icon': try: path = choose_files(self, 'choose_category_icon', _('Change Icon for: %s') % key, filters=[ ('Images', ['png', 'gif', 'jpg', 'jpeg']) ], all_files=False, select_only_single_file=True) if path: path = path[0] p = QIcon(path).pixmap(QSize(128, 128)) d = os.path.join(config_dir, 'tb_icons') if not os.path.exists(d): os.makedirs(d) with open( os.path.join( d, 'icon_' + sanitize_file_name_unicode(key) + '.png'), 'wb') as f: f.write(pixmap_to_data(p, format='PNG')) path = os.path.basename(f.name) self._model.set_custom_category_icon( key, unicode(path)) self.recount() except: import traceback traceback.print_exc() return if action == 'clear_icon': self._model.set_custom_category_icon(key, None) self.recount() return if action == 'edit_item_no_vl': item = self.model().get_node(index) item.use_vl = False self.edit(index) return if action == 'edit_item_in_vl': item = self.model().get_node(index) item.use_vl = True self.edit(index) return if action == 'delete_item_in_vl': self.tag_item_delete.emit(key, index.id, index.original_name, self.model().get_book_ids_to_use()) return if action == 'delete_item_no_vl': self.tag_item_delete.emit(key, index.id, index.original_name, None) return if action == 'open_editor': self.tags_list_edit.emit(category, key) return if action == 'manage_categories': self.edit_user_category.emit(category) return if action == 'search': self._toggle(index, set_to=search_state) return if action == 'add_to_category': tag = index.tag if len(index.children) > 0: for c in index.all_children(): self.add_item_to_user_cat.emit(category, c.tag.original_name, c.tag.category) self.add_item_to_user_cat.emit(category, tag.original_name, tag.category) return if action == 'add_subcategory': self.add_subcategory.emit(key) return if action == 'search_category': self._toggle(index, set_to=search_state) return if action == 'delete_user_category': self.delete_user_category.emit(key) return if action == 'delete_search': self.model().db.saved_search_delete(key) self.rebuild_saved_searches.emit() return if action == 'delete_item_from_user_category': tag = index.tag if len(index.children) > 0: for c in index.children: self.del_item_from_user_cat.emit( key, c.tag.original_name, c.tag.category) self.del_item_from_user_cat.emit(key, tag.original_name, tag.category) return if action == 'manage_searches': self.saved_search_edit.emit(category) return if action == 'edit_author_sort': self.author_sort_edit.emit(self, index, True, False) return if action == 'edit_author_link': self.author_sort_edit.emit(self, index, False, True) return reset_filter_categories = True if action == 'hide': self.hidden_categories.add(category) elif action == 'show': self.hidden_categories.discard(category) elif action == 'categorization': changed = self.collapse_model != category self._model.collapse_model = category if changed: reset_filter_categories = False gprefs['tags_browser_partition_method'] = category elif action == 'defaults': self.hidden_categories.clear() self.db.new_api.set_pref('tag_browser_hidden_categories', list(self.hidden_categories)) if reset_filter_categories: self._model.set_categories_filter(None) self._model.rebuild_node_tree() except: return
def __init__(self, db, book_id_map, parent=None): from calibre.ebooks.oeb.polish.main import HELP QDialog.__init__(self, parent) self.db, self.book_id_map = weakref.ref(db), book_id_map self.setWindowIcon(QIcon(I('polish.png'))) title = _('Polish book') if len(book_id_map) > 1: title = _('Polish %d books')%len(book_id_map) self.setWindowTitle(title) self.help_text = { 'polish': _('<h3>About Polishing books</h3>%s')%HELP['about'].format( _('''<p>If you have both EPUB and ORIGINAL_EPUB in your book, then polishing will run on ORIGINAL_EPUB (the same for other ORIGINAL_* formats). So if you want Polishing to not run on the ORIGINAL_* format, delete the ORIGINAL_* format before running it.</p>''') ), 'embed':_('<h3>Embed referenced fonts</h3>%s')%HELP['embed'], 'subset':_('<h3>Subsetting fonts</h3>%s')%HELP['subset'], 'smarten_punctuation': _('<h3>Smarten punctuation</h3>%s')%HELP['smarten_punctuation'], 'metadata':_('<h3>Updating metadata</h3>' '<p>This will update all metadata <i>except</i> the cover in the' ' e-book files to match the current metadata in the' ' calibre library.</p>' ' <p>Note that most e-book' ' formats are not capable of supporting all the' ' metadata in calibre.</p><p>There is a separate option to' ' update the cover.</p>'), 'do_cover': _('<h3>Update cover</h3><p>Update the covers in the e-book files to match the' ' current cover in the calibre library.</p>' '<p>If the e-book file does not have' ' an identifiable cover, a new cover is inserted.</p>' ), 'jacket':_('<h3>Book jacket</h3>%s')%HELP['jacket'], 'remove_jacket':_('<h3>Remove book jacket</h3>%s')%HELP['remove_jacket'], 'remove_unused_css':_('<h3>Remove unused CSS rules</h3>%s')%HELP['remove_unused_css'], 'compress_images': _('<h3>Losslessly compress images</h3>%s') % HELP['compress_images'], 'add_soft_hyphens': _('<h3>Add soft-hyphens</h3>%s') % HELP['add_soft_hyphens'], 'remove_soft_hyphens': _('<h3>Remove soft-hyphens</h3>%s') % HELP['remove_soft_hyphens'], 'upgrade_book': _('<h3>Upgrade book internals</h3>%s') % HELP['upgrade_book'], } self.l = l = QGridLayout() self.setLayout(l) self.la = la = QLabel('<b>'+_('Select actions to perform:')) l.addWidget(la, 0, 0, 1, 2) count = 0 self.all_actions = OrderedDict([ ('embed', _('&Embed all referenced fonts')), ('subset', _('&Subset all embedded fonts')), ('smarten_punctuation', _('Smarten &punctuation')), ('metadata', _('Update &metadata in the book files')), ('do_cover', _('Update the &cover in the book files')), ('jacket', _('Add/replace metadata as a "book &jacket" page')), ('remove_jacket', _('&Remove a previously inserted book jacket')), ('remove_unused_css', _('Remove &unused CSS rules from the book')), ('compress_images', _('Losslessly &compress images')), ('add_soft_hyphens', _('Add s&oft hyphens')), ('remove_soft_hyphens', _('Remove soft hyphens')), ('upgrade_book', _('&Upgrade book internals')), ]) prefs = gprefs.get('polishing_settings', {}) for name, text in iteritems(self.all_actions): count += 1 x = QCheckBox(text, self) x.setChecked(prefs.get(name, False)) x.setObjectName(name) connect_lambda(x.stateChanged, self, lambda self, state: self.option_toggled(self.sender().objectName(), state)) l.addWidget(x, count, 0, 1, 1) setattr(self, 'opt_'+name, x) la = QLabel(' <a href="#%s">%s</a>'%(name, _('About'))) setattr(self, 'label_'+name, x) la.linkActivated.connect(self.help_link_activated) l.addWidget(la, count, 1, 1, 1) count += 1 l.addItem(QSpacerItem(10, 10, vPolicy=QSizePolicy.Policy.Expanding), count, 1, 1, 2) la = self.help_label = QLabel('') self.help_link_activated('#polish') la.setWordWrap(True) la.setTextFormat(Qt.TextFormat.RichText) la.setFrameShape(QFrame.Shape.StyledPanel) la.setAlignment(Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignTop) la.setLineWidth(2) la.setStyleSheet('QLabel { margin-left: 75px }') l.addWidget(la, 0, 2, count+1, 1) l.setColumnStretch(2, 1) self.show_reports = sr = QCheckBox(_('Show &report'), self) sr.setChecked(gprefs.get('polish_show_reports', True)) sr.setToolTip(textwrap.fill(_('Show a report of all the actions performed' ' after polishing is completed'))) l.addWidget(sr, count+1, 0, 1, 1) self.bb = bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok|QDialogButtonBox.StandardButton.Cancel) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) self.save_button = sb = bb.addButton(_('&Save settings'), QDialogButtonBox.ButtonRole.ActionRole) sb.clicked.connect(self.save_settings) self.load_button = lb = bb.addButton(_('&Load settings'), QDialogButtonBox.ButtonRole.ActionRole) self.load_menu = QMenu(lb) lb.setMenu(self.load_menu) self.all_button = b = bb.addButton(_('Select &all'), QDialogButtonBox.ButtonRole.ActionRole) connect_lambda(b.clicked, self, lambda self: self.select_all(True)) self.none_button = b = bb.addButton(_('Select &none'), QDialogButtonBox.ButtonRole.ActionRole) connect_lambda(b.clicked, self, lambda self: self.select_all(False)) l.addWidget(bb, count+1, 1, 1, -1) self.setup_load_button() self.resize(QSize(950, 600))
class CoverMessageBox(QDialog, Ui_Dialog): ERROR = 0 WARNING = 1 INFO = 2 QUESTION = 3 def __init__(self, type_, title, msg, opts, det_msg='', q_icon=None, show_copy_button=True, parent=None, default_yes=True): QDialog.__init__(self, parent) if q_icon is None: icon = { self.ERROR: 'error', self.WARNING: 'warning', self.INFO: 'information', self.QUESTION: 'question', }[type_] icon = 'dialog_%s.png' % icon self.icon = QIcon(I(icon)) else: self.icon = q_icon self.setupUi(self) self.setWindowTitle(title) self.setWindowIcon(opts.icon) #self.icon_label.setPixmap(self.icon.pixmap(self.COVER_SIZE, self.COVER_SIZE)) self.icon_label.setPixmap(self.icon.pixmap(COVER_ICON_SIZE)) self.msg.setText(msg) self.msg.setOpenExternalLinks(True) self.det_msg.setPlainText(det_msg) self.det_msg.setVisible(False) self.toggle_checkbox.setVisible(False) if show_copy_button: self.ctc_button = self.bb.addButton(_('&Copy to clipboard'), self.bb.ActionRole) self.ctc_button.clicked.connect(self.copy_to_clipboard) self.show_det_msg = _('Show &details') self.hide_det_msg = _('Hide &details') self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole) self.det_msg_toggle.clicked.connect(self.toggle_det_msg) self.det_msg_toggle.setToolTip( _('Show detailed information')) self.copy_action = QAction(self) self.addAction(self.copy_action) self.copy_action.setShortcuts(QKeySequence.Copy) self.copy_action.triggered.connect(self.copy_to_clipboard) self.is_question = type_ == self.QUESTION if self.is_question: self.bb.setStandardButtons(self.bb.Yes | self.bb.No) self.bb.button(self.bb.Yes if default_yes else self.bb.No ).setDefault(True) self.default_yes = default_yes else: self.bb.button(self.bb.Ok).setDefault(True) if not det_msg: self.det_msg_toggle.setVisible(False) self.do_resize() def toggle_det_msg(self, *args): vis = unicode(self.det_msg_toggle.text()) == self.hide_det_msg self.det_msg_toggle.setText(self.show_det_msg if vis else self.hide_det_msg) self.det_msg.setVisible(not vis) self.do_resize() def do_resize(self): sz = self.sizeHint() + QSize(100, 0) sz.setWidth(min(500, sz.width())) sz.setHeight(min(500, sz.height())) self.resize(sz) def copy_to_clipboard(self, *args): QApplication.clipboard().setText( 'calibre, version %s\n%s: %s\n\n%s' % (__version__, unicode(self.windowTitle()), unicode(self.msg.text()), unicode(self.det_msg.toPlainText()))) if hasattr(self, 'ctc_button'): self.ctc_button.setText(_('Copied')) def showEvent(self, ev): ret = QDialog.showEvent(self, ev) if self.is_question: try: self.bb.button(self.bb.Yes if self.default_yes else self.bb.No ).setFocus(Qt.OtherFocusReason) except: # Buttons were changed pass else: self.bb.button(self.bb.Ok).setFocus(Qt.OtherFocusReason) return ret def set_details(self, msg): if not msg: msg = '' self.det_msg.setPlainText(msg) self.det_msg_toggle.setText(self.show_det_msg) self.det_msg_toggle.setVisible(bool(msg)) self.det_msg.setVisible(False) self.do_resize()
def register_text_editor_actions(_reg, palette): def reg(*args, **kw): ac = _reg(*args) for s in kw.get('syntaxes', ('format', )): editor_toolbar_actions[s][args[3]] = ac return ac ac = reg('format-text-bold', _('&Bold'), ('format_text', 'bold'), 'format-text-bold', 'Ctrl+B', _('Make the selected text bold')) ac.setToolTip(_('<h3>Bold</h3>Make the selected text bold')) ac = reg('format-text-italic', _('&Italic'), ('format_text', 'italic'), 'format-text-italic', 'Ctrl+I', _('Make the selected text italic')) ac.setToolTip(_('<h3>Italic</h3>Make the selected text italic')) ac = reg('format-text-underline', _('&Underline'), ('format_text', 'underline'), 'format-text-underline', (), _('Underline the selected text')) ac.setToolTip(_('<h3>Underline</h3>Underline the selected text')) ac = reg('format-text-strikethrough', _('&Strikethrough'), ('format_text', 'strikethrough'), 'format-text-strikethrough', (), _('Draw a line through the selected text')) ac.setToolTip( _('<h3>Strikethrough</h3>Draw a line through the selected text')) ac = reg('format-text-superscript', _('&Superscript'), ('format_text', 'superscript'), 'format-text-superscript', (), _('Make the selected text a superscript')) ac.setToolTip( _('<h3>Superscript</h3>Set the selected text slightly smaller and above the normal line' )) ac = reg('format-text-subscript', _('&Subscript'), ('format_text', 'subscript'), 'format-text-subscript', (), _('Make the selected text a subscript')) ac.setToolTip( _('<h3>Subscript</h3>Set the selected text slightly smaller and below the normal line' )) ac = reg('format-text-color', _('&Color'), ('format_text', 'color'), 'format-text-color', (), _('Change text color')) ac.setToolTip(_('<h3>Color</h3>Change the color of the selected text')) ac = reg('format-fill-color', _('&Background Color'), ('format_text', 'background-color'), 'format-text-background-color', (), _('Change background color of text')) ac.setToolTip( _('<h3>Background Color</h3>Change the background color of the selected text' )) ac = reg('format-justify-left', _('Align &left'), ('format_text', 'justify_left'), 'format-text-justify-left', (), _('Align left')) ac.setToolTip(_('<h3>Align left</h3>Align the paragraph to the left')) ac = reg('format-justify-center', _('&Center'), ('format_text', 'justify_center'), 'format-text-justify-center', (), _('Center')) ac.setToolTip(_('<h3>Center</h3>Center the paragraph')) ac = reg('format-justify-right', _('Align &right'), ('format_text', 'justify_right'), 'format-text-justify-right', (), _('Align right')) ac.setToolTip(_('<h3>Align right</h3>Align the paragraph to the right')) ac = reg('format-justify-fill', _('&Justify'), ('format_text', 'justify_justify'), 'format-text-justify-fill', (), _('Justify')) ac.setToolTip( _('<h3>Justify</h3>Align the paragraph to both the left and right margins' )) ac = reg('view-image', _('&Insert image'), ('insert_resource', 'image'), 'insert-image', (), _('Insert an image into the text'), syntaxes=('html', 'css')) ac.setToolTip(_('<h3>Insert image</h3>Insert an image into the text')) ac = reg('insert-link', _('Insert &hyperlink'), ('insert_hyperlink', ), 'insert-hyperlink', (), _('Insert hyperlink'), syntaxes=('html', )) ac.setToolTip( _('<h3>Insert hyperlink</h3>Insert a hyperlink into the text')) for i, name in enumerate(('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p')): text = ('&' + name) if name == 'p' else (name[0] + '&' + name[1]) desc = _('Convert the paragraph to <%s>') % name ac = reg(create_icon(name), text, ('rename_block_tag', name), 'rename-block-tag-' + name, 'Ctrl+%d' % (i + 1), desc, syntaxes=()) ac.setToolTip(desc) ac = reg('code', _('Insert &tag'), ('insert_tag', ), 'insert-tag', ('Ctrl+<'), _('Insert tag'), syntaxes=('html', 'xml')) ac.setToolTip( _('<h3>Insert tag</h3>Insert a tag, if some text is selected the tag will be inserted around the selected text' )) editor_toolbar_actions['html']['fix-html-current'] = actions[ 'fix-html-current'] for s in ('xml', 'html', 'css'): editor_toolbar_actions[s]['pretty-current'] = actions['pretty-current'] editor_toolbar_actions['html']['change-paragraph'] = actions[ 'change-paragraph'] = QAction(QIcon(I('format-text-heading.png')), _('Change paragraph to heading'), ac.parent())
def show_plugin(self, plugin=None): self.icon.set_icon( QIcon(I('lt.png') if plugin is None else plugin.icon)) self.title.setText( '<h1>' + (_('Preferences') if plugin is None else plugin.gui_name))
def setup_ui(self): self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, False) self.l = l = QVBoxLayout(self) self.setLayout(l) self.bb.clear() self.bb.addButton(self.bb.Close) self.splitter = s = QSplitter(self) self.h = h = QHBoxLayout() h.setContentsMargins(0, 0, 0, 0) self.install_fonts_button = b = QPushButton(_('&Install fonts'), self) h.addWidget(b), b.setIcon(QIcon(I('plus.png'))) b.setToolTip(textwrap.fill(_('Install fonts from .ttf/.otf files to make them available for embedding'))) b.clicked.connect(self.install_fonts) l.addWidget(s), l.addLayout(h), h.addStretch(10), h.addWidget(self.bb) self.fonts_view = fv = QTableView(self) fv.doubleClicked.connect(self.show_embedding_data) self.model = m = AllFonts(fv) fv.horizontalHeader().setStretchLastSection(True) fv.setModel(m) fv.setSortingEnabled(True) fv.setShowGrid(False) fv.setAlternatingRowColors(True) fv.setSelectionMode(fv.ExtendedSelection) fv.setSelectionBehavior(fv.SelectRows) fv.horizontalHeader().setSortIndicator(1, Qt.SortOrder.AscendingOrder) self.container = c = QWidget() l = c.l = QVBoxLayout(c) c.setLayout(l) s.addWidget(fv), s.addWidget(c) self.cb = b = QPushButton(_('&Change selected fonts')) b.setIcon(QIcon(I('wizard.png'))) b.clicked.connect(self.change_fonts) l.addWidget(b) self.rb = b = QPushButton(_('&Remove selected fonts')) b.clicked.connect(self.remove_fonts) b.setIcon(QIcon(I('trash.png'))) l.addWidget(b) self.eb = b = QPushButton(_('&Embed all fonts')) b.setIcon(QIcon(I('embed-fonts.png'))) b.clicked.connect(self.embed_fonts) l.addWidget(b) self.sb = b = QPushButton(_('&Subset all fonts')) b.setIcon(QIcon(I('subset-fonts.png'))) b.clicked.connect(self.subset_fonts) l.addWidget(b) self.refresh_button = b = self.bb.addButton(_('&Refresh'), self.bb.ActionRole) b.setToolTip(_('Rescan the book for fonts in case you have made changes')) b.setIcon(QIcon(I('view-refresh.png'))) b.clicked.connect(self.refresh) self.la = la = QLabel( '<p>' + _( ''' All the fonts declared in this book are shown to the left, along with whether they are embedded or not. You can remove or replace any selected font and also embed any declared fonts that are not already embedded.''') + '<p>' + _( ''' Double click any font family to see if the font is available for embedding on your computer. ''') ) la.setWordWrap(True) l.addWidget(la) l.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignHCenter)
def __init__(self, results, parent=None): QAbstractTableModel.__init__(self, parent) self.results = results self.yes_icon = (QIcon(I('ok.png')))
def editor_modified(self, *args): tb = self.editor_tabs.tabBar() for i in xrange(self.editor_tabs.count()): editor = self.editor_tabs.widget(i) modified = getattr(editor, 'is_modified', False) tb.setTabIcon(i, self.modified_icon if modified else QIcon())
def process(node, parent): parent.setIcon(0, QIcon(I('mimetypes/dir.png'))) for child in sorted(node, key=sort_key): c = QTreeWidgetItem(parent, (child, )) process(node[child], c)
def create_menubar(self): if isosx: p, q = self.create_application_menubar() q.triggered.connect(self.action_quit.trigger) p.triggered.connect(self.action_preferences.trigger) f = factory(app_id='com.calibre-ebook.EditBook-%d' % os.getpid()) b = f.create_window_menubar(self) f = b.addMenu(_('&File')) f.addAction(self.action_new_file) f.addAction(self.action_import_files) f.addSeparator() f.addAction(self.action_open_book) f.addAction(self.action_new_book) f.addAction(self.action_import_book) f.addAction(self.action_open_book_folder) self.recent_books_menu = f.addMenu(_('&Recently opened books')) self.update_recent_books() f.addSeparator() f.addAction(self.action_save) f.addAction(self.action_save_copy) f.addSeparator() f.addAction(self.action_compare_book) f.addAction(self.action_quit) e = b.addMenu(_('&Edit')) e.addAction(self.action_global_undo) e.addAction(self.action_global_redo) e.addAction(self.action_create_checkpoint) e.addSeparator() e.addAction(self.action_editor_undo) e.addAction(self.action_editor_redo) e.addSeparator() e.addAction(self.action_editor_cut) e.addAction(self.action_editor_copy) e.addAction(self.action_editor_paste) e.addAction(self.action_insert_char) e.addSeparator() e.addAction(self.action_quick_edit) e.addAction(self.action_preferences) e = b.addMenu(_('&Tools')) tm = e.addMenu(_('Table of Contents')) tm.addAction(self.action_toc) tm.addAction(self.action_inline_toc) e.addAction(self.action_manage_fonts) e.addAction(self.action_embed_fonts) e.addAction(self.action_subset_fonts) e.addAction(self.action_compress_images) e.addAction(self.action_smarten_punctuation) e.addAction(self.action_remove_unused_css) e.addAction(self.action_transform_styles) e.addAction(self.action_fix_html_all) e.addAction(self.action_pretty_all) e.addAction(self.action_rationalize_folders) e.addAction(self.action_add_cover) e.addAction(self.action_set_semantics) e.addAction(self.action_filter_css) e.addAction(self.action_spell_check_book) er = e.addMenu(_('External &links')) er.addAction(self.action_check_external_links) er.addAction(self.action_get_ext_resources) e.addAction(self.action_check_book) e.addAction(self.action_reports) e = b.addMenu(_('&View')) t = e.addMenu(_('Tool&bars')) e.addSeparator() for name in sorted(actions, key=lambda x: sort_key(actions[x].text())): ac = actions[name] if name.endswith('-dock'): e.addAction(ac) elif name.endswith('-bar'): t.addAction(ac) e.addAction(self.action_browse_images) e.addSeparator() e.addAction(self.action_close_current_tab) e.addAction(self.action_close_all_but_current_tab) e = b.addMenu(_('&Search')) a = e.addAction a(self.action_find) e.addSeparator() a(self.action_find_next) a(self.action_find_previous) e.addSeparator() a(self.action_replace) a(self.action_replace_next) a(self.action_replace_previous) a(self.action_replace_all) e.addSeparator() a(self.action_count) e.addSeparator() a(self.action_mark) e.addSeparator() a(self.action_go_to_line) e.addSeparator() a(self.action_saved_searches) e.aboutToShow.connect(self.search_menu_about_to_show) e.addSeparator() a(self.action_text_search) if self.plugin_menu_actions: e = b.addMenu(_('&Plugins')) for ac in sorted(self.plugin_menu_actions, key=lambda x: sort_key(unicode(x.text()))): e.addAction(ac) e = b.addMenu(_('&Help')) a = e.addAction a(self.action_help) a(QIcon(I('donate.png')), _('&Donate to support calibre development'), open_donate) a(self.action_preferences)
class JobError(QDialog): # {{{ WIDTH = 600 do_pop = pyqtSignal() def __init__(self, parent): QDialog.__init__(self, parent) self.setAttribute(Qt.WA_DeleteOnClose, False) self.queue = [] self.do_pop.connect(self.pop, type=Qt.QueuedConnection) self._layout = l = QGridLayout() self.setLayout(l) self.icon = QIcon(I('dialog_error.png')) self.setWindowIcon(self.icon) self.icon_label = QLabel() self.icon_label.setPixmap(self.icon.pixmap(68, 68)) self.icon_label.setMaximumSize(QSize(68, 68)) self.msg_label = QLabel('<p> ') self.msg_label.setStyleSheet('QLabel { margin-top: 1ex; }') self.msg_label.setWordWrap(True) self.msg_label.setTextFormat(Qt.RichText) self.det_msg = QPlainTextEdit(self) self.det_msg.setVisible(False) self.bb = QDialogButtonBox(QDialogButtonBox.Close, parent=self) self.bb.accepted.connect(self.accept) self.bb.rejected.connect(self.reject) self.ctc_button = self.bb.addButton(_('&Copy to clipboard'), self.bb.ActionRole) self.ctc_button.clicked.connect(self.copy_to_clipboard) self.retry_button = self.bb.addButton(_('&Retry'), self.bb.ActionRole) self.retry_button.clicked.connect(self.retry) self.retry_func = None self.show_det_msg = _('Show &details') self.hide_det_msg = _('Hide &details') self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole) self.det_msg_toggle.clicked.connect(self.toggle_det_msg) self.det_msg_toggle.setToolTip( _('Show detailed information about this error')) self.suppress = QCheckBox(self) l.addWidget(self.icon_label, 0, 0, 1, 1) l.addWidget(self.msg_label, 0, 1, 1, 1) l.addWidget(self.det_msg, 1, 0, 1, 2) l.addWidget(self.suppress, 2, 0, 1, 2, Qt.AlignLeft|Qt.AlignBottom) l.addWidget(self.bb, 3, 0, 1, 2, Qt.AlignRight|Qt.AlignBottom) l.setColumnStretch(1, 100) self.setModal(False) self.suppress.setVisible(False) self.do_resize() def retry(self): if self.retry_func is not None: self.accept() self.retry_func() def update_suppress_state(self): self.suppress.setText(_( 'Hide the remaining %d error messages'%len(self.queue))) self.suppress.setVisible(len(self.queue) > 3) self.do_resize() def copy_to_clipboard(self, *args): d = QTextDocument() d.setHtml(self.msg_label.text()) QApplication.clipboard().setText( u'calibre, version %s (%s, embedded-python: %s)\n%s: %s\n\n%s' % (__version__, sys.platform, isfrozen, unicode(self.windowTitle()), unicode(d.toPlainText()), unicode(self.det_msg.toPlainText()))) if hasattr(self, 'ctc_button'): self.ctc_button.setText(_('Copied')) def toggle_det_msg(self, *args): vis = unicode(self.det_msg_toggle.text()) == self.hide_det_msg self.det_msg_toggle.setText(self.show_det_msg if vis else self.hide_det_msg) self.det_msg.setVisible(not vis) self.do_resize() def do_resize(self): h = self.sizeHint().height() self.setMinimumHeight(0) # Needed as this gets set if det_msg is shown # Needed otherwise re-showing the box after showing det_msg causes the box # to not reduce in height self.setMaximumHeight(h) self.resize(QSize(self.WIDTH, h)) def showEvent(self, ev): ret = QDialog.showEvent(self, ev) self.bb.button(self.bb.Close).setFocus(Qt.OtherFocusReason) return ret def show_error(self, title, msg, det_msg=u'', retry_func=None): self.queue.append((title, msg, det_msg, retry_func)) self.update_suppress_state() self.pop() def pop(self): if not self.queue or self.isVisible(): return title, msg, det_msg, retry_func = self.queue.pop(0) self.setWindowTitle(title) self.msg_label.setText(msg) self.det_msg.setPlainText(det_msg) self.det_msg.setVisible(False) self.det_msg_toggle.setText(self.show_det_msg) self.det_msg_toggle.setVisible(True) self.suppress.setChecked(False) self.update_suppress_state() if not det_msg: self.det_msg_toggle.setVisible(False) self.retry_button.setVisible(retry_func is not None) self.retry_func = retry_func self.do_resize() self.show() def done(self, r): if self.suppress.isChecked(): self.queue = [] QDialog.done(self, r) self.do_pop.emit()
def __init__(self, gui, parent=None, query=''): QDialog.__init__(self, parent) self.setupUi(self) self.config = JSONConfig('store/search') self.search_title.initialize('store_search_search_title') self.search_author.initialize('store_search_search_author') self.search_edit.initialize('store_search_search') # Loads variables that store various settings. # This needs to be called soon in __init__ because # the variables it sets up are used later. self.load_settings() self.gui = gui # Setup our worker threads. self.search_pool = SearchThreadPool(self.search_thread_count) self.cache_pool = CacheUpdateThreadPool(self.cache_thread_count) self.results_view.model().cover_pool.set_thread_count( self.cover_thread_count) self.results_view.model().details_pool.set_thread_count( self.details_thread_count) self.results_view.setCursor(Qt.PointingHandCursor) # Check for results and hung threads. self.checker = QTimer() self.progress_checker = QTimer() self.hang_check = 0 # Update store caches silently. for p in self.gui.istores.values(): self.cache_pool.add_task(p, self.timeout) self.store_checks = {} self.setup_store_checks() # Set the search query if isinstance(query, (str, unicode)): self.search_edit.setText(query) elif isinstance(query, dict): if 'author' in query: self.search_author.setText(query['author']) if 'title' in query: self.search_title.setText(query['title']) # Create and add the progress indicator self.pi = ProgressIndicator(self, 24) self.button_layout.takeAt(0) self.button_layout.setAlignment(Qt.AlignCenter) self.button_layout.insertWidget(0, self.pi, 0, Qt.AlignCenter) self.adv_search_button.setIcon(QIcon(I('gear.png'))) self.adv_search_button.setToolTip(_('Advanced search')) self.configure.setIcon(QIcon(I('config.png'))) self.adv_search_button.clicked.connect(self.build_adv_search) self.search.clicked.connect(self.toggle_search) self.checker.timeout.connect(self.get_results) self.progress_checker.timeout.connect(self.check_progress) self.results_view.activated.connect(self.result_item_activated) self.results_view.download_requested.connect(self.download_book) self.results_view.open_requested.connect(self.open_store) self.results_view.model().total_changed.connect(self.update_book_total) self.select_all_stores.clicked.connect(self.stores_select_all) self.select_invert_stores.clicked.connect(self.stores_select_invert) self.select_none_stores.clicked.connect(self.stores_select_none) self.configure.clicked.connect(self.do_config) self.finished.connect(self.dialog_closed) self.searching = False self.progress_checker.start(100) self.restore_state()
def __init__(self, type_, title, msg, det_msg='', q_icon=None, show_copy_button=True, parent=None, default_yes=True, yes_text=None, no_text=None, yes_icon=None, no_icon=None): QDialog.__init__(self, parent) if q_icon is None: icon = { self.ERROR : 'error', self.WARNING: 'warning', self.INFO: 'information', self.QUESTION: 'question', }[type_] icon = 'dialog_%s.png'%icon self.icon = QIcon(I(icon)) else: self.icon = q_icon if isinstance(q_icon, QIcon) else QIcon(I(q_icon)) self.setup_ui() self.setWindowTitle(title) self.setWindowIcon(self.icon) self.icon_label.setPixmap(self.icon.pixmap(128, 128)) self.msg.setText(msg) self.det_msg.setPlainText(det_msg) self.det_msg.setVisible(False) self.toggle_checkbox.setVisible(False) if show_copy_button: self.ctc_button = self.bb.addButton(_('&Copy to clipboard'), self.bb.ActionRole) self.ctc_button.clicked.connect(self.copy_to_clipboard) self.show_det_msg = _('Show &details') self.hide_det_msg = _('Hide &details') self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole) self.det_msg_toggle.clicked.connect(self.toggle_det_msg) self.det_msg_toggle.setToolTip( _('Show detailed information about this error')) self.copy_action = QAction(self) self.addAction(self.copy_action) self.copy_action.setShortcuts(QKeySequence.Copy) self.copy_action.triggered.connect(self.copy_to_clipboard) self.is_question = type_ == self.QUESTION if self.is_question: self.bb.setStandardButtons(self.bb.Yes|self.bb.No) self.bb.button(self.bb.Yes if default_yes else self.bb.No ).setDefault(True) self.default_yes = default_yes if yes_text is not None: self.bb.button(self.bb.Yes).setText(yes_text) if no_text is not None: self.bb.button(self.bb.No).setText(no_text) if yes_icon is not None: self.bb.button(self.bb.Yes).setIcon(yes_icon if isinstance(yes_icon, QIcon) else QIcon(I(yes_icon))) if no_icon is not None: self.bb.button(self.bb.No).setIcon(no_icon if isinstance(no_icon, QIcon) else QIcon(I(no_icon))) else: self.bb.button(self.bb.Ok).setDefault(True) if not det_msg: self.det_msg_toggle.setVisible(False) self.resize_needed.connect(self.do_resize, type=Qt.QueuedConnection) self.do_resize()
def __init__(self, window, cat_name, tag_to_match, get_book_ids, sorter): QDialog.__init__(self, window) Ui_TagListEditor.__init__(self) self.setupUi(self) self.search_box.setMinimumContentsLength(25) # Put the category name into the title bar t = self.windowTitle() self.setWindowTitle(t + ' (' + cat_name + ')') # Remove help icon on title bar icon = self.windowIcon() self.setWindowFlags(self.windowFlags() & (~Qt.WindowContextHelpButtonHint)) self.setWindowIcon(icon) # Get saved geometry info try: self.table_column_widths = \ gprefs.get('tag_list_editor_table_widths', None) except: pass # initialization self.ordered_tags = [] self.sorter = sorter self.get_book_ids = get_book_ids # Set up the column headings self.down_arrow_icon = QIcon(I('arrow-down.png')) self.up_arrow_icon = QIcon(I('arrow-up.png')) self.blank_icon = QIcon(I('blank.png')) # Capture clicks on the horizontal header to sort the table columns hh = self.table.horizontalHeader() hh.setSectionsClickable(True) hh.sectionClicked.connect(self.header_clicked) hh.sectionResized.connect(self.table_column_resized) self.name_order = 0 self.count_order = 1 self.was_order = 1 self.table.setItemDelegate(EditColumnDelegate(self.table)) # Add the data select_item = self.fill_in_table(None, tag_to_match) # Scroll to the selected item if there is one if select_item is not None: self.table.setCurrentItem(select_item) self.delete_button.clicked.connect(self.delete_tags) self.rename_button.clicked.connect(self.rename_tag) self.undo_button.clicked.connect(self.undo_edit) self.table.itemDoubleClicked.connect(self._rename_tag) self.table.itemChanged.connect(self.finish_editing) self.buttonBox.button(QDialogButtonBox.Ok).setText(_('&OK')) self.buttonBox.button(QDialogButtonBox.Cancel).setText(_('&Cancel')) self.buttonBox.accepted.connect(self.accepted) self.search_box.initialize('tag_list_search_box_' + cat_name) self.search_button.clicked.connect(self.all_matching_clicked) self.search_button.setDefault(True) self.apply_vl_checkbox.clicked.connect(self.vl_box_changed) self.table.setEditTriggers(QTableWidget.EditKeyPressed) try: geom = gprefs.get('tag_list_editor_dialog_geometry', None) if geom is not None: self.restoreGeometry(QByteArray(geom)) else: self.resize(self.sizeHint() + QSize(150, 100)) except: pass
def initialize(self, library_path, db, listener, actions, show_gui=True): opts = self.opts self.preferences_action, self.quit_action = actions self.library_path = library_path self.content_server = None self._spare_pool = None self.must_restart_before_config = False self.listener = Listener(listener) self.check_messages_timer = QTimer() self.check_messages_timer.timeout.connect(self.another_instance_wants_to_talk) self.check_messages_timer.start(1000) for ac in self.iactions.values(): try: ac.do_genesis() except Exception: # Ignore errors in third party plugins import traceback traceback.print_exc() if getattr(ac, 'plugin_path', None) is None: raise self.donate_action = QAction(QIcon(I('donate.png')), _('&Donate to support calibre'), self) for st in self.istores.values(): st.do_genesis() MainWindowMixin.init_main_window_mixin(self, db) # Jobs Button {{{ self.job_manager = JobManager() self.jobs_dialog = JobsDialog(self, self.job_manager) self.jobs_button = JobsButton(horizontal=True, parent=self) self.jobs_button.initialize(self.jobs_dialog, self.job_manager) # }}} LayoutMixin.init_layout_mixin(self) DeviceMixin.init_device_mixin(self) self.progress_indicator = ProgressIndicator(self) self.progress_indicator.pos = (0, 20) self.verbose = opts.verbose self.get_metadata = GetMetadata() self.upload_memory = {} self.metadata_dialogs = [] self.default_thumbnail = None self.tb_wrapper = textwrap.TextWrapper(width=40) self.viewers = collections.deque() self.system_tray_icon = None if config['systray_icon']: self.system_tray_icon = factory(app_id='com.calibre-ebook.gui').create_system_tray_icon(parent=self, title='calibre') if self.system_tray_icon is not None: self.system_tray_icon.setIcon(QIcon(I('lt.png'))) if not (iswindows or isosx): self.system_tray_icon.setIcon(QIcon.fromTheme('calibre-gui', QIcon(I('lt.png')))) self.system_tray_icon.setToolTip(self.jobs_button.tray_tooltip()) self.system_tray_icon.setVisible(True) self.jobs_button.tray_tooltip_updated.connect(self.system_tray_icon.setToolTip) elif config['systray_icon']: prints('Failed to create system tray icon, your desktop environment probably does not support the StatusNotifier spec') self.system_tray_menu = QMenu(self) self.toggle_to_tray_action = self.system_tray_menu.addAction(QIcon(I('page.png')), '') self.toggle_to_tray_action.triggered.connect(self.system_tray_icon_activated) self.system_tray_menu.addAction(self.donate_action) self.donate_button.clicked.connect(self.donate_action.trigger) self.donate_button.setToolTip(self.donate_action.text().replace('&', '')) self.donate_button.setIcon(self.donate_action.icon()) self.donate_button.setStatusTip(self.donate_button.toolTip()) self.eject_action = self.system_tray_menu.addAction( QIcon(I('eject.png')), _('&Eject connected device')) self.eject_action.setEnabled(False) self.addAction(self.quit_action) self.system_tray_menu.addAction(self.quit_action) self.keyboard.register_shortcut('quit calibre', _('Quit calibre'), default_keys=('Ctrl+Q',), action=self.quit_action) if self.system_tray_icon is not None: self.system_tray_icon.setContextMenu(self.system_tray_menu) self.system_tray_icon.activated.connect(self.system_tray_icon_activated) self.quit_action.triggered[bool].connect(self.quit) self.donate_action.triggered[bool].connect(self.donate) self.minimize_action = QAction(_('Minimize the calibre window'), self) self.addAction(self.minimize_action) self.keyboard.register_shortcut('minimize calibre', self.minimize_action.text(), default_keys=(), action=self.minimize_action) self.minimize_action.triggered.connect(self.showMinimized) self.esc_action = QAction(self) self.addAction(self.esc_action) self.keyboard.register_shortcut('clear current search', _('Clear the current search'), default_keys=('Esc',), action=self.esc_action) self.esc_action.triggered.connect(self.esc) self.shift_esc_action = QAction(self) self.addAction(self.shift_esc_action) self.keyboard.register_shortcut('focus book list', _('Focus the book list'), default_keys=('Shift+Esc',), action=self.shift_esc_action) self.shift_esc_action.triggered.connect(self.shift_esc) self.ctrl_esc_action = QAction(self) self.addAction(self.ctrl_esc_action) self.keyboard.register_shortcut('clear virtual library', _('Clear the virtual library'), default_keys=('Ctrl+Esc',), action=self.ctrl_esc_action) self.ctrl_esc_action.triggered.connect(self.ctrl_esc) self.alt_esc_action = QAction(self) self.addAction(self.alt_esc_action) self.keyboard.register_shortcut('clear additional restriction', _('Clear the additional restriction'), default_keys=('Alt+Esc',), action=self.alt_esc_action) self.alt_esc_action.triggered.connect(self.clear_additional_restriction) # ###################### Start spare job server ######################## QTimer.singleShot(1000, self.create_spare_pool) # ###################### Location Manager ######################## self.location_manager.location_selected.connect(self.location_selected) self.location_manager.unmount_device.connect(self.device_manager.umount_device) self.location_manager.configure_device.connect(self.configure_connected_device) self.location_manager.update_device_metadata.connect(self.update_metadata_on_device) self.eject_action.triggered.connect(self.device_manager.umount_device) # ################### Update notification ################### UpdateMixin.init_update_mixin(self, opts) # ###################### Search boxes ######################## SearchRestrictionMixin.init_search_restriction_mixin(self) SavedSearchBoxMixin.init_saved_seach_box_mixin(self) # ###################### Library view ######################## LibraryViewMixin.init_library_view_mixin(self, db) SearchBoxMixin.init_search_box_mixin(self) # Requires current_db if show_gui: self.show() if self.system_tray_icon is not None and self.system_tray_icon.isVisible() and opts.start_in_tray: self.hide_windows() self.library_view.model().count_changed_signal.connect( self.iactions['Choose Library'].count_changed) if not gprefs.get('quick_start_guide_added', False): try: add_quick_start_guide(self.library_view) except: import traceback traceback.print_exc() for view in ('library', 'memory', 'card_a', 'card_b'): v = getattr(self, '%s_view' % view) v.selectionModel().selectionChanged.connect(self.update_status_bar) v.model().count_changed_signal.connect(self.update_status_bar) self.library_view.model().count_changed() self.bars_manager.database_changed(self.library_view.model().db) self.library_view.model().database_changed.connect(self.bars_manager.database_changed, type=Qt.QueuedConnection) # ########################## Tags Browser ############################## TagBrowserMixin.init_tag_browser_mixin(self, db) # ######################## Search Restriction ########################## if db.prefs['virtual_lib_on_startup']: self.apply_virtual_library(db.prefs['virtual_lib_on_startup']) self.rebuild_vl_tabs() # ########################## Cover Flow ################################ CoverFlowMixin.init_cover_flow_mixin(self) self._calculated_available_height = min(max_available_height()-15, self.height()) self.resize(self.width(), self._calculated_available_height) self.build_context_menus() for ac in self.iactions.values(): try: ac.gui_layout_complete() except: import traceback traceback.print_exc() if ac.plugin_path is None: raise if config['autolaunch_server']: self.start_content_server() self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection) self.read_settings() self.finalize_layout() if self.bars_manager.showing_donate: self.donate_button.start_animation() self.set_window_title() for ac in self.iactions.values(): try: ac.initialization_complete() except: import traceback traceback.print_exc() if ac.plugin_path is None: raise self.set_current_library_information(current_library_name(), db.library_id, db.field_metadata) register_keyboard_shortcuts() self.keyboard.finalize() self.auto_adder = AutoAdder(gprefs['auto_add_path'], self) self.save_layout_state() # Collect cycles now gc.collect() if show_gui and self.gui_debug is not None: QTimer.singleShot(10, self.show_gui_debug_msg) self.iactions['Connect Share'].check_smartdevice_menus() QTimer.singleShot(1, self.start_smartdevice) QTimer.singleShot(100, self.update_toggle_to_tray_action)
def main(args=sys.argv): # Ensure viewer can continue to function if GUI is closed os.environ.pop('CALIBRE_WORKER_TEMP_DIR', None) reset_base_dir() scheme = QWebEngineUrlScheme(FAKE_PROTOCOL.encode('ascii')) scheme.setSyntax(QWebEngineUrlScheme.Syntax.Host) scheme.setFlags(QWebEngineUrlScheme.SecureScheme) QWebEngineUrlScheme.registerScheme(scheme) override = 'calibre-ebook-viewer' if islinux else None app = Application(args, override_program_name=override, color_prefs=vprefs, windows_app_uid=VIEWER_APP_UID) parser = option_parser() opts, args = parser.parse_args(args) if opts.open_at and not (opts.open_at.startswith('toc:') or opts.open_at.startswith('epubcfi(/')): raise SystemExit('Not a valid --open-at value: {}'.format( opts.open_at)) listener = None if vprefs['singleinstance']: try: listener = ensure_single_instance(args, opts.open_at) except Exception as e: import traceback error_dialog(None, _('Failed to start viewer'), as_unicode(e), det_msg=traceback.format_exc(), show=True) raise SystemExit(1) acc = EventAccumulator(app) app.file_event_hook = acc app.load_builtin_fonts() app.setWindowIcon(QIcon(I('viewer.png'))) migrate_previous_viewer_prefs() main = EbookViewer(open_at=opts.open_at, continue_reading=opts.continue_reading) main.set_exception_handler() if len(args) > 1: acc.events.append(args[-1]) acc.got_file.connect(main.handle_commandline_arg) main.show() main.msg_from_anotherinstance.connect(main.another_instance_wants_to_talk, type=Qt.QueuedConnection) if listener is not None: t = Thread(name='ConnListener', target=listen, args=(listener, main.msg_from_anotherinstance)) t.daemon = True t.start() QTimer.singleShot(0, acc.flush) if opts.raise_window: main.raise_() if opts.full_screen: main.set_full_screen(True) app.exec_() if listener is not None: listener.close()
class JobError(QDialog): # {{{ WIDTH = 600 do_pop = pyqtSignal() def __init__(self, parent): QDialog.__init__(self, parent) self.setAttribute(Qt.WA_DeleteOnClose, False) self.queue = [] self.do_pop.connect(self.pop, type=Qt.QueuedConnection) self._layout = l = QGridLayout() self.setLayout(l) self.icon = QIcon(I('dialog_error.png')) self.setWindowIcon(self.icon) self.icon_label = QLabel() self.icon_label.setPixmap(self.icon.pixmap(68, 68)) self.icon_label.setMaximumSize(QSize(68, 68)) self.msg_label = QLabel('<p> ') self.msg_label.setStyleSheet('QLabel { margin-top: 1ex; }') self.msg_label.setWordWrap(True) self.msg_label.setTextFormat(Qt.RichText) self.det_msg = QPlainTextEdit(self) self.det_msg.setVisible(False) self.bb = QDialogButtonBox(QDialogButtonBox.Close, parent=self) self.bb.accepted.connect(self.accept) self.bb.rejected.connect(self.reject) self.ctc_button = self.bb.addButton(_('&Copy to clipboard'), self.bb.ActionRole) self.ctc_button.clicked.connect(self.copy_to_clipboard) self.retry_button = self.bb.addButton(_('&Retry'), self.bb.ActionRole) self.retry_button.clicked.connect(self.retry) self.retry_func = None self.show_det_msg = _('Show &details') self.hide_det_msg = _('Hide &details') self.det_msg_toggle = self.bb.addButton(self.show_det_msg, self.bb.ActionRole) self.det_msg_toggle.clicked.connect(self.toggle_det_msg) self.det_msg_toggle.setToolTip( _('Show detailed information about this error')) self.suppress = QCheckBox(self) l.addWidget(self.icon_label, 0, 0, 1, 1) l.addWidget(self.msg_label, 0, 1, 1, 1) l.addWidget(self.det_msg, 1, 0, 1, 2) l.addWidget(self.suppress, 2, 0, 1, 2, Qt.AlignLeft | Qt.AlignBottom) l.addWidget(self.bb, 3, 0, 1, 2, Qt.AlignRight | Qt.AlignBottom) l.setColumnStretch(1, 100) self.setModal(False) self.suppress.setVisible(False) self.do_resize() def retry(self): if self.retry_func is not None: self.accept() self.retry_func() def update_suppress_state(self): self.suppress.setText( _('Hide the remaining %d error messages' % len(self.queue))) self.suppress.setVisible(len(self.queue) > 3) self.do_resize() def copy_to_clipboard(self, *args): d = QTextDocument() d.setHtml(self.msg_label.text()) QApplication.clipboard().setText( u'calibre, version %s (%s, embedded-python: %s)\n%s: %s\n\n%s' % (__version__, sys.platform, isfrozen, unicode(self.windowTitle()), unicode(d.toPlainText()), unicode(self.det_msg.toPlainText()))) if hasattr(self, 'ctc_button'): self.ctc_button.setText(_('Copied')) def toggle_det_msg(self, *args): vis = unicode(self.det_msg_toggle.text()) == self.hide_det_msg self.det_msg_toggle.setText( self.show_det_msg if vis else self.hide_det_msg) self.det_msg.setVisible(not vis) self.do_resize() def do_resize(self): h = self.sizeHint().height() self.setMinimumHeight(0) # Needed as this gets set if det_msg is shown # Needed otherwise re-showing the box after showing det_msg causes the box # to not reduce in height self.setMaximumHeight(h) self.resize(QSize(self.WIDTH, h)) def showEvent(self, ev): ret = QDialog.showEvent(self, ev) self.bb.button(self.bb.Close).setFocus(Qt.OtherFocusReason) return ret def show_error(self, title, msg, det_msg=u'', retry_func=None): self.queue.append((title, msg, det_msg, retry_func)) self.update_suppress_state() self.pop() def pop(self): if not self.queue or self.isVisible(): return title, msg, det_msg, retry_func = self.queue.pop(0) self.setWindowTitle(title) self.msg_label.setText(msg) self.det_msg.setPlainText(det_msg) self.det_msg.setVisible(False) self.det_msg_toggle.setText(self.show_det_msg) self.det_msg_toggle.setVisible(True) self.suppress.setChecked(False) self.update_suppress_state() if not det_msg: self.det_msg_toggle.setVisible(False) self.retry_button.setVisible(retry_func is not None) self.retry_func = retry_func self.do_resize() self.show() def done(self, r): if self.suppress.isChecked(): self.queue = [] QDialog.done(self, r) self.do_pop.emit()
def ask_link(self): class Ask(QDialog): def accept(self): if self.treat_as_image.isChecked(): url = self.url.text() if url.lower().split(':', 1)[0] in ('http', 'https'): error_dialog( self, _('Remote images not supported'), _('You must download the image to your computer, URLs pointing' ' to remote images are not supported.'), show=True) return QDialog.accept(self) d = Ask(self) d.setWindowTitle(_('Create link')) l = QFormLayout() l.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow) d.setLayout(l) d.url = QLineEdit(d) d.name = QLineEdit(d) d.treat_as_image = QCheckBox(d) d.setMinimumWidth(600) d.bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) d.br = b = QPushButton(_('&Browse')) b.setIcon(QIcon(I('document_open.png'))) def cf(): filetypes = [] if d.treat_as_image.isChecked(): filetypes = [(_('Images'), 'png jpeg jpg gif'.split())] files = choose_files(d, 'select link file', _('Choose file'), filetypes, select_only_single_file=True) if files: path = files[0] d.url.setText(path) if path and os.path.exists(path): with lopen(path, 'rb') as f: q = what(f) is_image = q in {'jpeg', 'png', 'gif'} d.treat_as_image.setChecked(is_image) b.clicked.connect(cf) d.la = la = QLabel( _('Enter a URL. If you check the "Treat the URL as an image" box ' 'then the URL will be added as an image reference instead of as ' 'a link. You can also choose to create a link to a file on ' 'your computer. ' 'Note that if you create a link to a file on your computer, it ' 'will stop working if the file is moved.')) la.setWordWrap(True) la.setStyleSheet('QLabel { margin-bottom: 1.5ex }') l.setWidget(0, l.SpanningRole, la) l.addRow(_('Enter &URL:'), d.url) l.addRow(_('Treat the URL as an &image'), d.treat_as_image) l.addRow(_('Enter &name (optional):'), d.name) l.addRow(_('Choose a file on your computer:'), d.br) l.addRow(d.bb) d.bb.accepted.connect(d.accept) d.bb.rejected.connect(d.reject) d.resize(d.sizeHint()) link, name, is_image = None, None, False if d.exec_() == d.Accepted: link, name = unicode_type(d.url.text()).strip(), unicode_type( d.name.text()).strip() is_image = d.treat_as_image.isChecked() return link, name, is_image
def __init__(self, parent=None, panel_name='search'): QWidget.__init__(self, parent) self.ignore_search_type_changes = False self.l = l = QVBoxLayout(self) l.setContentsMargins(0, 0, 0, 0) h = QHBoxLayout() h.setContentsMargins(0, 0, 0, 0) l.addLayout(h) self.search_box = sb = SearchBox(self) self.panel_name = panel_name sb.initialize('viewer-{}-panel-expression'.format(panel_name)) sb.item_selected.connect(self.saved_search_selected) sb.history_saved.connect(self.history_saved) sb.cleared.connect(self.cleared) sb.lineEdit().returnPressed.connect(self.find_next) h.addWidget(sb) self.next_button = nb = QToolButton(self) h.addWidget(nb) nb.setFocusPolicy(Qt.FocusPolicy.NoFocus) nb.setIcon(QIcon(I('arrow-down.png'))) nb.clicked.connect(self.find_next) nb.setToolTip(_('Find next match')) self.prev_button = nb = QToolButton(self) h.addWidget(nb) nb.setFocusPolicy(Qt.FocusPolicy.NoFocus) nb.setIcon(QIcon(I('arrow-up.png'))) nb.clicked.connect(self.find_previous) nb.setToolTip(_('Find previous match')) h = QHBoxLayout() h.setContentsMargins(0, 0, 0, 0) l.addLayout(h) self.query_type = qt = QComboBox(self) qt.setFocusPolicy(Qt.FocusPolicy.NoFocus) qt.addItem(_('Contains'), 'normal') qt.addItem(_('Whole words'), 'word') qt.addItem(_('Regex'), 'regex') qt.setToolTip(('<p>' + _( 'Choose the type of search: <ul>' '<li><b>Contains</b> will search for the entered text anywhere.' '<li><b>Whole words</b> will search for whole words that equal the entered text.' '<li><b>Regex</b> will interpret the text as a regular expression.' ))) qt.setCurrentIndex( qt.findData( vprefs.get('viewer-{}-mode'.format(self.panel_name), 'normal') or 'normal')) qt.currentIndexChanged.connect(self.save_search_type) h.addWidget(qt) self.case_sensitive = cs = QCheckBox(_('&Case sensitive'), self) cs.setFocusPolicy(Qt.FocusPolicy.NoFocus) cs.setChecked( bool( vprefs.get('viewer-{}-case-sensitive'.format(self.panel_name), False))) cs.stateChanged.connect(self.save_search_type) h.addWidget(cs) self.return_button = rb = QToolButton(self) rb.setIcon(QIcon(I('back.png'))) rb.setToolTip(_('Go back to where you were before searching')) rb.clicked.connect(self.go_back) h.addWidget(rb)
def initialize(self, library_path, db, listener, actions, show_gui=True): opts = self.opts self.preferences_action, self.quit_action = actions self.library_path = library_path self.content_server = None self._spare_pool = None self.must_restart_before_config = False self.listener = Listener(listener) self.check_messages_timer = QTimer() self.check_messages_timer.timeout.connect(self.another_instance_wants_to_talk) self.check_messages_timer.start(1000) for ac in self.iactions.values(): try: ac.do_genesis() except Exception: # Ignore errors in third party plugins import traceback traceback.print_exc() if getattr(ac, 'plugin_path', None) is None: raise self.donate_action = QAction(QIcon(I('donate.png')), _('&Donate to support calibre'), self) for st in self.istores.values(): st.do_genesis() MainWindowMixin.init_main_window_mixin(self, db) # Jobs Button {{{ self.job_manager = JobManager() self.jobs_dialog = JobsDialog(self, self.job_manager) self.jobs_button = JobsButton(horizontal=True, parent=self) self.jobs_button.initialize(self.jobs_dialog, self.job_manager) # }}} LayoutMixin.init_layout_mixin(self) DeviceMixin.init_device_mixin(self) self.progress_indicator = ProgressIndicator(self) self.progress_indicator.pos = (0, 20) self.verbose = opts.verbose self.get_metadata = GetMetadata() self.upload_memory = {} self.metadata_dialogs = [] self.default_thumbnail = None self.tb_wrapper = textwrap.TextWrapper(width=40) self.viewers = collections.deque() self.system_tray_icon = None if config['systray_icon']: self.system_tray_icon = factory(app_id='com.calibre-ebook.gui').create_system_tray_icon(parent=self, title='calibre') if self.system_tray_icon is not None: self.system_tray_icon.setIcon(QIcon(I('lt.png'))) if not (iswindows or isosx): self.system_tray_icon.setIcon(QIcon.fromTheme('calibre-gui', QIcon(I('lt.png')))) self.system_tray_icon.setToolTip(self.jobs_button.tray_tooltip()) self.system_tray_icon.setVisible(True) self.jobs_button.tray_tooltip_updated.connect(self.system_tray_icon.setToolTip) elif config['systray_icon']: prints('Failed to create system tray icon, your desktop environment probably does not support the StatusNotifier spec') self.system_tray_menu = QMenu(self) self.toggle_to_tray_action = self.system_tray_menu.addAction(QIcon(I('page.png')), '') self.toggle_to_tray_action.triggered.connect(self.system_tray_icon_activated) self.system_tray_menu.addAction(self.donate_action) self.donate_button.clicked.connect(self.donate_action.trigger) self.donate_button.setToolTip(self.donate_action.text().replace('&', '')) self.donate_button.setIcon(self.donate_action.icon()) self.donate_button.setStatusTip(self.donate_button.toolTip()) self.eject_action = self.system_tray_menu.addAction( QIcon(I('eject.png')), _('&Eject connected device')) self.eject_action.setEnabled(False) self.addAction(self.quit_action) self.system_tray_menu.addAction(self.quit_action) self.keyboard.register_shortcut('quit calibre', _('Quit calibre'), default_keys=('Ctrl+Q',), action=self.quit_action) if self.system_tray_icon is not None: self.system_tray_icon.setContextMenu(self.system_tray_menu) self.system_tray_icon.activated.connect(self.system_tray_icon_activated) self.quit_action.triggered[bool].connect(self.quit) self.donate_action.triggered[bool].connect(self.donate) self.minimize_action = QAction(_('Minimize the calibre window'), self) self.addAction(self.minimize_action) self.keyboard.register_shortcut('minimize calibre', self.minimize_action.text(), default_keys=(), action=self.minimize_action) self.minimize_action.triggered.connect(self.showMinimized) self.esc_action = QAction(self) self.addAction(self.esc_action) self.keyboard.register_shortcut('clear current search', _('Clear the current search'), default_keys=('Esc',), action=self.esc_action) self.esc_action.triggered.connect(self.esc) self.shift_esc_action = QAction(self) self.addAction(self.shift_esc_action) self.keyboard.register_shortcut('focus book list', _('Focus the book list'), default_keys=('Shift+Esc',), action=self.shift_esc_action) self.shift_esc_action.triggered.connect(self.shift_esc) self.ctrl_esc_action = QAction(self) self.addAction(self.ctrl_esc_action) self.keyboard.register_shortcut('clear virtual library', _('Clear the virtual library'), default_keys=('Ctrl+Esc',), action=self.ctrl_esc_action) self.ctrl_esc_action.triggered.connect(self.ctrl_esc) self.alt_esc_action = QAction(self) self.addAction(self.alt_esc_action) self.keyboard.register_shortcut('clear additional restriction', _('Clear the additional restriction'), default_keys=('Alt+Esc',), action=self.alt_esc_action) self.alt_esc_action.triggered.connect(self.clear_additional_restriction) # ###################### Start spare job server ######################## QTimer.singleShot(1000, self.create_spare_pool) # ###################### Location Manager ######################## self.location_manager.location_selected.connect(self.location_selected) self.location_manager.unmount_device.connect(self.device_manager.umount_device) self.location_manager.configure_device.connect(self.configure_connected_device) self.location_manager.update_device_metadata.connect(self.update_metadata_on_device) self.eject_action.triggered.connect(self.device_manager.umount_device) # ################### Update notification ################### UpdateMixin.init_update_mixin(self, opts) # ###################### Search boxes ######################## SearchRestrictionMixin.init_search_restirction_mixin(self) SavedSearchBoxMixin.init_saved_seach_box_mixin(self) # ###################### Library view ######################## LibraryViewMixin.init_library_view_mixin(self, db) SearchBoxMixin.init_search_box_mixin(self) # Requires current_db if show_gui: self.show() if self.system_tray_icon is not None and self.system_tray_icon.isVisible() and opts.start_in_tray: self.hide_windows() self.library_view.model().count_changed_signal.connect( self.iactions['Choose Library'].count_changed) if not gprefs.get('quick_start_guide_added', False): try: add_quick_start_guide(self.library_view) except: import traceback traceback.print_exc() for view in ('library', 'memory', 'card_a', 'card_b'): v = getattr(self, '%s_view' % view) v.selectionModel().selectionChanged.connect(self.update_status_bar) v.model().count_changed_signal.connect(self.update_status_bar) self.library_view.model().count_changed() self.bars_manager.database_changed(self.library_view.model().db) self.library_view.model().database_changed.connect(self.bars_manager.database_changed, type=Qt.QueuedConnection) # ########################## Tags Browser ############################## TagBrowserMixin.init_tag_browser_mixin(self, db) # ######################## Search Restriction ########################## if db.prefs['virtual_lib_on_startup']: self.apply_virtual_library(db.prefs['virtual_lib_on_startup']) self.rebuild_vl_tabs() # ########################## Cover Flow ################################ CoverFlowMixin.init_cover_flow_mixin(self) self._calculated_available_height = min(max_available_height()-15, self.height()) self.resize(self.width(), self._calculated_available_height) self.build_context_menus() for ac in self.iactions.values(): try: ac.gui_layout_complete() except: import traceback traceback.print_exc() if ac.plugin_path is None: raise if config['autolaunch_server']: self.start_content_server() self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection) self.read_settings() self.finalize_layout() if self.bars_manager.showing_donate: self.donate_button.start_animation() self.set_window_title() for ac in self.iactions.values(): try: ac.initialization_complete() except: import traceback traceback.print_exc() if ac.plugin_path is None: raise self.set_current_library_information(current_library_name(), db.library_id, db.field_metadata) register_keyboard_shortcuts() self.keyboard.finalize() self.auto_adder = AutoAdder(gprefs['auto_add_path'], self) self.save_layout_state() # Collect cycles now gc.collect() if show_gui and self.gui_debug is not None: QTimer.singleShot(10, self.show_gui_debug_msg) self.iactions['Connect Share'].check_smartdevice_menus() QTimer.singleShot(1, self.start_smartdevice) QTimer.singleShot(100, self.update_toggle_to_tray_action)