def check_key_modifier(which_modifier): v = int(QApplication.keyboardModifiers() & (Qt.KeyboardModifier.ControlModifier + Qt.KeyboardModifier.ShiftModifier)) return v == which_modifier
# Probably the user deleted the files, in any case, failing # to delete the book is not catastrophic traceback.print_exc() def email_news(self, id_): mi = self.library_view.model().db.get_metadata(id_, index_is_id=True) remove = [id_] if config['delete_news_from_library_on_upload'] \ else [] def get_fmts(fmts): files, auto = self.library_view.model().\ get_preferred_formats_from_ids([id_], fmts, set_metadata=True, use_plugboard=plugboard_email_value, plugboard_formats=plugboard_email_formats) return files sent_mails = email_news(mi, remove, get_fmts, self.email_sent, self.job_manager) if sent_mails: self.status_bar.show_message( _('Sent news to') + ' ' + ', '.join(sent_mails), 3000) # }}} if __name__ == '__main__': from qt.core import QApplication app = QApplication([]) # noqa print(select_recipients())
def rehighlight(self): QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) super().rehighlight() QApplication.restoreOverrideCursor()
def __init__(self, recipe_model, parent=None): QDialog.__init__(self, parent) self.commit_on_change = True self.previous_urn = None self.setWindowIcon(QIcon(I('scheduler.png'))) self.l = l = QGridLayout(self) # Left panel self.h = h = QHBoxLayout() l.addLayout(h, 0, 0, 1, 1) self.search = s = SearchBox2(self) self.search.initialize('scheduler_search_history') self.search.setMinimumContentsLength(15) self.go_button = b = QToolButton(self) b.setText(_("Go")) b.clicked.connect(self.search.do_search) h.addWidget(s), h.addWidget(b) self.recipes = RecipesView(self) l.addWidget(self.recipes, 1, 0, 2, 1) self.recipe_model = recipe_model self.recipe_model.do_refresh() self.recipes.setModel(self.recipe_model) self.recipes.setFocus(Qt.FocusReason.OtherFocusReason) self.recipes.item_activated.connect(self.download_clicked) self.setWindowTitle( _("Schedule news download [{} sources]").format( self.recipe_model.showing_count)) self.search.search.connect(self.recipe_model.search) self.recipe_model.searched.connect( self.search.search_done, type=Qt.ConnectionType.QueuedConnection) self.recipe_model.searched.connect(self.search_done) # Right Panel self.scroll_area_contents = sac = QWidget(self) self.l.addWidget(sac, 0, 1, 2, 1) sac.v = v = QVBoxLayout(sac) v.setContentsMargins(0, 0, 0, 0) self.detail_box = QTabWidget(self) self.detail_box.setVisible(False) self.detail_box.setCurrentIndex(0) v.addWidget(self.detail_box) v.addItem( QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)) # First Tab (scheduling) self.tab = QWidget() self.detail_box.addTab(self.tab, _("&Schedule")) self.tab.v = vt = QVBoxLayout(self.tab) vt.setContentsMargins(0, 0, 0, 0) self.blurb = la = QLabel('blurb') la.setWordWrap(True), la.setOpenExternalLinks(True) vt.addWidget(la) self.frame = f = QFrame(self.tab) vt.addWidget(f) f.setFrameShape(QFrame.Shape.StyledPanel) f.setFrameShadow(QFrame.Shadow.Raised) f.v = vf = QVBoxLayout(f) self.schedule = s = QCheckBox(_("&Schedule for download:"), f) self.schedule.stateChanged[int].connect(self.toggle_schedule_info) vf.addWidget(s) f.h = h = QHBoxLayout() vf.addLayout(h) self.days_of_week = QRadioButton(_("&Days of week"), f) self.days_of_month = QRadioButton(_("Da&ys of month"), f) self.every_x_days = QRadioButton(_("Every &x days"), f) self.days_of_week.setChecked(True) h.addWidget(self.days_of_week), h.addWidget( self.days_of_month), h.addWidget(self.every_x_days) self.schedule_stack = ss = QStackedWidget(f) self.schedule_widgets = [] for key in reversed(self.SCHEDULE_TYPES): self.schedule_widgets.insert(0, self.SCHEDULE_TYPES[key](self)) self.schedule_stack.insertWidget(0, self.schedule_widgets[0]) vf.addWidget(ss) self.last_downloaded = la = QLabel(f) la.setWordWrap(True) vf.addWidget(la) self.account = acc = QGroupBox(self.tab) acc.setTitle(_("&Account")) vt.addWidget(acc) acc.g = g = QGridLayout(acc) acc.unla = la = QLabel(_("&Username:"******"&Password:"******"&Show password"), self.account) spw.stateChanged[int].connect(self.set_pw_echo_mode) g.addWidget(spw, 2, 0, 1, 2) self.rla = la = QLabel( _("For the scheduling to work, you must leave calibre running.")) vt.addWidget(la) for b, c in iteritems(self.SCHEDULE_TYPES): b = getattr(self, b) b.toggled.connect(self.schedule_type_selected) b.setToolTip(textwrap.dedent(c.HELP)) # Second tab (advanced settings) self.tab2 = t2 = QWidget() self.detail_box.addTab(self.tab2, _("&Advanced")) self.tab2.g = g = QGridLayout(t2) g.setContentsMargins(0, 0, 0, 0) self.add_title_tag = tt = QCheckBox(_("Add &title as tag"), t2) g.addWidget(tt, 0, 0, 1, 2) t2.la = la = QLabel(_("&Extra tags:")) self.custom_tags = ct = QLineEdit(self) la.setBuddy(ct) g.addWidget(la), g.addWidget(ct, 1, 1) t2.la2 = la = QLabel(_("&Keep at most:")) la.setToolTip( _("Maximum number of copies (issues) of this recipe to keep. Set to 0 to keep all (disable)." )) self.keep_issues = ki = QSpinBox(t2) tt.toggled['bool'].connect(self.keep_issues.setEnabled) ki.setMaximum(100000), la.setBuddy(ki) ki.setToolTip( _("<p>When set, this option will cause calibre to keep, at most, the specified number of issues" " of this periodical. Every time a new issue is downloaded, the oldest one is deleted, if the" " total is larger than this number.\n<p>Note that this feature only works if you have the" " option to add the title as tag checked, above.\n<p>Also, the setting for deleting periodicals" " older than a number of days, below, takes priority over this setting." )) ki.setSpecialValueText(_("all issues")), ki.setSuffix(_(" issues")) g.addWidget(la), g.addWidget(ki, 2, 1) si = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) g.addItem(si, 3, 1, 1, 1) # Bottom area self.hb = h = QHBoxLayout() self.l.addLayout(h, 2, 1, 1, 1) self.labt = la = QLabel(_("Delete downloaded &news older than:")) self.old_news = on = QSpinBox(self) on.setToolTip( _("<p>Delete downloaded news older than the specified number of days. Set to zero to disable.\n" "<p>You can also control the maximum number of issues of a specific periodical that are kept" " by clicking the Advanced tab for that periodical above.")) on.setSpecialValueText(_("never delete")), on.setSuffix(_(" days")) on.setMaximum(1000), la.setBuddy(on) on.setValue(gconf['oldest_news']) h.addWidget(la), h.addWidget(on) self.download_all_button = b = QPushButton( QIcon(I('news.png')), _("Download &all scheduled"), self) b.setToolTip(_("Download all scheduled news sources at once")) b.clicked.connect(self.download_all_clicked) self.l.addWidget(b, 3, 0, 1, 1) self.bb = bb = QDialogButtonBox( QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel, self) bb.accepted.connect(self.accept), bb.rejected.connect(self.reject) self.download_button = b = bb.addButton( _('&Download now'), QDialogButtonBox.ButtonRole.ActionRole) b.setIcon(QIcon(I('arrow-down.png'))), b.setVisible(False) b.clicked.connect(self.download_clicked) self.l.addWidget(bb, 3, 1, 1, 1) geom = gprefs.get('scheduler_dialog_geometry') if geom is not None: QApplication.instance().safe_restore_geometry(self, geom)
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.WindowType.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.CheckState.Checked if gprefs['qv_respects_vls'] else Qt. CheckState.Unchecked) self.apply_vls.stateChanged.connect(self.vl_box_changed) self.fm = self.db.field_metadata self.items.setSelectionMode( QAbstractItemView.SelectionMode.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.ContextMenuPolicy.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.SelectionBehavior.SelectRows) self.books_table.setSelectionMode( QAbstractItemView.SelectionMode.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.SortOrder.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.ContextMenuPolicy.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 build_item_context_menu(self, item): m = QMenu(self) sel = self.selectedItems() num = len(sel) container = current_container() ci = self.currentItem() if ci is not None: cn = str(ci.data(0, NAME_ROLE) or '') mt = str(ci.data(0, MIME_ROLE) or '') cat = str(ci.data(0, CATEGORY_ROLE) or '') n = elided_text(cn.rpartition('/')[-1]) m.addAction(QIcon(I('save.png')), _('Export %s') % n, partial(self.export, cn)) if cn not in container.names_that_must_not_be_changed and cn not in container.names_that_must_not_be_removed and mt not in OEB_FONTS: m.addAction(_('Replace %s with file...') % n, partial(self.replace, cn)) if num > 1: m.addAction(QIcon(I('save.png')), _('Export all %d selected files') % num, self.export_selected) if cn not in container.names_that_must_not_be_changed: self.add_open_with_actions(m, cn) m.addSeparator() m.addAction(QIcon(I('modified.png')), _('&Rename %s') % n, self.edit_current_item) if is_raster_image(mt): m.addAction(QIcon(I('default_cover.png')), _('Mark %s as cover image') % n, partial(self.mark_as_cover, cn)) elif current_container().SUPPORTS_TITLEPAGES and mt in OEB_DOCS and cat == 'text': m.addAction(QIcon(I('default_cover.png')), _('Mark %s as cover page') % n, partial(self.mark_as_titlepage, cn)) m.addSeparator() if num > 0: m.addSeparator() if num > 1: m.addAction(QIcon(I('modified.png')), _('&Bulk rename the selected files'), self.request_bulk_rename) m.addAction(QIcon(I('modified.png')), _('Change the file extension for the selected files'), self.request_change_ext) m.addAction(QIcon(I('trash.png')), ngettext( '&Delete the selected file', '&Delete the {} selected files', num).format(num), self.request_delete) m.addAction(QIcon(I('edit-copy.png')), ngettext( '&Copy the selected file to another editor instance', '&Copy the {} selected files to another editor instance', num).format(num), self.copy_selected_files) m.addSeparator() md = QApplication.instance().clipboard().mimeData() if md.hasUrls() and md.hasFormat(FILE_COPY_MIME): import json name_map = json.loads(bytes(md.data(FILE_COPY_MIME))) m.addAction(ngettext( _('Paste file from other editor instance'), _('Paste {} files from other editor instance'), len(name_map)).format(len(name_map)), self.paste_from_other_instance) selected_map = defaultdict(list) for item in sel: selected_map[str(item.data(0, CATEGORY_ROLE) or '')].append(str(item.data(0, NAME_ROLE) or '')) for items in selected_map.values(): items.sort(key=self.index_of_name) if selected_map['text']: m.addAction(QIcon(I('format-text-color.png')), _('Link &stylesheets...'), partial(self.link_stylesheets, selected_map['text'])) if len(selected_map['text']) > 1: m.addAction(QIcon(I('merge.png')), _('&Merge selected text files'), partial(self.start_merge, 'text', selected_map['text'])) if len(selected_map['styles']) > 1: m.addAction(QIcon(I('merge.png')), _('&Merge selected style files'), partial(self.start_merge, 'styles', selected_map['styles'])) return m
def copy_to_clipboard(self): QApplication.clipboard().setText(self.text_results)
def data(self, index, role): row, col = index.row(), index.column() if row >= len(self.matches): return None result = self.matches[row] if role == Qt.ItemDataRole.DisplayRole: if col == 1: t = result.title if result.title else _('Unknown') a = result.author if result.author else '' return ('<b>%s</b><br><i>%s</i>' % (t, a)) elif col == 2: return (result.price) elif col == 4: return ('<span>%s<br>%s</span>' % (result.store_name, result.formats)) return None elif role == Qt.ItemDataRole.DecorationRole: if col == 0 and result.cover_data: p = QPixmap() p.loadFromData(result.cover_data) p.setDevicePixelRatio(QApplication.instance().devicePixelRatio()) return p if col == 3: if result.drm == SearchResult.DRM_LOCKED: return (self.DRM_LOCKED_ICON) elif result.drm == SearchResult.DRM_UNLOCKED: return (self.DRM_UNLOCKED_ICON) elif result.drm == SearchResult.DRM_UNKNOWN: return (self.DRM_UNKNOWN_ICON) if col == 5: if result.downloads: return (self.DOWNLOAD_ICON) if col == 6: if result.affiliate: return (self.DONATE_ICON) elif role == Qt.ItemDataRole.ToolTipRole: if col == 1: return ('<p>%s</p>' % result.title) elif col == 2: if result.price: return ('<p>' + _( 'Detected price as: %s. Check with the store before making a purchase' ' to verify this price is correct. This price often does not include' ' promotions the store may be running.') % result.price + '</p>') return '<p>' + _( 'No price was found') elif col == 3: if result.drm == SearchResult.DRM_LOCKED: return ('<p>' + _('This book as been detected as having DRM restrictions. This book may not work with your reader and you will have limitations placed upon you as to what you can do with this book. Check with the store before making any purchases to ensure you can actually read this book.') + '</p>') # noqa elif result.drm == SearchResult.DRM_UNLOCKED: return ('<p>' + _('This book has been detected as being DRM Free. You should be able to use this book on any device provided it is in a format calibre supports for conversion. However, before making a purchase double check the DRM status with the store. The store may not be disclosing the use of DRM.') + '</p>') # noqa else: return ('<p>' + _('The DRM status of this book could not be determined. There is a very high likelihood that this book is actually DRM restricted.') + '</p>') # noqa elif col == 4: return ('<p>%s</p>' % result.formats) elif col == 5: if result.downloads: return ('<p>' + _('The following formats can be downloaded directly: %s.') % ', '.join(result.downloads.keys()) + '</p>') elif col == 6: if result.affiliate: return ('<p>' + _('Buying from this store supports the calibre developer: %s.') % result.plugin_author + '</p>') elif role == Qt.ItemDataRole.SizeHintRole: return QSize(64, 64) return None
def copy_report(): text = re.sub(r'</.+?>', '\n', report) text = re.sub(r'<.+?>', '', text) cp = QApplication.instance().clipboard() cp.setText(text)
def eventFilter(self, obj, e): 'Redirect key presses from the popup to the widget' widget = self.parent() if widget is None or sip.isdeleted(widget): return False etype = e.type() if obj is not self: return QObject.eventFilter(self, obj, e) # self.debug_event(e) if etype == QEvent.Type.KeyPress: try: key = e.key() except AttributeError: return QObject.eventFilter(self, obj, e) if key == Qt.Key.Key_Escape: self.hide() e.accept() return True if key == Qt.Key.Key_F4 and e.modifiers( ) & Qt.KeyboardModifier.AltModifier: self.hide() e.accept() return True if key in (Qt.Key.Key_Enter, Qt.Key.Key_Return): # We handle this explicitly because on OS X activated() is # not emitted on pressing Enter. idx = self.currentIndex() if idx.isValid(): self.item_chosen(idx) self.hide() e.accept() return True if key == Qt.Key.Key_Tab: idx = self.currentIndex() if idx.isValid(): self.item_chosen(idx) self.hide() elif self.model().rowCount() > 0: self.next_match() e.accept() return True if key in (Qt.Key.Key_PageUp, Qt.Key.Key_PageDown): # Let the list view handle these keys return False if key in (Qt.Key.Key_Up, Qt.Key.Key_Down): self.next_match(previous=key == Qt.Key.Key_Up) e.accept() return True # Send to widget widget.eat_focus_out = False widget.keyPressEvent(e) widget.eat_focus_out = True if not widget.hasFocus(): # Widget lost focus hide the popup self.hide() if e.isAccepted(): return True elif ismacos and etype == QEvent.Type.InputMethodQuery and e.queries( ) == (Qt.InputMethodQuery.ImHints | Qt.InputMethodQuery.ImEnabled) and self.isVisible(): # In Qt 5 the Esc key causes this event and the line edit does not # handle it, which causes the parent dialog to be closed # See https://bugreports.qt-project.org/browse/QTBUG-41806 e.accept() return True elif etype == QEvent.Type.MouseButtonPress and hasattr( e, 'globalPos') and not self.rect().contains( self.mapFromGlobal(e.globalPos())): # A click outside the popup, close it if isinstance(widget, QComboBox): # This workaround is needed to ensure clicking on the drop down # arrow of the combobox closes the popup opt = QStyleOptionComboBox() widget.initStyleOption(opt) sc = widget.style().hitTestComplexControl( QStyle.ComplexControl.CC_ComboBox, opt, widget.mapFromGlobal(e.globalPos()), widget) if sc == QStyle.SubControl.SC_ComboBoxArrow: QTimer.singleShot(0, self.hide) e.accept() return True self.hide() e.accept() return True elif etype in (QEvent.Type.InputMethod, QEvent.Type.ShortcutOverride): QApplication.sendEvent(widget, e) return False
def __init__(self, parent=None): self._host_widget = None self.callback_id_counter = count() self.callback_map = {} self.current_cfi = self.current_content_file = None RestartingWebEngineView.__init__(self, parent) self.tts = TTS(self) self.tts.settings_changed.connect(self.tts_settings_changed) self.tts.event_received.connect(self.tts_event_received) self.dead_renderer_error_shown = False self.render_process_failed.connect(self.render_process_died) w = QApplication.instance().desktop().availableGeometry(self).width() QApplication.instance().palette_changed.connect(self.palette_changed) self.show_home_page_on_ready = True self._size_hint = QSize(int(w / 3), int(w / 2)) self._page = WebPage(self) self._page.linkHovered.connect(self.link_hovered) self.view_is_ready = False self.bridge.bridge_ready.connect(self.on_bridge_ready) self.bridge.view_created.connect(self.on_view_created) self.bridge.content_file_changed.connect(self.on_content_file_changed) self.bridge.set_session_data.connect(self.set_session_data) self.bridge.set_local_storage.connect(self.set_local_storage) self.bridge.reload_book.connect(self.reload_book) self.bridge.toggle_toc.connect(self.toggle_toc) self.bridge.show_search.connect(self.show_search) self.bridge.search_result_not_found.connect( self.search_result_not_found) self.bridge.search_result_discovered.connect( self.search_result_discovered) self.bridge.find_next.connect(self.find_next) self.bridge.toggle_bookmarks.connect(self.toggle_bookmarks) self.bridge.toggle_highlights.connect(self.toggle_highlights) self.bridge.new_bookmark.connect(self.new_bookmark) self.bridge.toggle_inspector.connect(self.toggle_inspector) self.bridge.toggle_lookup.connect(self.toggle_lookup) self.bridge.quit.connect(self.quit) self.bridge.update_current_toc_nodes.connect( self.update_current_toc_nodes) self.bridge.toggle_full_screen.connect(self.toggle_full_screen) self.bridge.ask_for_open.connect(self.ask_for_open) self.bridge.selection_changed.connect(self.selection_changed) self.bridge.autoscroll_state_changed.connect( self.autoscroll_state_changed) self.bridge.read_aloud_state_changed.connect( self.read_aloud_state_changed) self.bridge.view_image.connect(self.view_image) self.bridge.copy_image.connect(self.copy_image) self.bridge.overlay_visibility_changed.connect( self.overlay_visibility_changed) self.bridge.reference_mode_changed.connect(self.reference_mode_changed) self.bridge.show_loading_message.connect(self.show_loading_message) self.bridge.show_error.connect(self.show_error) self.bridge.print_book.connect(self.print_book) self.bridge.clear_history.connect(self.clear_history) self.bridge.reset_interface.connect(self.reset_interface) self.bridge.quit.connect(self.quit) self.bridge.customize_toolbar.connect(self.customize_toolbar) self.bridge.scrollbar_context_menu.connect(self.scrollbar_context_menu) self.bridge.close_prep_finished.connect(self.close_prep_finished) self.bridge.highlights_changed.connect(self.highlights_changed) self.bridge.edit_book.connect(self.edit_book) self.bridge.show_book_folder.connect(self.show_book_folder) self.bridge.open_url.connect(safe_open_url) self.bridge.speak_simple_text.connect(self.tts.speak_simple_text) self.bridge.tts.connect(self.tts.action) self.bridge.export_shortcut_map.connect(self.set_shortcut_map) self.shortcut_map = {} self.bridge.report_cfi.connect(self.call_callback) self.bridge.change_background_image.connect( self.change_background_image) self.pending_bridge_ready_actions = {} self.setPage(self._page) self.setAcceptDrops(False) self.setUrl(QUrl('{}://{}/'.format(FAKE_PROTOCOL, FAKE_HOST))) self.urlChanged.connect(self.url_changed) if parent is not None: self.inspector = Inspector( parent.inspector_dock.toggleViewAction(), self) parent.inspector_dock.setWidget(self.inspector)
def load_pixmap(self, data): pmap = QPixmap() pmap.loadFromData(data) pmap.setDevicePixelRatio(QApplication.instance().devicePixelRatio()) return pmap
def copy_to_clipboard(self): QApplication.clipboard().setText(''.join(self.log.plain_text))
def updateEditorGeometry(self, editor, option, index): if editor is None: return fm = editor.fontMetrics() # get the original size of the edit widget opt = QStyleOptionViewItem(option) self.initStyleOption(opt, index) opt.showDecorationSelected = True opt.decorationSize = QSize( 0, 0) # We want the editor to cover the decoration style = QApplication.style() initial_geometry = style.subElementRect( QStyle.SubElement.SE_ItemViewItemText, opt, None) orig_width = initial_geometry.width() # Compute the required width: the width that can show all of the current value if hasattr(self, 'get_required_width'): new_width = self.get_required_width(editor, style, fm) else: # The line edit box seems to extend by the space consumed by an 'M'. # So add that to the text text = self.displayText(index.data(Qt.ItemDataRole.DisplayRole), QLocale()) + 'M' srect = style.itemTextRect(fm, editor.geometry(), Qt.AlignmentFlag.AlignLeft, False, text) new_width = srect.width() # Now get the size of the combo/spinner arrows and add them to the needed width if isinstance(editor, (QComboBox, QDateTimeEdit)): r = style.subControlRect(QStyle.ComplexControl.CC_ComboBox, QStyleOptionComboBox(), QStyle.SubControl.SC_ComboBoxArrow, editor) new_width += r.width() elif isinstance(editor, (QSpinBox, QDoubleSpinBox)): r = style.subControlRect(QStyle.ComplexControl.CC_SpinBox, QStyleOptionSpinBox(), QStyle.SubControl.SC_SpinBoxUp, editor) new_width += r.width() # Compute the maximum we can show if we consume the entire viewport pin_view = self.table_widget.pin_view is_pin_view, p = False, editor.parent() while p is not None: if p is pin_view: is_pin_view = True break p = p.parent() if is_pin_view: max_width = pin_view.horizontalScrollBar().geometry().width() else: view = self.table_widget max_width = view.horizontalScrollBar().geometry().width( ) - view.verticalHeader().width() # What we have to display might not fit. If so, adjust down new_width = new_width if new_width < max_width else max_width # See if we need to change the editor's geometry if new_width <= orig_width: delta_x = 0 delta_width = 0 else: # Compute the space available from the left edge of the widget to # the right edge of the displayed table (the viewport) and the left # edge of the widget to the left edge of the viewport. These are # used to position the edit box space_left = initial_geometry.x() space_right = max_width - space_left if editor.layoutDirection() == Qt.LayoutDirection.RightToLeft: # If language is RtL, align to the cell's right edge if possible cw = initial_geometry.width() consume_on_left = min(space_left, new_width - cw) consume_on_right = max(0, new_width - (consume_on_left + cw)) delta_x = -consume_on_left delta_width = consume_on_right else: # If language is LtR, align to the left if possible consume_on_right = min(space_right, new_width) consume_on_left = max(0, new_width - consume_on_right) delta_x = -consume_on_left delta_width = consume_on_right - initial_geometry.width() initial_geometry.adjust(delta_x, 0, delta_width, 0) editor.setGeometry(initial_geometry)
def __enter__(self): QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
def add_copy_action(name): copy_menu.addAction( QIcon(I('edit-copy.png')), _('The text: {}').format(name), lambda: QApplication.instance().clipboard().setText(name))
def __exit__(self, *args): QApplication.restoreOverrideCursor()
def doit(): QApplication.instance().clipboard().setText(url)
self.db.set_has_cover(id, False) def fix_extra_covers(self): tl = self.top_level_items['extra_covers'] child_count = tl.childCount() for i in range(0, child_count): item = tl.child(i) id = int(item.data(0, Qt.ItemDataRole.UserRole)) self.db.set_has_cover(id, True) def fix_items(self): for check in CHECKS: attr = check[0] fixable = check[3] tl = self.top_level_items[attr] if fixable and tl.checkState(1): func = getattr(self, 'fix_' + attr, None) if func is not None and callable(func): func() self.run_the_check() def copy_to_clipboard(self): QApplication.clipboard().setText(self.text_results) if __name__ == '__main__': app = QApplication([]) from calibre.library import db d = CheckLibraryDialog(None, db()) d.exec()
def __init__(self, parent, text, mi=None, fm=None, color_field=None, icon_field_key=None, icon_rule_kind=None, doing_emblem=False, text_is_placeholder=False, dialog_is_st_editor=False, global_vars=None, all_functions=None, builtin_functions=None): QDialog.__init__(self, parent) Ui_TemplateDialog.__init__(self) self.setupUi(self) self.coloring = color_field is not None self.iconing = icon_field_key is not None self.embleming = doing_emblem self.dialog_is_st_editor = dialog_is_st_editor if global_vars is None: self.global_vars = {} else: self.global_vars = global_vars cols = [] self.fm = fm if fm is not None: for key in sorted( displayable_columns(fm), key=lambda k: sort_key(fm[k]['name'] if k != color_row_key else 0)): if key == color_row_key and not self.coloring: continue from calibre.gui2.preferences.coloring import all_columns_string name = all_columns_string if key == color_row_key else fm[key][ 'name'] if name: cols.append((name, key)) self.color_layout.setVisible(False) self.icon_layout.setVisible(False) if self.coloring: self.color_layout.setVisible(True) for n1, k1 in cols: self.colored_field.addItem( n1 + (' (' + k1 + ')' if k1 != color_row_key else ''), k1) self.colored_field.setCurrentIndex( self.colored_field.findData(color_field)) elif self.iconing or self.embleming: self.icon_layout.setVisible(True) if self.embleming: self.icon_kind_label.setVisible(False) self.icon_kind.setVisible(False) self.icon_chooser_label.setVisible(False) self.icon_field.setVisible(False) for n1, k1 in cols: self.icon_field.addItem(f'{n1} ({k1})', k1) self.icon_file_names = [] d = os.path.join(config_dir, 'cc_icons') if os.path.exists(d): for icon_file in os.listdir(d): icon_file = icu_lower(icon_file) if os.path.exists(os.path.join(d, icon_file)): if icon_file.endswith('.png'): self.icon_file_names.append(icon_file) self.icon_file_names.sort(key=sort_key) self.update_filename_box() if self.iconing: dex = 0 from calibre.gui2.preferences.coloring import icon_rule_kinds for i, tup in enumerate(icon_rule_kinds): txt, val = tup self.icon_kind.addItem(txt, userData=(val)) if val == icon_rule_kind: dex = i self.icon_kind.setCurrentIndex(dex) self.icon_field.setCurrentIndex( self.icon_field.findData(icon_field_key)) self.setup_saved_template_editor(not dialog_is_st_editor, dialog_is_st_editor) # Remove help icon on title bar icon = self.windowIcon() self.setWindowFlags(self.windowFlags() & (~Qt.WindowType.WindowContextHelpButtonHint)) self.setWindowIcon(icon) self.all_functions = all_functions if all_functions else formatter_functions( ).get_functions() self.builtins = (builtin_functions if builtin_functions else formatter_functions().get_builtins_and_aliases()) # Set up the display table self.table_column_widths = None try: self.table_column_widths = \ gprefs.get('template_editor_table_widths', None) except: pass self.set_mi(mi, fm) self.last_text = '' self.highlighter = TemplateHighlighter(self.textbox.document(), builtin_functions=self.builtins) self.textbox.cursorPositionChanged.connect(self.text_cursor_changed) self.textbox.textChanged.connect(self.textbox_changed) self.set_editor_font() self.documentation.setReadOnly(True) self.source_code.setReadOnly(True) if text is not None: if text_is_placeholder: self.textbox.setPlaceholderText(text) self.textbox.clear() text = '' else: self.textbox.setPlainText(text) else: text = '' self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText( _('&OK')) self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText( _('&Cancel')) self.color_copy_button.clicked.connect(self.color_to_clipboard) self.filename_button.clicked.connect(self.filename_button_clicked) self.icon_copy_button.clicked.connect(self.icon_to_clipboard) try: with open(P('template-functions.json'), 'rb') as f: self.builtin_source_dict = json.load(f, encoding='utf-8') except: self.builtin_source_dict = {} func_names = sorted(self.all_functions) self.function.clear() self.function.addItem('') for f in func_names: self.function.addItem( '{} -- {}'.format( f, self.function_type_string(f, longform=False)), f) self.function.setCurrentIndex(0) self.function.currentIndexChanged.connect(self.function_changed) self.rule = (None, '') tt = _('Template language tutorial') self.template_tutorial.setText('<a href="{}">{}</a>'.format( localize_user_manual_link( 'https://manual.calibre-ebook.com/template_lang.html'), tt)) tt = _('Template function reference') self.template_func_reference.setText('<a href="{}">{}</a>'.format( localize_user_manual_link( 'https://manual.calibre-ebook.com/generated/en/template_ref.html' ), tt)) s = gprefs.get('template_editor_break_on_print', False) self.go_button.setEnabled(s) self.remove_all_button.setEnabled(s) self.set_all_button.setEnabled(s) self.toggle_button.setEnabled(s) self.breakpoint_line_box.setEnabled(s) self.breakpoint_line_box_label.setEnabled(s) self.break_box.setChecked(s) self.break_box.stateChanged.connect(self.break_box_changed) self.go_button.clicked.connect(self.go_button_pressed) self.textbox.setFocus() self.set_up_font_boxes() self.toggle_button.clicked.connect(self.toggle_button_pressed) self.remove_all_button.clicked.connect(self.remove_all_button_pressed) self.set_all_button.clicked.connect(self.set_all_button_pressed) self.load_button.clicked.connect(self.load_template_from_file) self.save_button.clicked.connect(self.save_template) self.set_word_wrap( gprefs.get('gpm_template_editor_word_wrap_mode', True)) self.textbox.setContextMenuPolicy( Qt.ContextMenuPolicy.CustomContextMenu) self.textbox.customContextMenuRequested.connect(self.show_context_menu) # Now geometry try: geom = gprefs.get('template_editor_dialog_geometry', None) if geom is not None: QApplication.instance().safe_restore_geometry( self, QByteArray(geom)) except Exception: pass
def __init__(self, parent, view, row, link_delegate): QDialog.__init__(self, parent) 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.WidgetAttribute.WA_OpaquePaintEvent, False) palette = self.details.palette() self.details.setAcceptDrops(False) palette.setBrush(QPalette.ColorRole.Base, Qt.GlobalColor.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.SequenceFormat.NativeText))) self.previous_button.setToolTip( _('Previous [%s]') % unicode_type(self.ps.key().toString( QKeySequence.SequenceFormat.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 color_to_clipboard(self): app = QApplication.instance() c = app.clipboard() c.setText(str(self.color_name.color))
def bd_copy_link(self, url): if url: QApplication.clipboard().setText(url)
def icon_to_clipboard(self): app = QApplication.instance() c = app.clipboard() c.setText(str(self.icon_files.currentText()))
def copy_to_clipboard(self): items = [('✓' if item.checkState() == Qt.CheckState.Checked else '✗') + ' ' + str(item.text()) for item in self.items] QApplication.clipboard().setText('\n'.join(items))
def __init__(self, parent, mi, op_label, op_value, locals_, line_number): super().__init__(parent) self.mi = mi self.setModal(True) l = QVBoxLayout(self) t = self.table = QTableWidget(self) t.setColumnCount(2) t.setHorizontalHeaderLabels((_('Name'), _('Value'))) t.setRowCount(2) l.addWidget(t) self.table_column_widths = None try: self.table_column_widths = \ gprefs.get('template_editor_break_table_widths', None) t.setColumnWidth(0, self.table_column_widths[0]) except: t.setColumnWidth(0, t.fontMetrics().averageCharWidth() * 20) t.horizontalHeader().sectionResized.connect(self.table_column_resized) t.horizontalHeader().setStretchLastSection(True) bb = QDialogButtonBox() b = bb.addButton(_('&Continue'), QDialogButtonBox.ButtonRole.AcceptRole) b.setIcon(QIcon(I('sync-right.png'))) b.setToolTip(_('Continue running the template')) b.setDefault(True) l.addWidget(bb) b = bb.addButton(_('&Stop'), QDialogButtonBox.ButtonRole.RejectRole) b.setIcon(QIcon(I('list_remove.png'))) b.setToolTip(_('Stop running the template')) l.addWidget(bb) bb.accepted.connect(self.accept) bb.rejected.connect(self.reject) self.setLayout(l) self.setWindowTitle( _('Break: line {0}, book {1}').format(line_number, self.mi.title)) local_names = sorted(locals_.keys()) rows = len(local_names) self.table.setRowCount(rows + 2) self.table.setItem(0, 0, BreakReporterItem(op_label)) self.table.item(0, 0).setToolTip( _('The name of the template language operation')) self.table.setItem(0, 1, BreakReporterItem(op_value)) self.mi_combo = QComboBox() t.setCellWidget(1, 0, self.mi_combo) self.mi_combo.addItems(self.get_field_keys()) self.mi_combo.setToolTip('Choose a book metadata field to display') self.mi_combo.setCurrentIndex(-1) self.mi_combo.currentTextChanged.connect(self.get_field_value) for i, k in enumerate(local_names): itm = BreakReporterItem(k) itm.setToolTip(_('A variable in the template')) self.table.setItem(i + 2, 0, itm) itm = BreakReporterItem(locals_[k]) itm.setToolTip(_('The value of the variable')) self.table.setItem(i + 2, 1, itm) try: geom = gprefs.get('template_editor_break_geometry', None) if geom is not None: QApplication.instance().safe_restore_geometry( self, QByteArray(geom)) except Exception: pass
unit = { QPageSize.Unit.Millimeter: 'mm', QPageSize.Unit.Inch: 'inch' }[QPageSize.definitionUnits(s)] name = f'{QPageSize.name(s)} ({sz.width():g} x {sz.height():g} {unit})' self.addItem(name, a) @property def get_value_for_config(self): return self.currentData() @get_value_for_config.setter def set_value_for_config(self, val): idx = self.findData(val or PaperSizes.system_default_paper_size) if idx == -1: idx = self.findData('a4') self.setCurrentIndex(idx) # }}} if __name__ == '__main__': from qt.core import QTextEdit app = QApplication([]) w = QTextEdit() s = PythonHighlighter(w) # w.setSyntaxHighlighter(s) w.setText(open(__file__, 'rb').read().decode('utf-8')) w.show() app.exec()
def emphasis_style(): pal = QApplication.instance().palette() return 'color: {}; font-weight: bold'.format( pal.color(QPalette.ColorRole.Link).name())
def copy_to_clipboard(self): QApplication.instance().clipboard().setPixmap(self.get_pixmap())
def copy_to_clipboard(self): QApplication.instance().clipboard().setText(self.exported_data()) self.accept()