Esempio n. 1
0
    def __init__(self, parent):
        orientation = Qt.Orientation.Vertical
        if config['gui_layout'] == 'narrow':
            orientation = Qt.Orientation.Horizontal if is_widescreen() else Qt.Orientation.Vertical
        idx = 0 if orientation == Qt.Orientation.Vertical else 1
        size = 300 if orientation == Qt.Orientation.Vertical else 550
        Splitter.__init__(self, 'cover_browser_splitter', _('Cover browser'),
                I('cover_flow.png'),
                orientation=orientation, parent=parent,
                connect_button=not config['separate_cover_flow'],
                side_index=idx, initial_side_size=size, initial_show=False,
                shortcut='Shift+Alt+B')

        quickview_widget = QWidget()
        parent.quickview_splitter = QuickviewSplitter(
                parent=self, orientation=Qt.Orientation.Vertical, qv_widget=quickview_widget)
        parent.library_view = BooksView(parent)
        parent.library_view.setObjectName('library_view')
        stack = QStackedWidget(self)
        av = parent.library_view.alternate_views
        parent.pin_container = av.set_stack(stack)
        parent.grid_view = GridView(parent)
        parent.grid_view.setObjectName('grid_view')
        av.add_view('grid', parent.grid_view)
        parent.quickview_splitter.addWidget(stack)

        l = QVBoxLayout()
        l.setContentsMargins(4, 0, 0, 0)
        quickview_widget.setLayout(l)
        parent.quickview_splitter.addWidget(quickview_widget)
        parent.quickview_splitter.hide_quickview_widget()

        self.addWidget(parent.quickview_splitter)
Esempio n. 2
0
 def __init__(self, parent):
     QWidget.__init__(self, parent)
     l = QVBoxLayout(parent)
     l.addWidget(self)
     l.setContentsMargins(0, 0, 0, 0)
     l = QFormLayout(self)
     l.setContentsMargins(0, 0, 0, 0)
     l.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.AllNonFixedFieldsGrow)
     self.choices = c = QComboBox()
     c.setMinimumContentsLength(30)
     for text, data in [
             (_('Search for the author on Goodreads'), 'search-goodreads'),
             (_('Search for the author on Amazon'), 'search-amzn'),
             (_('Search for the author in your calibre library'), 'search-calibre'),
             (_('Search for the author on Wikipedia'), 'search-wikipedia'),
             (_('Search for the author on Google Books'), 'search-google'),
             (_('Search for the book on Goodreads'), 'search-goodreads-book'),
             (_('Search for the book on Amazon'), 'search-amzn-book'),
             (_('Search for the book on Google Books'), 'search-google-book'),
             (_('Use a custom search URL'), 'url'),
     ]:
         c.addItem(text, data)
     l.addRow(_('Clicking on &author names should:'), c)
     self.custom_url = u = QLineEdit(self)
     u.setToolTip(_(
         'Enter the URL to search. It should contain the string {0}'
         '\nwhich will be replaced by the author name. For example,'
         '\n{1}').format('{author}', 'https://en.wikipedia.org/w/index.php?search={author}'))
     u.textChanged.connect(self.changed_signal)
     u.setPlaceholderText(_('Enter the URL'))
     c.currentIndexChanged.connect(self.current_changed)
     l.addRow(u)
     self.current_changed()
     c.currentIndexChanged.connect(self.changed_signal)
Esempio n. 3
0
 def __init__(self, parent):
     self.restrict_to_book_ids = frozenset()
     QWidget.__init__(self, parent)
     v = QVBoxLayout(self)
     v.setContentsMargins(0, 0, 0, 0)
     h = QHBoxLayout()
     h.setContentsMargins(0, 0, 0, 0)
     v.addLayout(h)
     self.rla = QLabel(_('Restrict to') + ': ')
     h.addWidget(self.rla)
     la = QLabel(_('Type:'))
     h.addWidget(la)
     self.types_box = tb = QComboBox(self)
     tb.la = la
     tb.currentIndexChanged.connect(self.restrictions_changed)
     connect_lambda(
         tb.currentIndexChanged, tb, lambda tb: gprefs.set(
             'browse_annots_restrict_to_type', tb.currentData()))
     la.setBuddy(tb)
     tb.setToolTip(_('Show only annotations of the specified type'))
     h.addWidget(tb)
     la = QLabel(_('User:'******'browse_annots_restrict_to_user', ub.currentData()))
     la.setBuddy(ub)
     ub.setToolTip(_('Show only annotations created by the specified user'))
     h.addWidget(ub)
     h.addStretch(10)
     h = QHBoxLayout()
     self.restrict_to_books_cb = cb = QCheckBox('')
     self.update_book_restrictions_text()
     cb.setToolTip(
         _('Only show annotations from books that have been selected in the calibre library'
           ))
     cb.setChecked(
         bool(gprefs.get('show_annots_from_selected_books_only', False)))
     cb.stateChanged.connect(self.show_only_selected_changed)
     h.addWidget(cb)
     v.addLayout(h)
