Example #1
0
    def genesis(self):
        md = self.qaction.menu()
        cm = partial(self.create_menu_action, md)
        cm('individual', _('Edit metadata individually'), icon=self.qaction.icon(),
                triggered=partial(self.edit_metadata, False, bulk=False))
        cm('bulk', _('Edit metadata in bulk'),
                triggered=partial(self.edit_metadata, False, bulk=True))
        md.addSeparator()
        cm('download', _('Download metadata and covers'),
                triggered=partial(self.download_metadata, ids=None),
                shortcut='Ctrl+D')
        self.metadata_menu = md

        self.metamerge_menu = mb = QMenu()
        cm2 = partial(self.create_menu_action, mb)
        cm2('merge delete', _('Merge into first selected book - delete others'),
                triggered=self.merge_books)
        mb.addSeparator()
        cm2('merge keep', _('Merge into first selected book - keep others'),
                triggered=partial(self.merge_books, safe_merge=True),
                shortcut='Alt+M')
        mb.addSeparator()
        cm2('merge formats', _('Merge only formats into first selected book - delete others'),
                triggered=partial(self.merge_books, merge_only_formats=True),
                shortcut='Alt+Shift+M')
        self.merge_menu = mb
        md.addSeparator()
        self.action_copy = cm('copy', _('Copy metadata'), icon='edit-copy.png', triggered=self.copy_metadata)
        self.action_paset = cm('paste', _('Paste metadata'), icon='edit-paste.png', triggered=self.paste_metadata)
        self.action_merge = cm('merge', _('Merge book records'), icon='merge_books.png',
            shortcut=_('M'), triggered=self.merge_books)
        self.action_merge.setMenu(mb)

        self.qaction.triggered.connect(self.edit_metadata)
        ac = QAction(_('Copy URL to show book in calibre'), self.gui)
        ac.setToolTip(_('Copy URLs to show the currently selected books in calibre, to the system clipboard'))
        ac.triggered.connect(self.copy_show_link)
        self.gui.addAction(ac)
        self.gui.keyboard.register_shortcut(
            self.unique_name + ' - ' + 'copy_show_book',
            ac.text(), description=ac.toolTip(),
            action=ac, group=self.action_spec[0])
        ac = QAction(_('Copy URL to open book in calibre'), self.gui)
        ac.triggered.connect(self.copy_view_link)
        ac.setToolTip(_('Copy URLs to open the currently selected books in calibre, to the system clipboard'))
        self.gui.addAction(ac)
        self.gui.keyboard.register_shortcut(
            self.unique_name + ' - ' + 'copy_view_book',
            ac.text(), description=ac.toolTip(),
            action=ac, group=self.action_spec[0])
Example #2
0
class SearchBarButton(LayoutButton):  # {{{

    def __init__(self, gui):
        sc = 'Alt+Shift+F'
        LayoutButton.__init__(self, I('search.png'), _('Search bar'), parent=gui, shortcut=sc)
        self.set_state_to_hide()
        self.action_toggle = QAction(self.icon(), _('Toggle') + ' ' + self.label, self)
        gui.addAction(self.action_toggle)
        gui.keyboard.register_shortcut('search bar toggle' + self.label, str(self.action_toggle.text()),
                                    default_keys=(sc,), action=self.action_toggle)
        self.action_toggle.triggered.connect(self.toggle)
        self.action_toggle.changed.connect(self.update_shortcut)
        self.toggled.connect(self.update_state)

    def update_state(self, checked):
        if checked:
            self.set_state_to_hide()
        else:
            self.set_state_to_show()

    def save_state(self):
        gprefs['search bar visible'] = bool(self.isChecked())

    def restore_state(self):
        self.setChecked(bool(gprefs.get('search bar visible', True)))
Example #3
0
class GridViewButton(LayoutButton):  # {{{

    def __init__(self, gui):
        sc = 'Alt+Shift+G'
        LayoutButton.__init__(self, I('grid.png'), _('Cover grid'), parent=gui, shortcut=sc)
        self.set_state_to_show()
        self.action_toggle = QAction(self.icon(), _('Toggle') + ' ' + self.label, self)
        gui.addAction(self.action_toggle)
        gui.keyboard.register_shortcut('grid view toggle' + self.label, str(self.action_toggle.text()),
                                    default_keys=(sc,), action=self.action_toggle)
        self.action_toggle.triggered.connect(self.toggle)
        self.action_toggle.changed.connect(self.update_shortcut)
        self.toggled.connect(self.update_state)

    def update_state(self, checked):
        if checked:
            self.set_state_to_hide()
        else:
            self.set_state_to_show()

    def save_state(self):
        gprefs['grid view visible'] = bool(self.isChecked())

    def restore_state(self):
        if gprefs.get('grid view visible', False):
            self.toggle()
