def __init__(self, parent, view, row, link_delegate):
        QDialog.__init__(self, parent)
        self.normal_brush = QBrush(Qt.GlobalColor.white)
        self.marked_brush = QBrush(Qt.GlobalColor.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.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)
Esempio n. 2
0
 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
Esempio n. 3
0
 def copy_to_clipboard(self):
     QApplication.instance().clipboard().setText(self.plain_text)
Esempio n. 4
0
 def icon_to_clipboard(self):
     app = QApplication.instance()
     c = app.clipboard()
     c.setText(unicode_type(self.icon_files.currentText()))
Esempio n. 5
0
    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())
        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.slave_timers = [QTimer(self), QTimer(self), QTimer(self)]
        self.view.clicked.connect(
            partial(self.delayed_slave, func=self.slave, dex=0))
        self.view.selectionModel().currentColumnChanged.connect(
            partial(self.delayed_slave, func=self.column_slave, dex=1))
        QCoreApplication.instance().aboutToQuit.connect(self.save_state)
        self.view.model().new_bookdisplay_data.connect(
            partial(self.delayed_slave, func=self.book_was_changed, dex=2))

        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())
Esempio n. 6
0
    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('{} ({})'.format(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="%s">%s</a>' % (localize_user_manual_link(
                'https://manual.calibre-ebook.com/template_lang.html'), tt))
        tt = _('Template function reference')
        self.template_func_reference.setText(
            '<a href="%s">%s</a>' % (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.textbox.setWordWrapMode(QTextOption.WordWrap)
        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
Esempio n. 7
0
    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 = []
        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('{} ({})'.format(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))

        if dialog_is_st_editor:
            self.buttonBox.setVisible(False)
        else:
            self.new_doc_label.setVisible(False)
            self.new_doc.setVisible(False)
            self.template_name_label.setVisible(False)
            self.template_name.setVisible(False)

        if mi:
            if not isinstance(mi, list):
                mi = (mi, )
        else:
            mi = Metadata(_('Title'), [_('Author')])
            mi.author_sort = _('Author Sort')
            mi.series = ngettext('Series', 'Series', 1)
            mi.series_index = 3
            mi.rating = 4.0
            mi.tags = [_('Tag 1'), _('Tag 2')]
            mi.languages = ['eng']
            mi.id = 1
            if fm is not None:
                self.mi.set_all_user_metadata(fm.custom_field_metadata())
            else:
                # No field metadata. Grab a copy from the current library so
                # that we can validate any custom column names. The values for
                # the columns will all be empty, which in some very unusual
                # cases might cause formatter errors. We can live with that.
                from calibre.gui2.ui import get_gui
                mi.set_all_user_metadata(get_gui(
                ).current_db.new_api.field_metadata.custom_field_metadata())
            for col in mi.get_all_user_metadata(False):
                mi.set(col, (col, ), 0)
            mi = (mi, )
        self.mi = mi

        # Set up the display table
        self.table_column_widths = None
        try:
            self.table_column_widths = \
                        gprefs.get('template_editor_table_widths', None)
        except:
            pass
        tv = self.template_value
        tv.setRowCount(len(mi))
        tv.setColumnCount(2)
        tv.setHorizontalHeaderLabels((_('Book title'), _('Template value')))
        tv.horizontalHeader().setStretchLastSection(True)
        tv.horizontalHeader().sectionResized.connect(self.table_column_resized)
        # Set the height of the table
        h = tv.rowHeight(0) * min(len(mi), 5)
        h += 2 * tv.frameWidth() + tv.horizontalHeader().height()
        tv.setMinimumHeight(h)
        tv.setMaximumHeight(h)
        # Set the size of the title column
        if self.table_column_widths:
            tv.setColumnWidth(0, self.table_column_widths[0])
        else:
            tv.setColumnWidth(0, tv.fontMetrics().averageCharWidth() * 10)
        # Use our own widget to get rid of elision. setTextElideMode() doesn't work
        for r in range(0, len(mi)):
            w = QLineEdit(tv)
            w.setReadOnly(True)
            tv.setCellWidget(r, 0, w)
            w = QLineEdit(tv)
            w.setReadOnly(True)
            tv.setCellWidget(r, 1, w)
        tv.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)

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

        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.textbox.setFont(self.get_current_font())

        self.textbox.setTabStopWidth(10)
        self.source_code.setTabStopWidth(10)
        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.textbox.setContextMenuPolicy(
            Qt.ContextMenuPolicy.CustomContextMenu)
        self.textbox.customContextMenuRequested.connect(self.show_context_menu)

        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.display_values(text)
        self.rule = (None, '')

        tt = _('Template language tutorial')
        self.template_tutorial.setText(
            '<a href="%s">%s</a>' % (localize_user_manual_link(
                'https://manual.calibre-ebook.com/template_lang.html'), tt))
        tt = _('Template function reference')
        self.template_func_reference.setText(
            '<a href="%s">%s</a>' % (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.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)
        # 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
Esempio n. 8
0
    def __init__(self,
                 parent,
                 current_img,
                 current_url,
                 geom_name='viewer_image_popup_geometry'):
        QDialog.__init__(self)
        self.current_image_name = ''
        self.maximized_at_last_fullscreen = False
        self.setWindowFlag(Qt.WindowType.WindowMinimizeButtonHint)
        self.setWindowFlag(Qt.WindowType.WindowMaximizeButtonHint)
        dw = QApplication.instance().desktop()
        self.avail_geom = dw.availableGeometry(
            parent if parent is not None else self)
        self.current_img = current_img
        self.current_url = current_url
        self.factor = 1.0
        self.geom_name = geom_name

        self.scrollarea = sa = QScrollArea()
        sa.setAlignment(Qt.AlignmentFlag.AlignHCenter
                        | Qt.AlignmentFlag.AlignVCenter)
        sa.setBackgroundRole(QPalette.ColorRole.Dark)
        self.label = l = Label(sa)
        l.toggle_fit.connect(self.toggle_fit)
        sa.setWidget(l)

        self.bb = bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Close)
        bb.accepted.connect(self.accept)
        bb.rejected.connect(self.reject)
        self.zi_button = zi = bb.addButton(
            _('Zoom &in'), QDialogButtonBox.ButtonRole.ActionRole)
        self.zo_button = zo = bb.addButton(
            _('Zoom &out'), QDialogButtonBox.ButtonRole.ActionRole)
        self.save_button = so = bb.addButton(
            _('&Save as'), QDialogButtonBox.ButtonRole.ActionRole)
        self.rotate_button = ro = bb.addButton(
            _('&Rotate'), QDialogButtonBox.ButtonRole.ActionRole)
        self.fullscreen_buton = fo = bb.addButton(
            _('&Full screen'), QDialogButtonBox.ButtonRole.ActionRole)
        zi.setIcon(QIcon(I('plus.png')))
        zo.setIcon(QIcon(I('minus.png')))
        so.setIcon(QIcon(I('save.png')))
        ro.setIcon(QIcon(I('rotate-right.png')))
        fo.setIcon(QIcon(I('page.png')))
        zi.clicked.connect(self.zoom_in)
        zo.clicked.connect(self.zoom_out)
        so.clicked.connect(self.save_image)
        ro.clicked.connect(self.rotate_image)
        fo.setCheckable(True)
        fo.toggled.connect(self.toggle_fullscreen)

        self.l = l = QVBoxLayout(self)
        l.addWidget(sa)
        self.h = h = QHBoxLayout()
        h.setContentsMargins(0, 0, 0, 0)
        l.addLayout(h)
        self.fit_image = i = QCheckBox(_('&Fit image'))
        i.setToolTip(_('Fit image inside the available space'))
        i.setChecked(bool(gprefs.get('image_popup_fit_image')))
        i.stateChanged.connect(self.fit_changed)
        h.addWidget(i), h.addStretch(), h.addWidget(bb)
        if self.fit_image.isChecked():
            self.set_to_viewport_size()
        geom = gprefs.get(self.geom_name)
        if geom is not None:
            self.restoreGeometry(geom)
Esempio n. 9
0
    def __init__(self,
                 parent,
                 db,
                 id_to_select,
                 select_sort,
                 select_link,
                 find_aut_func,
                 is_first_letter=False):
        QDialog.__init__(self, parent)
        Ui_EditAuthorsDialog.__init__(self)
        self.setupUi(self)

        # Remove help icon on title bar
        icon = self.windowIcon()
        self.setWindowFlags(self.windowFlags()
                            & (~Qt.WindowType.WindowContextHelpButtonHint))
        self.setWindowIcon(icon)

        try:
            self.table_column_widths = \
                        gprefs.get('manage_authors_table_widths', None)
            geom = gprefs.get('manage_authors_dialog_geometry', None)
            if geom:
                QApplication.instance().safe_restore_geometry(
                    self, QByteArray(geom))
        except Exception:
            pass

        self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(
            _('&OK'))
        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(
            _('&Cancel'))
        self.buttonBox.accepted.connect(self.accepted)
        self.apply_vl_checkbox.stateChanged.connect(self.use_vl_changed)

        # Set up the heading for sorting
        self.table.setSelectionMode(
            QAbstractItemView.SelectionMode.SingleSelection)

        self.find_aut_func = find_aut_func
        self.table.resizeColumnsToContents()
        if self.table.columnWidth(2) < 200:
            self.table.setColumnWidth(2, 200)

        # set up the cellChanged signal only after the table is filled
        self.table.cellChanged.connect(self.cell_changed)

        self.recalc_author_sort.clicked.connect(self.do_recalc_author_sort)
        self.auth_sort_to_author.clicked.connect(self.do_auth_sort_to_author)

        # Capture clicks on the horizontal header to sort the table columns
        hh = self.table.horizontalHeader()
        hh.sectionResized.connect(self.table_column_resized)
        hh.setSectionsClickable(True)
        hh.sectionClicked.connect(self.do_sort)
        hh.setSortIndicatorShown(True)

        # set up the search & filter boxes
        self.find_box.initialize('manage_authors_search')
        le = self.find_box.lineEdit()
        ac = le.findChild(QAction, QT_HIDDEN_CLEAR_ACTION)
        if ac is not None:
            ac.triggered.connect(self.clear_find)
        le.returnPressed.connect(self.do_find)
        self.find_box.editTextChanged.connect(self.find_text_changed)
        self.find_button.clicked.connect(self.do_find)
        self.find_button.setDefault(True)

        self.filter_box.initialize('manage_authors_filter')
        le = self.filter_box.lineEdit()
        ac = le.findChild(QAction, QT_HIDDEN_CLEAR_ACTION)
        if ac is not None:
            ac.triggered.connect(self.clear_filter)
        self.filter_box.lineEdit().returnPressed.connect(self.do_filter)
        self.filter_button.clicked.connect(self.do_filter)

        self.not_found_label = l = QLabel(self.table)
        l.setFrameStyle(QFrame.Shape.StyledPanel)
        l.setAutoFillBackground(True)
        l.setText(_('No matches found'))
        l.setAlignment(Qt.AlignmentFlag.AlignVCenter)
        l.resize(l.sizeHint())
        l.move(10, 2)
        l.setVisible(False)
        self.not_found_label_timer = QTimer()
        self.not_found_label_timer.setSingleShot(True)
        self.not_found_label_timer.timeout.connect(
            self.not_found_label_timer_event,
            type=Qt.ConnectionType.QueuedConnection)

        self.table.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self.table.customContextMenuRequested.connect(self.show_context_menu)

        # Fetch the data
        self.authors = {}
        self.original_authors = {}
        auts = db.new_api.author_data()
        self.completion_data = []
        for id_, v in auts.items():
            name = v['name']
            name = name.replace('|', ',')
            self.completion_data.append(name)
            self.authors[id_] = {
                'name': name,
                'sort': v['sort'],
                'link': v['link']
            }
            self.original_authors[id_] = {
                'name': name,
                'sort': v['sort'],
                'link': v['link']
            }

        self.edited_icon = QIcon(I('modified.png'))
        self.empty_icon = QIcon()
        if prefs['use_primary_find_in_search']:
            self.string_contains = primary_contains
        else:
            self.string_contains = contains

        self.last_sorted_by = 'sort'
        self.author_order = 1
        self.author_sort_order = 0
        self.link_order = 1
        self.show_table(id_to_select, select_sort, select_link,
                        is_first_letter)
Esempio n. 10
0
 def evaljs_callback(self, result):
     self.evaljs_result = result
     QApplication.instance().exit(0)
Esempio n. 11
0
 def size_dialog():
     if geom is None:
         config_dialog.resize(config_dialog.sizeHint())
     else:
         from qt.core import QApplication
         QApplication.instance().safe_restore_geometry(config_dialog, geom)
Esempio n. 12
0
 def signal_received(self, read_fd):
     try:
         os.read(read_fd, 1024)
     except OSError:
         return
     QApplication.instance().exit(KILL_SIGNAL)
Esempio n. 13
0
    def __init__(self,
                 window,
                 cat_name,
                 tag_to_match,
                 get_book_ids,
                 sorter,
                 ttm_is_first_letter=False,
                 category=None,
                 fm=None):
        QDialog.__init__(self, window)
        Ui_TagListEditor.__init__(self)
        self.setupUi(self)
        self.verticalLayout_2.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.search_box.setMinimumContentsLength(25)

        # Put the category name into the title bar
        t = self.windowTitle()
        self.category_name = cat_name
        self.category = category
        self.setWindowTitle(t + ' (' + cat_name + ')')
        # Remove help icon on title bar
        icon = self.windowIcon()
        self.setWindowFlags(self.windowFlags()
                            & (~Qt.WindowType.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.to_rename = {}
        self.to_delete = set()
        self.all_tags = {}
        self.original_names = {}

        self.ordered_tags = []
        self.sorter = sorter
        self.get_book_ids = get_book_ids
        self.text_before_editing = ''

        # Capture clicks on the horizontal header to sort the table columns
        hh = self.table.horizontalHeader()
        hh.sectionResized.connect(self.table_column_resized)
        hh.setSectionsClickable(True)
        hh.sectionClicked.connect(self.do_sort)
        hh.setSortIndicatorShown(True)

        self.last_sorted_by = 'name'
        self.name_order = 0
        self.count_order = 1
        self.was_order = 1

        self.edit_delegate = EditColumnDelegate(self.table)
        self.edit_delegate.editing_finished.connect(self.stop_editing)
        self.edit_delegate.editing_started.connect(self.start_editing)
        self.table.setItemDelegateForColumn(0, self.edit_delegate)

        if prefs['case_sensitive']:
            self.string_contains = contains
        else:
            self.string_contains = self.case_insensitive_compare

        self.delete_button.clicked.connect(self.delete_tags)
        self.table.delete_pressed.connect(self.delete_pressed)
        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.StandardButton.Ok).setText(
            _('&OK'))
        self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText(
            _('&Cancel'))
        self.buttonBox.accepted.connect(self.accepted)

        self.search_box.initialize('tag_list_search_box_' + cat_name)
        le = self.search_box.lineEdit()
        ac = le.findChild(QAction, QT_HIDDEN_CLEAR_ACTION)
        if ac is not None:
            ac.triggered.connect(self.clear_search)
        self.search_box.textChanged.connect(self.search_text_changed)
        self.search_button.clicked.connect(self.do_search)
        self.search_button.setDefault(True)
        l = QLabel(self.table)
        self.not_found_label = l
        l.setFrameStyle(QFrame.Shape.StyledPanel)
        l.setAutoFillBackground(True)
        l.setText(_('No matches found'))
        l.setAlignment(Qt.AlignmentFlag.AlignVCenter)
        l.resize(l.sizeHint())
        l.move(10, 0)
        l.setVisible(False)
        self.not_found_label_timer = QTimer()
        self.not_found_label_timer.setSingleShot(True)
        self.not_found_label_timer.timeout.connect(
            self.not_found_label_timer_event,
            type=Qt.ConnectionType.QueuedConnection)

        self.filter_box.initialize('tag_list_filter_box_' + cat_name)
        le = self.filter_box.lineEdit()
        ac = le.findChild(QAction, QT_HIDDEN_CLEAR_ACTION)
        if ac is not None:
            ac.triggered.connect(self.clear_filter)
        le.returnPressed.connect(self.do_filter)
        self.filter_button.clicked.connect(self.do_filter)

        self.apply_vl_checkbox.clicked.connect(self.vl_box_changed)

        self.table.setEditTriggers(
            QAbstractItemView.EditTrigger.EditKeyPressed)

        try:
            geom = gprefs.get('tag_list_editor_dialog_geometry', None)
            if geom is not None:
                QApplication.instance().safe_restore_geometry(
                    self, QByteArray(geom))
            else:
                self.resize(self.sizeHint() + QSize(150, 100))
        except:
            pass

        self.is_enumerated = False
        if fm:
            if fm['datatype'] == 'enumeration':
                self.is_enumerated = True
                self.enum_permitted_values = fm.get('display', {}).get(
                    'enum_values', None)
        # Add the data
        self.search_item_row = -1
        self.fill_in_table(None, tag_to_match, ttm_is_first_letter)

        self.table.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self.table.customContextMenuRequested.connect(self.show_context_menu)
Esempio n. 14
0
 def copy_image(self):
     if self.current_img and not self.current_img.isNull():
         QApplication.instance().clipboard().setPixmap(self.current_img)
Esempio n. 15
0
    def test_qt(self):
        if is_sanitized:
            raise unittest.SkipTest(
                'Skipping Qt build test as sanitizer is enabled')
        from qt.core import QTimer
        from qt.core import QApplication
        from qt.webengine import QWebEnginePage
        from qt.core import QImageReader, QFontDatabase
        from qt.core import QNetworkAccessManager
        from calibre.utils.img import image_from_data, image_to_data, test
        # Ensure that images can be read before QApplication is constructed.
        # Note that this requires QCoreApplication.libraryPaths() to return the
        # path to the Qt plugins which it always does in the frozen build,
        # because Qt is patched to know the layout of the calibre application
        # package. On non-frozen builds, it should just work because the
        # hard-coded paths of the Qt installation should work. If they do not,
        # then it is a distro problem.
        fmts = set(
            map(lambda x: x.data().decode('utf-8'),
                QImageReader.supportedImageFormats()))  # no2to3
        testf = {'jpg', 'png', 'svg', 'ico', 'gif'}
        self.assertEqual(
            testf.intersection(fmts), testf,
            "Qt doesn't seem to be able to load some of its image plugins. Available plugins: %s"
            % fmts)
        data = P('images/blank.png', allow_user_override=False, data=True)
        img = image_from_data(data)
        image_from_data(
            P('catalog/mastheadImage.gif',
              allow_user_override=False,
              data=True))
        for fmt in 'png bmp jpeg'.split():
            d = image_to_data(img, fmt=fmt)
            image_from_data(d)
        # Run the imaging tests
        test()

        from calibre.gui2 import ensure_app, destroy_app
        display_env_var = os.environ.pop('DISPLAY', None)
        try:
            ensure_app()
            self.assertGreaterEqual(
                len(QFontDatabase().families()), 5,
                'The QPA headless plugin is not able to locate enough system fonts via fontconfig'
            )
            from calibre.ebooks.covers import create_cover
            create_cover('xxx', ['yyy'])
            na = QNetworkAccessManager()
            self.assertTrue(hasattr(na, 'sslErrors'),
                            'Qt not compiled with openssl')
            if iswindows:
                from qt.core import QtWin
                QtWin
            p = QWebEnginePage()

            def callback(result):
                callback.result = result
                if hasattr(print_callback, 'result'):
                    QApplication.instance().quit()

            def print_callback(result):
                print_callback.result = result
                if hasattr(callback, 'result'):
                    QApplication.instance().quit()

            p.runJavaScript('1 + 1', callback)
            p.printToPdf(print_callback)
            QTimer.singleShot(5000, lambda: QApplication.instance().quit())
            QApplication.instance().exec_()
            test_flaky = ismacos and not is_ci
            if not test_flaky:
                self.assertEqual(callback.result, 2,
                                 'Simple JS computation failed')
                self.assertIn(b'Skia/PDF', bytes(print_callback.result),
                              'Print to PDF failed')
            del p
            del na
            destroy_app()
            del QWebEnginePage
        finally:
            if display_env_var is not None:
                os.environ['DISPLAY'] = display_env_var
Esempio n. 16
0
    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:
            QApplication.instance().safe_restore_geometry(self, geom)

        # Center
        if islinux:
            self.move(gui.rect().center() - self.rect().center())

        self.setWindowModality(Qt.WindowModality.ApplicationModal)
        self.setWindowTitle(__appname__ + ' - ' + _('Preferences'))
        self.setWindowIcon(QIcon(I('config.png')))
        self.l = l = QVBoxLayout(self)

        self.stack = QStackedWidget(self)
        self.bb = QDialogButtonBox(
            QDialogButtonBox.StandardButton.Close
            | QDialogButtonBox.StandardButton.Apply
            | QDialogButtonBox.StandardButton.Cancel
            | QDialogButtonBox.StandardButton.RestoreDefaults)
        self.bb.button(QDialogButtonBox.StandardButton.Apply).clicked.connect(
            self.accept)
        self.bb.button(
            QDialogButtonBox.StandardButton.RestoreDefaults).setIcon(
                QIcon(I('clear_left.png')))
        self.bb.button(
            QDialogButtonBox.StandardButton.RestoreDefaults).clicked.connect(
                self.restore_defaults)
        self.wizard_button = self.bb.addButton(
            _('Run Welcome &wizard'), QDialogButtonBox.ButtonRole.ActionRole)
        self.wizard_button.setIcon(QIcon(I('wizard.png')))
        self.wizard_button.clicked.connect(
            self.run_wizard, type=Qt.ConnectionType.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.ContextMenuPolicy.NoContextMenu)
        self.title_bar = TitleBar(self)
        for ac, tt in [(QDialogButtonBox.StandardButton.Apply,
                        _('Save changes')),
                       (QDialogButtonBox.StandardButton.Cancel,
                        _('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()
Esempio n. 17
0
 def print_callback(result):
     print_callback.result = result
     if hasattr(callback, 'result'):
         QApplication.instance().quit()
Esempio n. 18
0
    def __init__(self,
                 ids,
                 get_metadata,
                 field_metadata,
                 parent=None,
                 window_title=None,
                 reject_button_tooltip=None,
                 accept_all_tooltip=None,
                 reject_all_tooltip=None,
                 revert_tooltip=None,
                 intro_msg=None,
                 action_button=None,
                 **kwargs):
        QDialog.__init__(self, parent)
        self.stack = s = QStackedLayout(self)
        self.w = w = QWidget(self)
        self.l = l = QVBoxLayout(w)
        s.addWidget(w)
        self.next_called = False
        self.setWindowIcon(QIcon(I('auto_author_sort.png')))
        self.get_metadata = get_metadata
        self.ids = list(ids)
        self.total = len(self.ids)
        self.accepted = OrderedDict()
        self.rejected_ids = set()
        self.window_title = window_title or _('Compare metadata')

        if intro_msg:
            self.la = la = QLabel(intro_msg)
            la.setWordWrap(True)
            l.addWidget(la)

        self.compare_widget = CompareSingle(field_metadata,
                                            parent=parent,
                                            revert_tooltip=revert_tooltip,
                                            **kwargs)
        self.sa = sa = QScrollArea()
        l.addWidget(sa)
        sa.setWidget(self.compare_widget)
        sa.setWidgetResizable(True)
        self.cover_zoom = cz = CoverZoom(self)
        cz.bb.rejected.connect(self.reject)
        s.addWidget(cz)
        self.compare_widget.zoom_requested.connect(self.show_zoomed_cover)

        self.bb = bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Cancel)
        bb.button(QDialogButtonBox.StandardButton.Cancel).setAutoDefault(False)
        bb.rejected.connect(self.reject)
        if self.total > 1:
            self.aarb = b = bb.addButton(_('&Accept all remaining'),
                                         QDialogButtonBox.ButtonRole.YesRole)
            b.setIcon(QIcon(I('ok.png'))), b.setAutoDefault(False)
            if accept_all_tooltip:
                b.setToolTip(accept_all_tooltip)
            b.clicked.connect(self.accept_all_remaining)
            self.rarb = b = bb.addButton(
                _('Re&ject all remaining'),
                QDialogButtonBox.ButtonRole.ActionRole)
            b.setIcon(QIcon(I('minus.png'))), b.setAutoDefault(False)
            if reject_all_tooltip:
                b.setToolTip(reject_all_tooltip)
            b.clicked.connect(self.reject_all_remaining)
            self.sb = b = bb.addButton(_('R&eject'),
                                       QDialogButtonBox.ButtonRole.ActionRole)
            connect_lambda(b.clicked, self, lambda self: self.next_item(False))
            b.setIcon(QIcon(I('minus.png'))), b.setAutoDefault(False)
            if reject_button_tooltip:
                b.setToolTip(reject_button_tooltip)
            self.next_action = ac = QAction(self)
            ac.setShortcut(QKeySequence(Qt.Modifier.ALT | Qt.Key.Key_Right))
            self.addAction(ac)
        if action_button is not None:
            self.acb = b = bb.addButton(action_button[0],
                                        QDialogButtonBox.ButtonRole.ActionRole)
            b.setIcon(QIcon(action_button[1]))
            self.action_button_action = action_button[2]
            b.clicked.connect(self.action_button_clicked)
        self.nb = b = bb.addButton(
            _('&Next') if self.total > 1 else _('&OK'),
            QDialogButtonBox.ButtonRole.ActionRole)
        if self.total > 1:
            b.setToolTip(
                _('Move to next [%s]') % self.next_action.shortcut().toString(
                    QKeySequence.SequenceFormat.NativeText))
            self.next_action.triggered.connect(b.click)
        b.setIcon(QIcon(I('forward.png' if self.total > 1 else 'ok.png')))
        connect_lambda(b.clicked, self, lambda self: self.next_item(True))
        b.setDefault(True), b.setAutoDefault(True)
        self.bbh = h = QHBoxLayout()
        h.setContentsMargins(0, 0, 0, 0)
        l.addLayout(h)
        self.markq = m = QCheckBox(_('&Mark rejected books'))
        m.setChecked(gprefs['metadata_diff_mark_rejected'])
        connect_lambda(
            m.stateChanged[int], self, lambda self: gprefs.set(
                'metadata_diff_mark_rejected', self.markq.isChecked()))
        m.setToolTip(
            _('Mark rejected books in the book list after this dialog is closed'
              ))
        h.addWidget(m), h.addWidget(bb)

        self.next_item(True)

        desktop = QApplication.instance().desktop()
        geom = desktop.availableGeometry(parent or self)
        width = max(700, min(950, geom.width() - 50))
        height = max(650, min(1000, geom.height() - 100))
        self.resize(QSize(width, height))
        geom = gprefs.get('diff_dialog_geom', None)
        if geom is not None:
            QApplication.instance().safe_restore_geometry(self, geom)
        b.setFocus(Qt.FocusReason.OtherFocusReason)
        self.next_called = False
Esempio n. 19
0
 def resize_dialog(self):
     if self.geom is None:
         self.resize(self.sizeHint()+self.initial_extra_size)
     else:
         QApplication.instance().safe_restore_geometry(self, self.geom)
Esempio n. 20
0
 def do_paste_and_match_style(self):
     text = QApplication.instance().clipboard().text()
     if text:
         self.setText(text)
Esempio n. 21
0
 def color_to_clipboard(self):
     app = QApplication.instance()
     c = app.clipboard()
     c.setText(unicode_type(self.color_name.color))
Esempio n. 22
0
 def copy_report():
     text = re.sub(r'</.+?>', '\n', report)
     text = re.sub(r'<.+?>', '', text)
     cp = QApplication.instance().clipboard()
     cp.setText(text)
Esempio n. 23
0
    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(
            _('Book "%s": break on line number %d') %
            (self.mi.title, line_number))

        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
Esempio n. 24
0
 def hide_cursor(self):
     if get_session_pref('auto_hide_mouse', True):
         self.cursor_hidden = True
         QApplication.instance().setOverrideCursor(
             Qt.CursorShape.BlankCursor)
Esempio n. 25
0
 def copy_to_clipboard(self):
     QApplication.instance().clipboard().setText(self.exported_data())
     self.accept()
Esempio n. 26
0
def show_config_widget(category, name, gui=None, show_restart_msg=False,
        parent=None, never_shutdown=False):
    '''
    Show the preferences plugin identified by category and name

    :param gui: gui instance, if None a hidden gui is created
    :param show_restart_msg: If True and the preferences plugin indicates a
    restart is required, show a message box telling the user to restart
    :param parent: The parent of the displayed dialog

    :return: True iff a restart is required for the changes made by the user to
    take effect
    '''
    from calibre.gui2 import gprefs
    pl = get_plugin(category, name)
    d = ConfigDialog(parent)
    d.resize(750, 550)
    conf_name = 'config_widget_dialog_geometry_%s_%s'%(category, name)
    geom = gprefs.get(conf_name, None)
    d.setWindowTitle(_('Configure ') + pl.gui_name)
    d.setWindowIcon(QIcon(I('config.png')))
    bb = QDialogButtonBox(d)
    bb.setStandardButtons(QDialogButtonBox.StandardButton.Apply|QDialogButtonBox.StandardButton.Cancel|QDialogButtonBox.StandardButton.RestoreDefaults)
    bb.accepted.connect(d.accept)
    bb.rejected.connect(d.reject)
    w = pl.create_widget(d)
    d.set_widget(w)
    bb.button(QDialogButtonBox.StandardButton.RestoreDefaults).clicked.connect(w.restore_defaults)
    bb.button(QDialogButtonBox.StandardButton.RestoreDefaults).setEnabled(w.supports_restoring_to_defaults)
    bb.button(QDialogButtonBox.StandardButton.Apply).setEnabled(False)
    bb.button(QDialogButtonBox.StandardButton.Apply).clicked.connect(d.accept)

    def onchange():
        b = bb.button(QDialogButtonBox.StandardButton.Apply)
        b.setEnabled(True)
        b.setDefault(True)
        b.setAutoDefault(True)
    w.changed_signal.connect(onchange)
    bb.button(QDialogButtonBox.StandardButton.Cancel).setFocus(Qt.FocusReason.OtherFocusReason)
    l = QVBoxLayout()
    d.setLayout(l)
    l.addWidget(w)
    l.addWidget(bb)
    mygui = gui is None
    if gui is None:
        gui = init_gui()
        mygui = True
    w.genesis(gui)
    w.initialize()
    if geom is not None:
        QApplication.instance().safe_restore_geometry(d, geom)
    d.exec()
    geom = bytearray(d.saveGeometry())
    gprefs[conf_name] = geom
    rr = getattr(d, 'restart_required', False)
    if show_restart_msg and rr:
        from calibre.gui2 import warning_dialog
        warning_dialog(gui, 'Restart required', 'Restart required', show=True)
    if mygui and not never_shutdown:
        gui.shutdown()
    return rr
Esempio n. 27
0
 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 = self.screen().availableSize().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.on_iframe_ready.connect(self.on_iframe_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.update_reading_rates.connect(self.update_reading_rates)
     self.bridge.edit_book.connect(self.edit_book)
     self.bridge.show_book_folder.connect(self.show_book_folder)
     self.bridge.show_help.connect(self.show_help)
     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(f'{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)
Esempio n. 28
0
    def __init__(self, parent, dbspec, ids, db):
        import re
        from PyQt5.uic import compileUi

        from calibre import prints as info

        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.dbspec, self.ids = dbspec, ids

        # Display the number of books we've been passed
        self.count.setText(str(self.count.text()).format(len(ids)))

        # Display the last-used title
        self.title.setText(dynamic.get('catalog_last_used_title',
            _('My books')))

        self.fmts, self.widgets = [], []

        for plugin in catalog_plugins():
            if plugin.name in config['disabled_plugins']:
                continue

            name = plugin.name.lower().replace(' ', '_')
            if getattr(plugin, 'installation_type', None) is PluginInstallationType.BUILTIN:
                try:
                    catalog_widget = importlib.import_module('calibre.gui2.catalog.'+name)
                    pw = catalog_widget.PluginWidget()
                    pw.parent_ref = weakref.ref(self)
                    pw.initialize(name, db)
                    pw.ICON = I('forward.png')
                    self.widgets.append(pw)
                    [self.fmts.append([file_type.upper(), pw.sync_enabled,pw]) for file_type in plugin.file_types]
                except ImportError:
                    info("ImportError initializing %s" % name)
                    continue
            else:
                # Load dynamic tab
                form = os.path.join(plugin.resources_path,'%s.ui' % name)
                klass = os.path.join(plugin.resources_path,'%s.py' % name)
                compiled_form = os.path.join(plugin.resources_path,'%s_ui.py' % name)

                if os.path.exists(form) and os.path.exists(klass):
                    # info("Adding widget for user-installed Catalog plugin %s" % plugin.name)

                    # Compile the .ui form provided in plugin.zip
                    if not os.path.exists(compiled_form):
                        from polyglot.io import PolyglotStringIO

                        # info('\tCompiling form', form)
                        buf = PolyglotStringIO()
                        compileUi(form, buf)
                        dat = buf.getvalue()
                        dat = re.compile(r'QtGui.QApplication.translate\(.+?,\s+"(.+?)(?<!\\)",.+?\)',
                                         re.DOTALL).sub(r'_("\1")', dat)
                        open(compiled_form, 'wb').write(dat.encode('utf-8'))

                    # Import the dynamic PluginWidget() from .py file provided in plugin.zip
                    try:
                        sys.path.insert(0, plugin.resources_path)
                        catalog_widget = importlib.import_module(name)
                        pw = catalog_widget.PluginWidget()
                        pw.initialize(name)
                        pw.ICON = I('forward.png')
                        self.widgets.append(pw)
                        [self.fmts.append([file_type.upper(), pw.sync_enabled,pw]) for file_type in plugin.file_types]
                    except ImportError:
                        info("ImportError with %s" % name)
                        continue
                    finally:
                        sys.path.remove(plugin.resources_path)

                else:
                    info("No dynamic tab resources found for %s" % name)

        self.widgets = sorted(self.widgets, key=lambda x: x.TITLE)

        # Generate a sorted list of installed catalog formats/sync_enabled pairs
        fmts = sorted(x[0] for x in self.fmts)

        self.sync_enabled_formats = []
        for fmt in self.fmts:
            if fmt[1]:
                self.sync_enabled_formats.append(fmt[0])

        # Callbacks when format, title changes
        self.format.currentIndexChanged.connect(self.format_changed)
        self.format.currentIndexChanged.connect(self.settings_changed)
        self.title.editingFinished.connect(self.settings_changed)

        # Add the installed catalog format list to the format QComboBox
        self.format.blockSignals(True)
        self.format.addItems(fmts)

        pref = dynamic.get('catalog_preferred_format', 'CSV')
        idx = self.format.findText(pref)
        if idx > -1:
            self.format.setCurrentIndex(idx)
        self.format.blockSignals(False)

        if self.sync.isEnabled():
            self.sync.setChecked(dynamic.get('catalog_sync_to_device', True))
        self.add_to_library.setChecked(dynamic.get('catalog_add_to_library', True))

        self.format.currentIndexChanged.connect(self.show_plugin_tab)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Apply).clicked.connect(self.apply)
        self.buttonBox.button(QDialogButtonBox.StandardButton.Help).clicked.connect(self.help)
        self.show_plugin_tab(None)

        geom = dynamic.get('catalog_window_geom', None)
        if geom is not None:
            QApplication.instance().safe_restore_geometry(self, bytes(geom))
        else:
            self.resize(self.sizeHint())
        d = QCoreApplication.instance().desktop()
        g = d.availableGeometry(d.screenNumber(self))
        self.setMaximumWidth(g.width() - 50)
        self.setMaximumHeight(g.height() - 50)
Esempio n. 29
0
 def show_normal(self):
     self.showNormal()
     if self.pre_fs_geom is not None:
         QApplication.instance().safe_restore_geometry(self, self.pre_fs_geom)
         self.pre_fs_geom = None
Esempio n. 30
0
 def copy_to_clipboard(self):
     QApplication.instance().clipboard().setPixmap(self.pixmap)