Esempio n. 4
0
class TagBrowserWidget(QFrame):  # {{{

    def __init__(self, parent):
        QFrame.__init__(self, parent)
        self.setFrameStyle(QFrame.Shape.NoFrame if gprefs['tag_browser_old_look'] else QFrame.Shape.StyledPanel)
        self._parent = parent
        self._layout = QVBoxLayout(self)
        self._layout.setContentsMargins(0,0,0,0)

        # Set up the find box & button
        self.tb_bar = tbb = TagBrowserBar(self)
        tbb.clear_find.connect(self.reset_find)
        self.alter_tb, self.item_search, self.search_button = tbb.alter_tb, tbb.item_search, tbb.search_button
        self.toggle_search_button = tbb.toggle_search_button
        self._layout.addWidget(tbb)

        self.current_find_position = None
        self.search_button.clicked.connect(self.find)
        self.item_search.lineEdit().textEdited.connect(self.find_text_changed)
        self.item_search.activated[str].connect(self.do_find)

        # The tags view
        parent.tags_view = TagsView(parent)
        self.tags_view = parent.tags_view
        self._layout.insertWidget(0, parent.tags_view)

        # Now the floating 'not found' box
        l = QLabel(self.tags_view)
        self.not_found_label = l
        l.setFrameStyle(QFrame.Shape.StyledPanel)
        l.setAutoFillBackground(True)
        l.setText('<p><b>'+_('No more matches.</b><p> Click Find again to go to first match'))
        l.setAlignment(Qt.AlignmentFlag.AlignVCenter)
        l.setWordWrap(True)
        l.resize(l.sizeHint())
        l.move(10,20)
        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.collapse_all_action = ac = QAction(parent)
        parent.addAction(ac)
        parent.keyboard.register_shortcut('tag browser collapse all',
                _('Collapse all'), default_keys=(),
                action=ac, group=_('Tag browser'))
        connect_lambda(ac.triggered, self, lambda self: self.tags_view.collapseAll())

        # The Configure Tag Browser button
        l = self.alter_tb
        ac = QAction(parent)
        parent.addAction(ac)
        parent.keyboard.register_shortcut('tag browser alter',
                _('Configure Tag browser'), default_keys=(),
                action=ac, group=_('Tag browser'))
        ac.triggered.connect(l.showMenu)

        l.m.aboutToShow.connect(self.about_to_show_configure_menu)
        l.m.show_counts_action = ac = l.m.addAction('counts')
        ac.triggered.connect(self.toggle_counts)
        l.m.show_avg_rating_action = ac = l.m.addAction('avg rating')
        ac.triggered.connect(self.toggle_avg_rating)
        sb = l.m.addAction(_('Sort by'))
        sb.m = l.sort_menu = QMenu(l.m)
        sb.setMenu(sb.m)
        sb.bg = QActionGroup(sb)

        # Must be in the same order as db2.CATEGORY_SORTS
        for i, x in enumerate((_('Name'), _('Number of books'),
                  _('Average rating'))):
            a = sb.m.addAction(x)
            sb.bg.addAction(a)
            a.setCheckable(True)
            if i == 0:
                a.setChecked(True)
        sb.setToolTip(
                _('Set the sort order for entries in the Tag browser'))
        sb.setStatusTip(sb.toolTip())

        ma = l.m.addAction(_('Search type when selecting multiple items'))
        ma.m = l.match_menu = QMenu(l.m)
        ma.setMenu(ma.m)
        ma.ag = QActionGroup(ma)

        # Must be in the same order as db2.MATCH_TYPE
        for i, x in enumerate((_('Match any of the items'), _('Match all of the items'))):
            a = ma.m.addAction(x)
            ma.ag.addAction(a)
            a.setCheckable(True)
            if i == 0:
                a.setChecked(True)
        ma.setToolTip(
                _('When selecting multiple entries in the Tag browser '
                    'match any or all of them'))
        ma.setStatusTip(ma.toolTip())

        mt = l.m.addAction(_('Manage authors, tags, etc.'))
        mt.setToolTip(_('All of these category_managers are available by right-clicking '
                       'on items in the Tag browser above'))
        mt.m = l.manage_menu = QMenu(l.m)
        mt.setMenu(mt.m)

        ac = QAction(parent)
        parent.addAction(ac)
        parent.keyboard.register_shortcut('tag browser toggle item',
                _("'Click' found item"), default_keys=(),
                action=ac, group=_('Tag browser'))
        ac.triggered.connect(self.toggle_item)

        ac = QAction(parent)
        parent.addAction(ac)
        parent.keyboard.register_shortcut('tag browser set focus',
                _("Give the Tag browser keyboard focus"), default_keys=(),
                action=ac, group=_('Tag browser'))
        ac.triggered.connect(self.give_tb_focus)

        # self.leak_test_timer = QTimer(self)
        # self.leak_test_timer.timeout.connect(self.test_for_leak)
        # self.leak_test_timer.start(5000)

    def about_to_show_configure_menu(self):
        ac = self.alter_tb.m.show_counts_action
        ac.setText(_('Hide counts') if gprefs['tag_browser_show_counts'] else _('Show counts'))
        ac = self.alter_tb.m.show_avg_rating_action
        ac.setText(_('Hide average rating') if config['show_avg_rating'] else _('Show average rating'))

    def toggle_counts(self):
        gprefs['tag_browser_show_counts'] ^= True

    def toggle_avg_rating(self):
        config['show_avg_rating'] ^= True

    def save_state(self):
        gprefs.set('tag browser search box visible', self.toggle_search_button.isChecked())

    def toggle_item(self):
        self.tags_view.toggle_current_index()

    def give_tb_focus(self, *args):
        if gprefs['tag_browser_allow_keyboard_focus']:
            tb = self.tags_view
            if tb.hasFocus():
                self._parent.shift_esc()
            elif self._parent.current_view() == self._parent.library_view:
                tb.setFocus()
                idx = tb.currentIndex()
                if not idx.isValid():
                    idx = tb.model().createIndex(0, 0)
                    tb.setCurrentIndex(idx)

    def set_pane_is_visible(self, to_what):
        self.tags_view.set_pane_is_visible(to_what)
        if not to_what:
            self._parent.shift_esc()

    def find_text_changed(self, str_):
        self.current_find_position = None

    def set_focus_to_find_box(self):
        self.tb_bar.set_focus_to_find_box()

    def do_find(self, str_=None):
        self.current_find_position = None
        self.find()

    @property
    def find_text(self):
        return str(self.item_search.currentText()).strip()

    def reset_find(self):
        model = self.tags_view.model()
        model.clear_boxed()
        if model.get_categories_filter():
            model.set_categories_filter(None)
            self.tags_view.recount()
            self.current_find_position = None

    def find(self):
        model = self.tags_view.model()
        model.clear_boxed()

        # When a key is specified don't use the auto-collapsing search.
        # A colon separates the lookup key from the search string.
        # A leading colon says not to use autocollapsing search but search all keys
        txt = self.find_text
        colon = txt.find(':')
        if colon >= 0:
            key = self._parent.library_view.model().db.\
                        field_metadata.search_term_to_field_key(txt[:colon])
            if key in self._parent.library_view.model().db.field_metadata:
                txt = txt[colon+1:]
            else:
                key = ''
                txt = txt[1:] if colon == 0 else txt
        else:
            key = None

        # key is None indicates that no colon was found.
        # key == '' means either a leading : was found or the key is invalid

        # At this point the txt might have a leading =, in which case do an
        # exact match search

        if (gprefs.get('tag_browser_always_autocollapse', False) and
                key is None and not txt.startswith('*')):
            txt = '*' + txt
        if txt.startswith('*'):
            self.tags_view.collapseAll()
            model.set_categories_filter(txt[1:])
            self.tags_view.recount()
            self.current_find_position = None
            return
        if model.get_categories_filter():
            model.set_categories_filter(None)
            self.tags_view.recount()
            self.current_find_position = None

        if not txt:
            return

        self.item_search.lineEdit().blockSignals(True)
        self.search_button.setFocus(True)
        self.item_search.lineEdit().blockSignals(False)

        if txt.startswith('='):
            equals_match = True
            txt = txt[1:]
        else:
            equals_match = False
        self.current_find_position = \
            model.find_item_node(key, txt, self.current_find_position,
                                 equals_match=equals_match)

        if self.current_find_position:
            self.tags_view.show_item_at_path(self.current_find_position, box=True)
        elif self.item_search.text():
            self.not_found_label.setVisible(True)
            if self.tags_view.verticalScrollBar().isVisible():
                sbw = self.tags_view.verticalScrollBar().width()
            else:
                sbw = 0
            width = self.width() - 8 - sbw
            height = self.not_found_label.heightForWidth(width) + 20
            self.not_found_label.resize(width, height)
            self.not_found_label.move(4, 10)
            self.not_found_label_timer.start(2000)

    def not_found_label_timer_event(self):
        self.not_found_label.setVisible(False)

    def keyPressEvent(self, ev):
        if ev.key() in (Qt.Key.Key_Enter, Qt.Key.Key_Return) and self.item_search.hasFocus():
            self.find()
            ev.accept()
            return
        return QFrame.keyPressEvent(self, ev)