Example #4
0
class Splitter(QSplitter):

    state_changed = pyqtSignal(object)
    reapply_sizes = pyqtSignal(object)

    def __init__(self,
                 name,
                 label,
                 icon,
                 initial_show=True,
                 initial_side_size=120,
                 connect_button=True,
                 orientation=Qt.Orientation.Horizontal,
                 side_index=0,
                 parent=None,
                 shortcut=None,
                 hide_handle_on_single_panel=True):
        QSplitter.__init__(self, parent)
        self.reapply_sizes.connect(self.setSizes,
                                   type=Qt.ConnectionType.QueuedConnection)
        self.hide_handle_on_single_panel = hide_handle_on_single_panel
        if hide_handle_on_single_panel:
            self.state_changed.connect(self.update_handle_width)
        self.original_handle_width = self.handleWidth()
        self.resize_timer = QTimer(self)
        self.resize_timer.setSingleShot(True)
        self.desired_side_size = initial_side_size
        self.desired_show = initial_show
        self.resize_timer.setInterval(5)
        self.resize_timer.timeout.connect(self.do_resize)
        self.setOrientation(orientation)
        self.side_index = side_index
        self._name = name
        self.label = label
        self.initial_side_size = initial_side_size
        self.initial_show = initial_show
        self.splitterMoved.connect(self.splitter_moved,
                                   type=Qt.ConnectionType.QueuedConnection)
        self.button = LayoutButton(icon, label, self, shortcut=shortcut)
        if connect_button:
            self.button.clicked.connect(self.double_clicked)

        if shortcut is not None:
            self.action_toggle = QAction(QIcon(icon),
                                         _('Toggle') + ' ' + label, self)
            self.action_toggle.changed.connect(self.update_shortcut)
            self.action_toggle.triggered.connect(self.toggle_triggered)
            if parent is not None:
                parent.addAction(self.action_toggle)
                if hasattr(parent, 'keyboard'):
                    parent.keyboard.register_shortcut(
                        'splitter %s %s' % (name, label),
                        str(self.action_toggle.text()),
                        default_keys=(shortcut, ),
                        action=self.action_toggle)
                else:
                    self.action_toggle.setShortcut(shortcut)
            else:
                self.action_toggle.setShortcut(shortcut)

    def update_shortcut(self):
        self.button.update_shortcut(self.action_toggle)

    def toggle_triggered(self, *args):
        self.toggle_side_pane()

    def createHandle(self):
        return SplitterHandle(self.orientation(), self)

    def initialize(self):
        for i in range(self.count()):
            h = self.handle(i)
            if h is not None:
                h.splitter_moved()
        self.state_changed.emit(not self.is_side_index_hidden)

    def splitter_moved(self, *args):
        self.desired_side_size = self.side_index_size
        self.state_changed.emit(not self.is_side_index_hidden)

    def update_handle_width(self, not_one_panel):
        self.setHandleWidth(self.original_handle_width if not_one_panel else 0)

    @property
    def is_side_index_hidden(self):
        sizes = list(self.sizes())
        try:
            return sizes[self.side_index] == 0
        except IndexError:
            return True

    @property
    def save_name(self):
        ori = 'horizontal' if self.orientation() == Qt.Orientation.Horizontal \
                else 'vertical'
        return self._name + '_' + ori

    def print_sizes(self):
        if self.count() > 1:
            print(self.save_name,
                  'side:',
                  self.side_index_size,
                  'other:',
                  end=' ')
            print(list(self.sizes())[self.other_index])

    @property
    def side_index_size(self):
        if self.count() < 2:
            return 0
        return self.sizes()[self.side_index]

    @side_index_size.setter
    def side_index_size(self, val):
        if self.count() < 2:
            return
        side_index_hidden = self.is_side_index_hidden
        if val == 0 and not side_index_hidden:
            self.save_state()
        sizes = list(self.sizes())
        for i in range(len(sizes)):
            sizes[i] = val if i == self.side_index else 10
        self.setSizes(sizes)
        sizes = list(self.sizes())
        total = sum(sizes)
        total_needs_adjustment = self.hide_handle_on_single_panel and side_index_hidden
        if total_needs_adjustment:
            total -= self.original_handle_width
        for i in range(len(sizes)):
            sizes[i] = val if i == self.side_index else total - val
        self.setSizes(sizes)
        self.initialize()
        if total_needs_adjustment:
            # the handle visibility and therefore size distribution will change
            # when the event loop ticks
            self.reapply_sizes.emit(sizes)

    def do_resize(self, *args):
        orig = self.desired_side_size
        QSplitter.resizeEvent(self, self._resize_ev)
        if orig > 20 and self.desired_show:
            c = 0
            while abs(self.side_index_size - orig) > 10 and c < 5:
                self.apply_state(self.get_state(), save_desired=False)
                c += 1

    def resizeEvent(self, ev):
        if self.resize_timer.isActive():
            self.resize_timer.stop()
        self._resize_ev = ev
        self.resize_timer.start()

    def get_state(self):
        if self.count() < 2:
            return (False, 200)
        return (self.desired_show, self.desired_side_size)

    def apply_state(self, state, save_desired=True):
        if state[0]:
            self.side_index_size = state[1]
            if save_desired:
                self.desired_side_size = self.side_index_size
        else:
            self.side_index_size = 0
        self.desired_show = state[0]

    def default_state(self):
        return (self.initial_show, self.initial_side_size)

    # Public API {{{

    def update_desired_state(self):
        self.desired_show = not self.is_side_index_hidden

    def save_state(self):
        if self.count() > 1:
            gprefs[self.save_name + '_state'] = self.get_state()

    @property
    def other_index(self):
        return (self.side_index + 1) % 2

    def restore_state(self):
        if self.count() > 1:
            state = gprefs.get(self.save_name + '_state', self.default_state())
            self.apply_state(state, save_desired=False)
            self.desired_side_size = state[1]

    def toggle_side_pane(self, hide=None):
        if hide is None:
            action = 'show' if self.is_side_index_hidden else 'hide'
        else:
            action = 'hide' if hide else 'show'
        getattr(self, action + '_side_pane')()

    def show_side_pane(self):
        if self.count() < 2 or not self.is_side_index_hidden:
            return
        if self.desired_side_size == 0:
            self.desired_side_size = self.initial_side_size
        self.apply_state((True, self.desired_side_size))

    def hide_side_pane(self):
        if self.count() < 2 or self.is_side_index_hidden:
            return
        self.apply_state((False, self.desired_side_size))

    def double_clicked(self, *args):
        self.toggle_side_pane()
