Пример #1
0
 def create_widgets(self, opt):
     val = self.plugin.prefs[opt.name]
     if opt.type == 'number':
         c = QSpinBox if isinstance(opt.default,
                                    numbers.Integral) else QDoubleSpinBox
         widget = c(self)
         widget.setValue(val)
     elif opt.type == 'string':
         widget = QLineEdit(self)
         widget.setText(val if val else '')
     elif opt.type == 'bool':
         widget = QCheckBox(opt.label, self)
         widget.setChecked(bool(val))
     elif opt.type == 'choices':
         widget = QComboBox(self)
         items = list(iteritems(opt.choices))
         items.sort(key=lambda k_v: sort_key(k_v[1]))
         for key, label in items:
             widget.addItem(label, (key))
         idx = widget.findData(val)
         widget.setCurrentIndex(idx)
     widget.opt = opt
     widget.setToolTip(textwrap.fill(opt.desc))
     self.widgets.append(widget)
     r = self.l.rowCount()
     if opt.type == 'bool':
         self.l.addWidget(widget, r, 0, 1, self.l.columnCount())
     else:
         l = QLabel(opt.label)
         l.setToolTip(widget.toolTip())
         self.memory.append(l)
         l.setBuddy(widget)
         self.l.addWidget(l, r, 0, 1, 1)
         self.l.addWidget(widget, r, 1, 1, 1)
Пример #2
0
    def setup_store_checks(self):
        first_run = self.config.get('first_run', True)

        # Add check boxes for each store so the user
        # can disable searching specific stores on a
        # per search basis.
        existing = {}
        for n in self.store_checks:
            existing[n] = self.store_checks[n].isChecked()

        self.store_checks = {}

        stores_check_widget = QWidget()
        store_list_layout = QGridLayout()
        stores_check_widget.setLayout(store_list_layout)

        icon = QIcon(I('donate.png'))
        for i, x in enumerate(
                sorted(self.gui.istores.keys(), key=lambda x: x.lower())):
            cbox = QCheckBox(x)
            cbox.setChecked(existing.get(x, first_run))
            store_list_layout.addWidget(cbox, i, 0, 1, 1)
            if self.gui.istores[x].base_plugin.affiliate:
                iw = QLabel(self)
                iw.setToolTip('<p>' + _(
                    'Buying from this store supports the calibre developer: %s</p>'
                ) % self.gui.istores[x].base_plugin.author + '</p>')
                iw.setPixmap(icon.pixmap(16, 16))
                store_list_layout.addWidget(iw, i, 1, 1, 1)
            self.store_checks[x] = cbox
        store_list_layout.setRowStretch(store_list_layout.rowCount(), 10)
        self.store_list.setWidget(stores_check_widget)

        self.config['first_run'] = False
    def __init__(self,
                 settings,
                 all_formats,
                 supports_subdirs,
                 must_read_metadata,
                 supports_use_author_sort,
                 extra_customization_message,
                 device,
                 extra_customization_choices=None):

        QWidget.__init__(self)
        Ui_ConfigWidget.__init__(self)
        self.setupUi(self)

        self.settings = settings

        all_formats = set(all_formats)
        self.calibre_known_formats = device.FORMATS
        try:
            self.device_name = device.get_gui_name()
        except TypeError:
            self.device_name = getattr(device, 'gui_name', None) or _('Device')
        if device.USER_CAN_ADD_NEW_FORMATS:
            all_formats = all_formats | set(BOOK_EXTENSIONS)

        format_map = settings.format_map
        disabled_formats = all_formats.difference(format_map)
        for format in format_map + sorted(disabled_formats):
            item = QListWidgetItem(format, self.columns)
            item.setData(Qt.ItemDataRole.UserRole, (format))
            item.setFlags(Qt.ItemFlag.ItemIsEnabled
                          | Qt.ItemFlag.ItemIsUserCheckable
                          | Qt.ItemFlag.ItemIsSelectable)
            item.setCheckState(Qt.CheckState.Checked if format in
                               format_map else Qt.CheckState.Unchecked)

        self.column_up.clicked.connect(self.up_column)
        self.column_down.clicked.connect(self.down_column)

        if device.HIDE_FORMATS_CONFIG_BOX:
            self.groupBox.hide()

        if supports_subdirs:
            self.opt_use_subdirs.setChecked(self.settings.use_subdirs)
        else:
            self.opt_use_subdirs.hide()
        if not must_read_metadata:
            self.opt_read_metadata.setChecked(self.settings.read_metadata)
        else:
            self.opt_read_metadata.hide()
        if supports_use_author_sort:
            self.opt_use_author_sort.setChecked(self.settings.use_author_sort)
        else:
            self.opt_use_author_sort.hide()
        if extra_customization_message:
            extra_customization_choices = extra_customization_choices or {}

            def parse_msg(m):
                msg, _, tt = m.partition(':::') if m else ('', '', '')
                return msg.strip(), textwrap.fill(tt.strip(), 100)

            if isinstance(extra_customization_message, list):
                self.opt_extra_customization = []
                if len(extra_customization_message) > 6:
                    row_func = lambda x, y: ((x // 2) * 2) + y
                    col_func = lambda x: x % 2
                else:
                    row_func = lambda x, y: x * 2 + y
                    col_func = lambda x: 0

                for i, m in enumerate(extra_customization_message):
                    label_text, tt = parse_msg(m)
                    if not label_text:
                        self.opt_extra_customization.append(None)
                        continue
                    if isinstance(settings.extra_customization[i], bool):
                        self.opt_extra_customization.append(
                            QCheckBox(label_text))
                        self.opt_extra_customization[-1].setToolTip(tt)
                        self.opt_extra_customization[i].setChecked(
                            bool(settings.extra_customization[i]))
                    elif i in extra_customization_choices:
                        cb = QComboBox(self)
                        self.opt_extra_customization.append(cb)
                        l = QLabel(label_text)
                        l.setToolTip(tt), cb.setToolTip(tt), l.setBuddy(
                            cb), cb.setToolTip(tt)
                        for li in sorted(extra_customization_choices[i]):
                            self.opt_extra_customization[i].addItem(li)
                        cb.setCurrentIndex(
                            max(0,
                                cb.findText(settings.extra_customization[i])))
                    else:
                        self.opt_extra_customization.append(QLineEdit(self))
                        l = QLabel(label_text)
                        l.setToolTip(tt)
                        self.opt_extra_customization[i].setToolTip(tt)
                        l.setBuddy(self.opt_extra_customization[i])
                        l.setWordWrap(True)
                        self.opt_extra_customization[i].setText(
                            settings.extra_customization[i])
                        self.opt_extra_customization[i].setCursorPosition(0)
                        self.extra_layout.addWidget(l, row_func(i, 0),
                                                    col_func(i))
                    self.extra_layout.addWidget(
                        self.opt_extra_customization[i], row_func(i, 1),
                        col_func(i))
            else:
                self.opt_extra_customization = QLineEdit()
                label_text, tt = parse_msg(extra_customization_message)
                l = QLabel(label_text)
                l.setToolTip(tt)
                l.setBuddy(self.opt_extra_customization)
                l.setWordWrap(True)
                if settings.extra_customization:
                    self.opt_extra_customization.setText(
                        settings.extra_customization)
                    self.opt_extra_customization.setCursorPosition(0)
                self.opt_extra_customization.setCursorPosition(0)
                self.extra_layout.addWidget(l, 0, 0)
                self.extra_layout.addWidget(self.opt_extra_customization, 1, 0)
        self.opt_save_template.setText(settings.save_template)
Пример #4
0
class Diff(Dialog):

    revert_requested = pyqtSignal()
    line_activated = pyqtSignal(object, object, object)

    def __init__(self, revert_button_msg=None, parent=None, show_open_in_editor=False, show_as_window=False):
        self.context = 3
        self.beautify = False
        self.apply_diff_calls = []
        self.show_open_in_editor = show_open_in_editor
        self.revert_button_msg = revert_button_msg
        Dialog.__init__(self, _('Differences between books'), 'diff-dialog', parent=parent)
        self.setWindowFlags(self.windowFlags() | Qt.WindowType.WindowMinMaxButtonsHint)
        if show_as_window:
            self.setWindowFlags(Qt.WindowType.Window)
        self.view.line_activated.connect(self.line_activated)

    def sizeHint(self):
        geom = self.screen().availableSize()
        return QSize(int(0.9 * geom.width()), int(0.8 * geom.height()))

    def setup_ui(self):
        self.setWindowIcon(QIcon(I('diff.png')))
        self.stacks = st = QStackedLayout(self)
        self.busy = BusyWidget(self)
        self.w = QWidget(self)
        st.addWidget(self.busy), st.addWidget(self.w)

        self.setLayout(st)
        self.l = l = QGridLayout()
        self.w.setLayout(l)

        self.view = v = DiffView(self, show_open_in_editor=self.show_open_in_editor)
        l.addWidget(v, l.rowCount(), 0, 1, -1)

        r = l.rowCount()
        self.bp = b = QToolButton(self)
        b.setIcon(QIcon(I('back.png')))
        connect_lambda(b.clicked, self, lambda self: self.view.next_change(-1))
        b.setToolTip(_('Go to previous change') + ' [p]')
        b.setText(_('&Previous change')), b.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
        l.addWidget(b, r, 0)

        self.bn = b = QToolButton(self)
        b.setIcon(QIcon(I('forward.png')))
        connect_lambda(b.clicked, self, lambda self: self.view.next_change(1))
        b.setToolTip(_('Go to next change') + ' [n]')
        b.setText(_('&Next change')), b.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
        l.addWidget(b, r, 1)

        self.search = s = HistoryLineEdit2(self)
        s.initialize('diff_search_history')
        l.addWidget(s, r, 2)
        s.setPlaceholderText(_('Search for text'))
        connect_lambda(s.returnPressed, self, lambda self: self.do_search(False))
        self.sbn = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-down.png')))
        connect_lambda(b.clicked, self, lambda self: self.do_search(False))
        b.setToolTip(_('Find next match'))
        b.setText(_('Next &match')), b.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
        l.addWidget(b, r, 3)
        self.sbp = b = QToolButton(self)
        b.setIcon(QIcon(I('arrow-up.png')))
        connect_lambda(b.clicked, self, lambda self: self.do_search(True))
        b.setToolTip(_('Find previous match'))
        b.setText(_('P&revious match')), b.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
        l.addWidget(b, r, 4)
        self.lb = b = QRadioButton(_('Left panel'), self)
        b.setToolTip(_('Perform search in the left panel'))
        l.addWidget(b, r, 5)
        self.rb = b = QRadioButton(_('Right panel'), self)
        b.setToolTip(_('Perform search in the right panel'))
        l.addWidget(b, r, 6)
        b.setChecked(True)
        self.pb = b = QToolButton(self)
        b.setIcon(QIcon(I('config.png')))
        b.setText(_('&Options')), b.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
        b.setToolTip(_('Change how the differences are displayed'))
        b.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
        m = QMenu(b)
        b.setMenu(m)
        cm = self.cm = QMenu(_('Lines of context around each change'))
        for i in (3, 5, 10, 50):
            cm.addAction(_('Show %d lines of context') % i, partial(self.change_context, i))
        cm.addAction(_('Show all text'), partial(self.change_context, None))
        self.beautify_action = m.addAction('', self.toggle_beautify)
        self.set_beautify_action_text()
        m.addMenu(cm)
        l.addWidget(b, r, 7)

        self.hl = QHBoxLayout()
        l.addLayout(self.hl, l.rowCount(), 0, 1, -1)
        self.names = QLabel('')
        self.hl.addWidget(self.names, stretch=100)
        if self.show_open_in_editor:
            self.edit_msg = QLabel(_('Double click right side to edit'))
            self.edit_msg.setToolTip(textwrap.fill(_(
                'Double click on any change in the right panel to edit that location in the editor')))
            self.hl.addWidget(self.edit_msg)

        self.bb.setStandardButtons(QDialogButtonBox.StandardButton.Close)
        if self.revert_button_msg is not None:
            self.rvb = b = self.bb.addButton(self.revert_button_msg, QDialogButtonBox.ButtonRole.ActionRole)
            b.setIcon(QIcon(I('edit-undo.png'))), b.setAutoDefault(False)
            b.clicked.connect(self.revert_requested)
            b.clicked.connect(self.reject)
        self.bb.button(QDialogButtonBox.StandardButton.Close).setDefault(True)
        self.hl.addWidget(self.bb)

        self.view.setFocus(Qt.FocusReason.OtherFocusReason)

    def break_cycles(self):
        self.view = None
        for x in ('revert_requested', 'line_activated'):
            try:
                getattr(self, x).disconnect()
            except:
                pass

    def do_search(self, reverse):
        text = str(self.search.text())
        if not text.strip():
            return
        v = self.view.view.left if self.lb.isChecked() else self.view.view.right
        v.search(text, reverse=reverse)

    def change_context(self, context):
        if context == self.context:
            return
        self.context = context
        self.refresh()

    def refresh(self):
        with self:
            self.view.clear()
            for args, kwargs in self.apply_diff_calls:
                kwargs['context'] = self.context
                kwargs['beautify'] = self.beautify
                self.view.add_diff(*args, **kwargs)
            self.view.finalize()

    def toggle_beautify(self):
        self.beautify = not self.beautify
        self.set_beautify_action_text()
        self.refresh()

    def set_beautify_action_text(self):
        self.beautify_action.setText(
            _('Beautify files before comparing them') if not self.beautify else
            _('Do not beautify files before comparing'))

    def __enter__(self):
        self.stacks.setCurrentIndex(0)
        self.busy.setVisible(True)
        self.busy.pi.startAnimation()
        QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor))
        QApplication.processEvents(QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents | QEventLoop.ProcessEventsFlag.ExcludeSocketNotifiers)

    def __exit__(self, *args):
        self.busy.pi.stopAnimation()
        self.stacks.setCurrentIndex(1)
        QApplication.restoreOverrideCursor()

    def set_names(self, names):
        t = ''
        if isinstance(names, tuple):
            t = '%s <--> %s' % names
        self.names.setText(t)

    def ebook_diff(self, path1, path2, names=None):
        self.set_names(names)
        with self:
            identical = self.apply_diff(_('The books are identical'), *ebook_diff(path1, path2))
            self.view.finalize()
        if identical:
            self.reject()

    def container_diff(self, left, right, identical_msg=None, names=None):
        self.set_names(names)
        with self:
            identical = self.apply_diff(identical_msg or _('No changes found'), *container_diff(left, right))
            self.view.finalize()
        if identical:
            self.reject()

    def file_diff(self, left, right, identical_msg=None):
        with self:
            identical = self.apply_diff(identical_msg or _('The files are identical'), *file_diff(left, right))
            self.view.finalize()
        if identical:
            self.reject()

    def string_diff(self, left, right, **kw):
        with self:
            identical = self.apply_diff(kw.pop('identical_msg', None) or _('No differences found'), *string_diff(left, right, **kw))
            self.view.finalize()
        if identical:
            self.reject()

    def dir_diff(self, left, right, identical_msg=None):
        with self:
            identical = self.apply_diff(identical_msg or _('The folders are identical'), *dir_diff(left, right))
            self.view.finalize()
        if identical:
            self.reject()

    def apply_diff(self, identical_msg, cache, syntax_map, changed_names, renamed_names, removed_names, added_names):
        self.view.clear()
        self.apply_diff_calls = calls = []

        def add(args, kwargs):
            self.view.add_diff(*args, **kwargs)
            calls.append((args, kwargs))

        if len(changed_names) + len(renamed_names) + len(removed_names) + len(added_names) < 1:
            self.busy.setVisible(False)
            info_dialog(self, _('No changes found'), identical_msg, show=True)
            self.busy.setVisible(True)
            return True

        kwargs = lambda name: {'context':self.context, 'beautify':self.beautify, 'syntax':syntax_map.get(name, None)}

        if isinstance(changed_names, dict):
            for name, other_name in sorted(iteritems(changed_names), key=lambda x:numeric_sort_key(x[0])):
                args = (name, other_name, cache.left(name), cache.right(other_name))
                add(args, kwargs(name))
        else:
            for name in sorted(changed_names, key=numeric_sort_key):
                args = (name, name, cache.left(name), cache.right(name))
                add(args, kwargs(name))

        for name in sorted(added_names, key=numeric_sort_key):
            args = (_('[%s was added]') % name, name, None, cache.right(name))
            add(args, kwargs(name))

        for name in sorted(removed_names, key=numeric_sort_key):
            args = (name, _('[%s was removed]') % name, cache.left(name), None)
            add(args, kwargs(name))

        for name, new_name in sorted(iteritems(renamed_names), key=lambda x:numeric_sort_key(x[0])):
            args = (name, new_name, None, None)
            add(args, kwargs(name))

    def keyPressEvent(self, ev):
        if not self.view.handle_key(ev):
            if ev.key() in (Qt.Key.Key_Enter, Qt.Key.Key_Return):
                return  # The enter key is used by the search box, so prevent it closing the dialog
            if ev.key() == Qt.Key.Key_Slash:
                return self.search.setFocus(Qt.FocusReason.OtherFocusReason)
            if ev.matches(QKeySequence.StandardKey.Copy):
                text = self.view.view.left.selected_text + self.view.view.right.selected_text
                if text:
                    QApplication.clipboard().setText(text)
                return
            if ev.matches(QKeySequence.StandardKey.FindNext):
                self.sbn.click()
                return
            if ev.matches(QKeySequence.StandardKey.FindPrevious):
                self.sbp.click()
                return
            return Dialog.keyPressEvent(self, ev)