Example #5
0
    def create_action(self,
                      spec=None,
                      attr='qaction',
                      shortcut_name=None,
                      persist_shortcut=False):
        if spec is None:
            spec = self.action_spec
        text, icon, tooltip, shortcut = spec
        if icon is not None:
            action = QAction(QIcon(I(icon)), text, self.gui)
        else:
            action = QAction(text, self.gui)
        if attr == 'qaction':
            if hasattr(self.action_menu_clone_qaction, 'rstrip'):
                mt = str(self.action_menu_clone_qaction)
            else:
                mt = action.text()
            self.menuless_qaction = ma = QAction(action.icon(), mt, self.gui)
            ma.triggered.connect(action.trigger)
        for a in ((action, ma) if attr == 'qaction' else (action, )):
            a.setAutoRepeat(self.auto_repeat)
            text = tooltip if tooltip else text
            a.setToolTip(text)
            a.setStatusTip(text)
            a.setWhatsThis(text)
        shortcut_action = action
        desc = tooltip if tooltip else None
        if attr == 'qaction':
            shortcut_action = ma
        if shortcut is not None:
            keys = ((shortcut, ) if isinstance(shortcut, string_or_bytes) else
                    tuple(shortcut))
            if shortcut_name is None and spec[0]:
                shortcut_name = str(spec[0])

            if shortcut_name and self.action_spec[0] and not (
                    attr == 'qaction' and self.popup_type
                    == QToolButton.ToolButtonPopupMode.InstantPopup):
                try:
                    self.gui.keyboard.register_shortcut(
                        self.unique_name + ' - ' + attr,
                        shortcut_name,
                        default_keys=keys,
                        action=shortcut_action,
                        description=desc,
                        group=self.action_spec[0],
                        persist_shortcut=persist_shortcut)
                except NameConflict as e:
                    try:
                        prints(str(e))
                    except:
                        pass
                    shortcut_action.setShortcuts([
                        QKeySequence(key,
                                     QKeySequence.SequenceFormat.PortableText)
                        for key in keys
                    ])
                else:
                    self.shortcut_action_for_context_menu = shortcut_action
                    if ismacos:
                        # In Qt 5 keyboard shortcuts dont work unless the
                        # action is explicitly added to the main window
                        self.gui.addAction(shortcut_action)

        if attr is not None:
            setattr(self, attr, action)
        if attr == 'qaction' and self.action_add_menu:
            menu = QMenu()
            action.setMenu(menu)
            if self.action_menu_clone_qaction:
                menu.addAction(self.menuless_qaction)
        return action