Пример #5
0
    def __init__(self, extra_customization_message,
                 extra_customization_choices, device_settings):
        super(ExtraCustomization, self).__init__()

        debug_print(
            "ExtraCustomization.__init__ - extra_customization_message=",
            extra_customization_message)
        debug_print(
            "ExtraCustomization.__init__ - extra_customization_choices=",
            extra_customization_choices)
        debug_print(
            "ExtraCustomization.__init__ - device_settings.extra_customization=",
            device_settings.extra_customization)
        debug_print("ExtraCustomization.__init__ - device_settings=",
                    device_settings)
        self.extra_customization_message = extra_customization_message

        self.l = QVBoxLayout(self)
        self.setLayout(self.l)

        options_group = QGroupBox(_("Extra driver customization options"),
                                  self)
        self.l.addWidget(options_group)
        self.extra_layout = QGridLayout()
        self.extra_layout.setObjectName("extra_layout")
        options_group.setLayout(self.extra_layout)

        if extra_customization_message:
            extra_customization_choices = extra_customization_choices or {}

            def parse_msg(m):
                msg, _, tt = m.partition(':::') if m else ('', '', '')
                return msg.strip(), textwrap.fill(tt.strip(), 100)

            if isinstance(extra_customization_message, list):
                self.opt_extra_customization = []
                if len(extra_customization_message) > 6:
                    row_func = lambda x, y: ((x // 2) * 2) + y
                    col_func = lambda x: x % 2
                else:
                    row_func = lambda x, y: x * 2 + y
                    col_func = lambda x: 0

                for i, m in enumerate(extra_customization_message):
                    label_text, tt = parse_msg(m)
                    if not label_text:
                        self.opt_extra_customization.append(None)
                        continue
                    if isinstance(device_settings.extra_customization[i],
                                  bool):
                        self.opt_extra_customization.append(
                            QCheckBox(label_text))
                        self.opt_extra_customization[-1].setToolTip(tt)
                        self.opt_extra_customization[i].setChecked(
                            bool(device_settings.extra_customization[i]))
                    elif i in extra_customization_choices:
                        cb = QComboBox(self)
                        self.opt_extra_customization.append(cb)
                        l = QLabel(label_text)
                        l.setToolTip(tt), cb.setToolTip(tt), l.setBuddy(
                            cb), cb.setToolTip(tt)
                        for li in sorted(extra_customization_choices[i]):
                            self.opt_extra_customization[i].addItem(li)
                        cb.setCurrentIndex(
                            max(
                                0,
                                cb.findText(
                                    device_settings.extra_customization[i])))
                    else:
                        self.opt_extra_customization.append(QLineEdit(self))
                        l = QLabel(label_text)
                        l.setToolTip(tt)
                        self.opt_extra_customization[i].setToolTip(tt)
                        l.setBuddy(self.opt_extra_customization[i])
                        l.setWordWrap(True)
                        self.opt_extra_customization[i].setText(
                            device_settings.extra_customization[i])
                        self.opt_extra_customization[i].setCursorPosition(0)
                        self.extra_layout.addWidget(l, row_func(i + 2, 0),
                                                    col_func(i))
                    self.extra_layout.addWidget(
                        self.opt_extra_customization[i], row_func(i + 2, 1),
                        col_func(i))
                spacerItem1 = QSpacerItem(10, 10, QSizePolicy.Policy.Minimum,
                                          QSizePolicy.Policy.Expanding)
                self.extra_layout.addItem(spacerItem1, row_func(i + 2 + 2, 1),
                                          0, 1, 2)
                self.extra_layout.setRowStretch(row_func(i + 2 + 2, 1), 2)
            else:
                self.opt_extra_customization = QLineEdit()
                label_text, tt = parse_msg(extra_customization_message)
                l = QLabel(label_text)
                l.setToolTip(tt)
                l.setBuddy(self.opt_extra_customization)
                l.setWordWrap(True)
                if device_settings.extra_customization:
                    self.opt_extra_customization.setText(
                        device_settings.extra_customization)
                    self.opt_extra_customization.setCursorPosition(0)
                self.opt_extra_customization.setCursorPosition(0)
                self.extra_layout.addWidget(l, 0, 0)
                self.extra_layout.addWidget(self.opt_extra_customization, 1, 0)