コード例 #1
0
    def init_search_restriction_mixin(self):
        self.checked = QIcon(I('ok.png'))
        self.empty = QIcon(I('blank.png'))
        self.current_search_action = QAction(self.empty, _('*current search'), self)
        self.current_search_action.triggered.connect(partial(self.apply_virtual_library, library='*'))
        self.addAction(self.current_search_action)
        self.keyboard.register_shortcut(
            'vl-from-current-search', _('Virtual library from current search'), description=_(
                'Create a temporary Virtual library from the current search'), group=pgettext('search restriction group name', 'Miscellaneous'),
            default_keys=('Ctrl+*',), action=self.current_search_action)

        self.search_based_vl_name = None
        self.search_based_vl = None

        self.virtual_library_menu = QMenu(self.virtual_library)
        self.virtual_library.setMenu(self.virtual_library_menu)
        self.virtual_library_menu.aboutToShow.connect(self.virtual_library_menu_about_to_show)

        self.clear_vl.clicked.connect(lambda x: (self.apply_virtual_library(), self.clear_additional_restriction()))

        self.virtual_library_tooltip = \
            _('Use a "Virtual library" to show only a subset of the books present in this library')
        self.virtual_library.setToolTip(self.virtual_library_tooltip)

        self.search_restriction = ComboBoxWithHelp(self)
        self.search_restriction.setVisible(False)
        self.clear_vl.setText(_("(all books)"))
        self.ar_menu = QMenu(_('Additional restriction'), self.virtual_library_menu)
        self.edit_menu = QMenu(_('Edit Virtual library'), self.virtual_library_menu)
        self.rm_menu = QMenu(_('Remove Virtual library'), self.virtual_library_menu)
        self.search_restriction_list_built = False
コード例 #2
0
    def init_search_restirction_mixin(self):
        self.checked = QIcon(I('ok.png'))
        self.empty = QIcon(I('blank.png'))
        self.current_search_action = QAction(self.empty, _('*current search'), self)
        self.current_search_action.triggered.connect(partial(self.apply_virtual_library, library='*'))
        self.addAction(self.current_search_action)
        self.keyboard.register_shortcut(
            'vl-from-current-search', _('Virtual library from current search'), description=_(
                'Create a temporary Virtual library from the current search'), group=_('Miscellaneous'),
            default_keys=('Ctrl+*',), action=self.current_search_action)

        self.search_based_vl_name = None
        self.search_based_vl = None

        self.virtual_library_menu = QMenu()

        self.virtual_library.clicked.connect(self.virtual_library_clicked)
        self.clear_vl.clicked.connect(lambda x: (self.apply_virtual_library(), self.clear_additional_restriction()))

        self.virtual_library_tooltip = \
            _('Use a "virtual library" to show only a subset of the books present in this library')
        self.virtual_library.setToolTip(self.virtual_library_tooltip)

        self.search_restriction = ComboBoxWithHelp(self)
        self.search_restriction.setVisible(False)
        self.search_count.setText(_("(all books)"))
        self.ar_menu = QMenu(_('Additional restriction'))
        self.edit_menu = QMenu(_('Edit Virtual Library'))
        self.rm_menu = QMenu(_('Remove Virtual Library'))
        self.search_restriction_list_built = False
コード例 #3
0
    def __init__(self):
        self.checked = QIcon(I('ok.png'))
        self.empty = QIcon(I('blank.png'))
        self.search_based_vl_name = None
        self.search_based_vl = None

        self.virtual_library_menu = QMenu()

        self.virtual_library.clicked.connect(self.virtual_library_clicked)

        self.virtual_library_tooltip = \
            _('Use a "virtual library" to show only a subset of the books present in this library')
        self.virtual_library.setToolTip(self.virtual_library_tooltip)

        self.search_restriction = ComboBoxWithHelp(self)
        self.search_restriction.setVisible(False)
        self.search_count.setText(_("(all books)"))
        self.ar_menu = QMenu(_('Additional restriction'))
        self.edit_menu = QMenu(_('Edit Virtual Library'))
        self.rm_menu = QMenu(_('Remove Virtual Library'))
コード例 #4
0
    def __init__(self):
        self.checked = QIcon(I('ok.png'))
        self.empty = QIcon(I('blank.png'))
        self.search_based_vl_name = None
        self.search_based_vl = None

        self.virtual_library_menu = QMenu()

        self.virtual_library.clicked.connect(self.virtual_library_clicked)

        self.virtual_library_tooltip = \
            _('Use a "virtual library" to show only a subset of the books present in this library')
        self.virtual_library.setToolTip(self.virtual_library_tooltip)

        self.search_restriction = ComboBoxWithHelp(self)
        self.search_restriction.setVisible(False)
        self.search_count.setText(_("(all books)"))
        self.ar_menu = QMenu(_('Additional restriction'))
        self.edit_menu = QMenu(_('Edit Virtual Library'))
        self.rm_menu = QMenu(_('Remove Virtual Library'))
コード例 #5
0
class SearchRestrictionMixin:

    no_restriction = '<' + _('None') + '>'

    def __init__(self, *args, **kwargs):
        pass

    def init_search_restriction_mixin(self):
        self.checked = QIcon(I('ok.png'))
        self.empty = QIcon(I('blank.png'))
        self.current_search_action = QAction(self.empty, _('*current search'), self)
        self.current_search_action.triggered.connect(partial(self.apply_virtual_library, library='*'))
        self.addAction(self.current_search_action)
        self.keyboard.register_shortcut(
            'vl-from-current-search', _('Virtual library from current search'), description=_(
                'Create a temporary Virtual library from the current search'), group=pgettext('search restriction group name', 'Miscellaneous'),
            default_keys=('Ctrl+*',), action=self.current_search_action)

        self.search_based_vl_name = None
        self.search_based_vl = None

        self.virtual_library_menu = QMenu(self.virtual_library)
        self.virtual_library.setMenu(self.virtual_library_menu)
        self.virtual_library_menu.aboutToShow.connect(self.virtual_library_menu_about_to_show)

        self.clear_vl.clicked.connect(lambda x: (self.apply_virtual_library(), self.clear_additional_restriction()))

        self.virtual_library_tooltip = \
            _('Use a "Virtual library" to show only a subset of the books present in this library')
        self.virtual_library.setToolTip(self.virtual_library_tooltip)

        self.search_restriction = ComboBoxWithHelp(self)
        self.search_restriction.setVisible(False)
        self.clear_vl.setText(_("(all books)"))
        self.ar_menu = QMenu(_('Additional restriction'), self.virtual_library_menu)
        self.edit_menu = QMenu(_('Edit Virtual library'), self.virtual_library_menu)
        self.rm_menu = QMenu(_('Remove Virtual library'), self.virtual_library_menu)
        self.search_restriction_list_built = False

    def add_virtual_library(self, db, name, search):
        virt_libs = db.new_api.pref('virtual_libraries', {})
        virt_libs[name] = search
        db.new_api.set_pref('virtual_libraries', virt_libs)
        db.new_api.clear_search_caches()
        self.library_view.model().db.refresh()

    def do_create_edit(self, name=None):
        db = self.library_view.model().db
        virt_libs = db.new_api.pref('virtual_libraries', {})
        cd = CreateVirtualLibrary(self, virt_libs.keys(), editing=name)
        if cd.exec() == QDialog.DialogCode.Accepted:
            if name:
                self._remove_vl(name, reapply=False)
            self.add_virtual_library(db, cd.library_name, cd.library_search)
            if not name or name == db.data.get_base_restriction_name():
                self.apply_virtual_library(cd.library_name)
            self.rebuild_vl_tabs()

    def build_virtual_library_menu(self, m, add_tabs_action=True):
        m.clear()

        a = m.addAction(QIcon.ic('plus.png'), _('Create Virtual library'))
        a.triggered.connect(partial(self.do_create_edit, name=None))
        db = self.current_db
        virt_libs = db.new_api.pref('virtual_libraries', {})

        a = self.edit_menu
        self.build_virtual_library_list(a, self.do_create_edit)
        if virt_libs:
            m.addMenu(a).setIcon(QIcon.ic('edit_input.png'))

        a = self.rm_menu
        self.build_virtual_library_list(a, self.remove_vl_triggered)
        if virt_libs:
            m.addMenu(a).setIcon(QIcon.ic('minus.png'))

        if virt_libs:
            m.addAction(QIcon.ic('toc.png'), _('Quick select Virtual library'), self.choose_vl_triggerred)

        if add_tabs_action:
            if gprefs['show_vl_tabs']:
                m.addAction(_('Hide Virtual library tabs'), self.vl_tabs.disable_bar)
            else:
                m.addAction(_('Show Virtual libraries as tabs'), self.vl_tabs.enable_bar)

        m.addSeparator()

        a = self.ar_menu
        a.clear()
        a.setIcon(self.checked if db.data.get_search_restriction_name() else self.empty)
        self.build_search_restriction_list()
        m.addMenu(a)

        m.addSeparator()

        current_lib = db.data.get_base_restriction_name()

        if not current_lib:
            a = m.addAction(self.checked, self.no_restriction)
        else:
            a = m.addAction(self.empty, self.no_restriction)
        a.triggered.connect(partial(self.apply_virtual_library, library=''))

        a = m.addAction(self.current_search_action)

        if self.search_based_vl_name:
            a = m.addAction(
                self.checked if db.data.get_base_restriction_name().startswith('*') else self.empty,
                self.search_based_vl_name)
            a.triggered.connect(partial(self.apply_virtual_library,
                                library=self.search_based_vl_name))

        m.addSeparator()

        for vl in sorted(virt_libs.keys(), key=sort_key):
            is_current = vl == current_lib
            a = m.addAction(self.checked if is_current else self.empty, vl.replace('&', '&&'))
            if is_current:
                a.triggered.connect(self.apply_virtual_library)
            else:
                a.triggered.connect(partial(self.apply_virtual_library, library=vl))

    def virtual_library_menu_about_to_show(self):
        self.build_virtual_library_menu(self.virtual_library_menu)

    def rebuild_vl_tabs(self):
        self.vl_tabs.rebuild()

    def apply_virtual_library(self, library=None, update_tabs=True):
        db = self.library_view.model().db
        virt_libs = db.new_api.pref('virtual_libraries', {})
        if not library:
            db.data.set_base_restriction('')
            db.data.set_base_restriction_name('')
        elif library == '*':
            if not self.search.current_text:
                error_dialog(self, _('No search'),
                     _('There is no current search to use'), show=True)
                return

            txt = _build_full_search_string(self)
            try:
                db.data.search_getting_ids('', txt, use_virtual_library=False)
            except ParseException as e:
                error_dialog(self, _('Invalid search'),
                             _('The search in the search box is not valid'),
                             det_msg=e.msg, show=True)
                return

            self.search_based_vl = txt
            db.data.set_base_restriction(txt)
            self.search_based_vl_name = self._trim_restriction_name('*' + txt)
            db.data.set_base_restriction_name(self.search_based_vl_name)
        elif library == self.search_based_vl_name:
            db.data.set_base_restriction(self.search_based_vl)
            db.data.set_base_restriction_name(self.search_based_vl_name)
        elif library in virt_libs:
            db.data.set_base_restriction(virt_libs[library])
            db.data.set_base_restriction_name(library)
        self.virtual_library.setToolTip(self.virtual_library_tooltip + '\n' +
                                        db.data.get_base_restriction())
        self._apply_search_restriction(db.data.get_search_restriction(),
                                       db.data.get_search_restriction_name())
        if update_tabs:
            self.vl_tabs.update_current()

    def build_virtual_library_list(self, menu, handler):
        db = self.library_view.model().db
        virt_libs = db.new_api.pref('virtual_libraries', {})
        menu.clear()
        menu.setIcon(self.empty)

        def add_action(name, search):
            a = menu.addAction(name.replace('&', '&&'))
            a.triggered.connect(partial(handler, name=name))
            a.setIcon(self.empty)

        libs = sorted(virt_libs.keys(), key=sort_key)
        if libs:
            menu.setEnabled(True)
            for n in libs:
                add_action(n, virt_libs[n])
        else:
            menu.setEnabled(False)

    def remove_vl_triggered(self, name=None):
        if not confirm(
            _('Are you sure you want to remove the Virtual library <b>{0}</b>?').format(name),
            'confirm_vl_removal', parent=self):
            return
        self._remove_vl(name, reapply=True)
        self.library_view.model().db.refresh()

    def choose_vl_triggerred(self):
        from calibre.gui2.tweak_book.widgets import QuickOpen, emphasis_style
        db = self.library_view.model().db
        virt_libs = db.new_api.pref('virtual_libraries', {})
        if not virt_libs:
            return error_dialog(self, _('No Virtual libraries'), _(
                'No Virtual libraries present, create some first'), show=True)
        example = '<pre>{0}S{1}ome {0}B{1}ook {0}C{1}ollection</pre>'.format(
            '<span style="%s">' % emphasis_style(), '</span>')
        chars = '<pre style="%s">sbc</pre>' % emphasis_style()
        help_text = _('''<p>Quickly choose a Virtual library by typing in just a few characters from the library name into the field above.
        For example, if want to choose the VL:
        {example}
        Simply type in the characters:
        {chars}
        and press Enter.''').format(example=example, chars=chars)

        d = QuickOpen(
                sorted(virt_libs.keys(), key=sort_key), parent=self, title=_('Choose Virtual library'),
                name='vl-open', level1=' ', help_text=help_text)
        if d.exec() == QDialog.DialogCode.Accepted and d.selected_result:
            self.apply_virtual_library(library=d.selected_result)

    def _remove_vl(self, name, reapply=True):
        db = self.library_view.model().db
        virt_libs = db.new_api.pref('virtual_libraries', {})
        virt_libs.pop(name, None)
        db.new_api.set_pref('virtual_libraries', virt_libs)
        if reapply and db.data.get_base_restriction_name() == name:
            self.apply_virtual_library('')
        self.rebuild_vl_tabs()

    def _trim_restriction_name(self, name):
        return name[0:MAX_VIRTUAL_LIBRARY_NAME_LENGTH].strip()

    def build_search_restriction_list(self):
        self.search_restriction_list_built = True
        from calibre.gui2.ui import get_gui
        m = self.ar_menu
        m.clear()

        current_restriction_text = None

        if self.search_restriction.count() > 1:
            txt = str(self.search_restriction.itemText(2))
            if txt.startswith('*'):
                current_restriction_text = txt
        self.search_restriction.clear()

        current_restriction = self.library_view.model().db.data.get_search_restriction_name()
        m.setIcon(self.checked if current_restriction else self.empty)

        def add_action(txt, index):
            self.search_restriction.addItem(txt)
            txt = self._trim_restriction_name(txt)
            if txt == current_restriction:
                a = m.addAction(self.checked, txt if txt else self.no_restriction)
            else:
                a = m.addAction(self.empty, txt if txt else self.no_restriction)
            a.triggered.connect(partial(self.search_restriction_triggered,
                                        action=a, index=index))

        add_action('', 0)
        add_action(_('*current search'), 1)
        dex = 2
        if current_restriction_text:
            add_action(current_restriction_text, 2)
            dex += 1

        for n in sorted(get_gui().current_db.saved_search_names(), key=sort_key):
            add_action(n, dex)
            dex += 1

    def search_restriction_triggered(self, action=None, index=None):
        self.search_restriction.setCurrentIndex(index)
        self.apply_search_restriction(index)

    def apply_named_search_restriction(self, name=None):
        if not self.search_restriction_list_built:
            self.build_search_restriction_list()
        if not name:
            r = 0
        else:
            r = self.search_restriction.findText(name)
            if r < 0:
                r = 0
        self.search_restriction.setCurrentIndex(r)
        self.apply_search_restriction(r)

    def apply_text_search_restriction(self, search):
        if not self.search_restriction_list_built:
            self.build_search_restriction_list()
        search = str(search)
        if not search:
            self.search_restriction.setCurrentIndex(0)
            self._apply_search_restriction('', '')
        else:
            s = '*' + search
            if self.search_restriction.count() > 1:
                txt = str(self.search_restriction.itemText(2))
                if txt.startswith('*'):
                    self.search_restriction.setItemText(2, s)
                else:
                    self.search_restriction.insertItem(2, s)
            else:
                self.search_restriction.insertItem(2, s)
            self.search_restriction.setCurrentIndex(2)
            self._apply_search_restriction(search, self._trim_restriction_name(s))

    def apply_search_restriction(self, i):
        if not self.search_restriction_list_built:
            self.build_search_restriction_list()
        if i == 1:
            self.apply_text_search_restriction(str(self.search.currentText()))
        elif i == 2 and str(self.search_restriction.currentText()).startswith('*'):
            self.apply_text_search_restriction(
                                str(self.search_restriction.currentText())[1:])
        else:
            r = str(self.search_restriction.currentText())
            if r is not None and r != '':
                restriction = 'search:"%s"'%(r)
            else:
                restriction = ''
            self._apply_search_restriction(restriction, r)

    def clear_additional_restriction(self):
        self.search_restriction.setCurrentIndex(0)
        self._apply_search_restriction('', '')

    def _apply_search_restriction(self, restriction, name):
        self.saved_search.clear()
        # The order below is important. Set the restriction, force a '' search
        # to apply it, reset the tag browser to take it into account, then set
        # the book count.
        self.library_view.model().db.data.set_search_restriction(restriction)
        self.library_view.model().db.data.set_search_restriction_name(name)
        self.search.clear(emit_search=True)
        self.tags_view.recount()
        self.set_number_of_books_shown()
        self.current_view().setFocus(Qt.FocusReason.OtherFocusReason)
        self.set_window_title()
        v = self.current_view()
        if not v.currentIndex().isValid():
            v.set_current_row()
        if not v.refresh_book_details():
            self.book_details.reset_info()

    def set_number_of_books_shown(self):
        db = self.library_view.model().db
        if self.current_view() == self.library_view and db is not None and \
                                            db.data.search_restriction_applied():
            restrictions = [x for x in (db.data.get_base_restriction_name(),
                            db.data.get_search_restriction_name()) if x]
            t = ' :: '.join(restrictions)
            if len(t) > 20:
                t = t[:19] + '…'
            self.clear_vl.setVisible(True)
            self.clear_vl.setVisible(not gprefs['show_vl_tabs'])
        else:  # No restriction or not library view
            t = ''
            self.clear_vl.setVisible(False)
        self.clear_vl.setText(t.replace('&', '&&'))
コード例 #6
0
class SearchRestrictionMixin(object):

    no_restriction = _('<None>')

    def __init__(self, *args, **kwargs):
        pass

    def init_search_restirction_mixin(self):
        self.checked = QIcon(I('ok.png'))
        self.empty = QIcon(I('blank.png'))
        self.current_search_action = QAction(self.empty, _('*current search'), self)
        self.current_search_action.triggered.connect(partial(self.apply_virtual_library, library='*'))
        self.addAction(self.current_search_action)
        self.keyboard.register_shortcut(
            'vl-from-current-search', _('Virtual library from current search'), description=_(
                'Create a temporary Virtual library from the current search'), group=_('Miscellaneous'),
            default_keys=('Ctrl+*',), action=self.current_search_action)

        self.search_based_vl_name = None
        self.search_based_vl = None

        self.virtual_library_menu = QMenu()

        self.virtual_library.clicked.connect(self.virtual_library_clicked)
        self.clear_vl.clicked.connect(lambda x: (self.apply_virtual_library(), self.clear_additional_restriction()))

        self.virtual_library_tooltip = \
            _('Use a "virtual library" to show only a subset of the books present in this library')
        self.virtual_library.setToolTip(self.virtual_library_tooltip)

        self.search_restriction = ComboBoxWithHelp(self)
        self.search_restriction.setVisible(False)
        self.search_count.setText(_("(all books)"))
        self.ar_menu = QMenu(_('Additional restriction'))
        self.edit_menu = QMenu(_('Edit Virtual Library'))
        self.rm_menu = QMenu(_('Remove Virtual Library'))
        self.search_restriction_list_built = False

    def add_virtual_library(self, db, name, search):
        virt_libs = db.prefs.get('virtual_libraries', {})
        virt_libs[name] = search
        db.prefs.set('virtual_libraries', virt_libs)

    def do_create_edit(self, name=None):
        db = self.library_view.model().db
        virt_libs = db.prefs.get('virtual_libraries', {})
        cd = CreateVirtualLibrary(self, virt_libs.keys(), editing=name)
        if cd.exec_() == cd.Accepted:
            if name:
                self._remove_vl(name, reapply=False)
            self.add_virtual_library(db, cd.library_name, cd.library_search)
            if not name or name == db.data.get_base_restriction_name():
                self.apply_virtual_library(cd.library_name)
            self.rebuild_vl_tabs()

    def virtual_library_clicked(self):
        m = self.virtual_library_menu
        m.clear()

        a = m.addAction(_('Create Virtual Library'))
        a.triggered.connect(partial(self.do_create_edit, name=None))

        a = self.edit_menu
        self.build_virtual_library_list(a, self.do_create_edit)
        m.addMenu(a)

        a = self.rm_menu
        self.build_virtual_library_list(a, self.remove_vl_triggered)
        m.addMenu(a)

        if gprefs['show_vl_tabs']:
            m.addAction(_('Hide virtual library tabs'), self.vl_tabs.disable_bar)
        else:
            m.addAction(_('Show virtual libraries as tabs'), self.vl_tabs.enable_bar)

        m.addSeparator()

        db = self.library_view.model().db

        a = self.ar_menu
        a.clear()
        a.setIcon(self.checked if db.data.get_search_restriction_name() else self.empty)
        self.build_search_restriction_list()
        m.addMenu(a)

        m.addSeparator()

        current_lib = db.data.get_base_restriction_name()

        if current_lib == '':
            a = m.addAction(self.checked, self.no_restriction)
        else:
            a = m.addAction(self.empty, self.no_restriction)
        a.triggered.connect(partial(self.apply_virtual_library, library=''))

        a = m.addAction(self.current_search_action)

        if self.search_based_vl_name:
            a = m.addAction(
                self.checked if db.data.get_base_restriction_name().startswith('*') else self.empty,
                self.search_based_vl_name)
            a.triggered.connect(partial(self.apply_virtual_library,
                                library=self.search_based_vl_name))

        m.addSeparator()

        virt_libs = db.prefs.get('virtual_libraries', {})
        for vl in sorted(virt_libs.keys(), key=sort_key):
            a = m.addAction(self.checked if vl == current_lib else self.empty, vl.replace('&', '&&'))
            a.triggered.connect(partial(self.apply_virtual_library, library=vl))

        p = QPoint(0, self.virtual_library.height())
        self.virtual_library_menu.popup(self.virtual_library.mapToGlobal(p))

    def rebuild_vl_tabs(self):
        self.vl_tabs.rebuild()

    def apply_virtual_library(self, library=None, update_tabs=True):
        db = self.library_view.model().db
        virt_libs = db.prefs.get('virtual_libraries', {})
        if not library:
            db.data.set_base_restriction('')
            db.data.set_base_restriction_name('')
        elif library == '*':
            if not self.search.current_text:
                error_dialog(self, _('No search'),
                     _('There is no current search to use'), show=True)
                return

            txt = _build_full_search_string(self)
            try:
                db.data.search_getting_ids('', txt, use_virtual_library=False)
            except ParseException as e:
                error_dialog(self, _('Invalid search'),
                             _('The search in the search box is not valid'),
                             det_msg=e.msg, show=True)
                return

            self.search_based_vl = txt
            db.data.set_base_restriction(txt)
            self.search_based_vl_name = self._trim_restriction_name('*' + txt)
            db.data.set_base_restriction_name(self.search_based_vl_name)
        elif library == self.search_based_vl_name:
            db.data.set_base_restriction(self.search_based_vl)
            db.data.set_base_restriction_name(self.search_based_vl_name)
        elif library in virt_libs:
            db.data.set_base_restriction(virt_libs[library])
            db.data.set_base_restriction_name(library)
        self.virtual_library.setToolTip(self.virtual_library_tooltip + '\n' +
                                        db.data.get_base_restriction())
        self._apply_search_restriction(db.data.get_search_restriction(),
                                       db.data.get_search_restriction_name())
        if update_tabs:
            self.vl_tabs.update_current()

    def build_virtual_library_list(self, menu, handler):
        db = self.library_view.model().db
        virt_libs = db.prefs.get('virtual_libraries', {})
        menu.clear()
        menu.setIcon(self.empty)

        def add_action(name, search):
            a = menu.addAction(name.replace('&', '&&'))
            a.triggered.connect(partial(handler, name=name))
            a.setIcon(self.empty)

        libs = sorted(virt_libs.keys(), key=sort_key)
        if libs:
            menu.setEnabled(True)
            for n in libs:
                add_action(n, virt_libs[n])
        else:
            menu.setEnabled(False)

    def remove_vl_triggered(self, name=None):
        if not confirm(
            _('Are you sure you want to remove the virtual library <b>{0}</b>?').format(name),
            'confirm_vl_removal', parent=self):
            return
        self._remove_vl(name, reapply=True)

    def _remove_vl(self, name, reapply=True):
        db = self.library_view.model().db
        virt_libs = db.prefs.get('virtual_libraries', {})
        virt_libs.pop(name, None)
        db.prefs.set('virtual_libraries', virt_libs)
        if reapply and db.data.get_base_restriction_name() == name:
            self.apply_virtual_library('')
        self.rebuild_vl_tabs()

    def _trim_restriction_name(self, name):
        return name[0:MAX_VIRTUAL_LIBRARY_NAME_LENGTH].strip()

    def build_search_restriction_list(self):
        self.search_restriction_list_built = True
        from calibre.gui2.ui import get_gui
        m = self.ar_menu
        m.clear()

        current_restriction_text = None

        if self.search_restriction.count() > 1:
            txt = unicode(self.search_restriction.itemText(2))
            if txt.startswith('*'):
                current_restriction_text = txt
        self.search_restriction.clear()

        current_restriction = self.library_view.model().db.data.get_search_restriction_name()
        m.setIcon(self.checked if current_restriction else self.empty)

        def add_action(txt, index):
            self.search_restriction.addItem(txt)
            txt = self._trim_restriction_name(txt)
            if txt == current_restriction:
                a = m.addAction(self.checked, txt if txt else self.no_restriction)
            else:
                a = m.addAction(self.empty, txt if txt else self.no_restriction)
            a.triggered.connect(partial(self.search_restriction_triggered,
                                        action=a, index=index))

        add_action('', 0)
        add_action(_('*current search'), 1)
        dex = 2
        if current_restriction_text:
            add_action(current_restriction_text, 2)
            dex += 1

        for n in sorted(get_gui().current_db.saved_search_names(), key=sort_key):
            add_action(n, dex)
            dex += 1

    def search_restriction_triggered(self, action=None, index=None):
        self.search_restriction.setCurrentIndex(index)
        self.apply_search_restriction(index)

    def apply_named_search_restriction(self, name):
        if not self.search_restriction_list_built:
            self.build_search_restriction_list()
        if not name:
            r = 0
        else:
            r = self.search_restriction.findText(name)
            if r < 0:
                r = 0
        self.search_restriction.setCurrentIndex(r)
        self.apply_search_restriction(r)

    def apply_text_search_restriction(self, search):
        if not self.search_restriction_list_built:
            self.build_search_restriction_list()
        search = unicode(search)
        if not search:
            self.search_restriction.setCurrentIndex(0)
            self._apply_search_restriction('', '')
        else:
            s = '*' + search
            if self.search_restriction.count() > 1:
                txt = unicode(self.search_restriction.itemText(2))
                if txt.startswith('*'):
                    self.search_restriction.setItemText(2, s)
                else:
                    self.search_restriction.insertItem(2, s)
            else:
                self.search_restriction.insertItem(2, s)
            self.search_restriction.setCurrentIndex(2)
            self._apply_search_restriction(search, self._trim_restriction_name(s))

    def apply_search_restriction(self, i):
        if not self.search_restriction_list_built:
            self.build_search_restriction_list()
        if i == 1:
            self.apply_text_search_restriction(unicode(self.search.currentText()))
        elif i == 2 and unicode(self.search_restriction.currentText()).startswith('*'):
            self.apply_text_search_restriction(
                                unicode(self.search_restriction.currentText())[1:])
        else:
            r = unicode(self.search_restriction.currentText())
            if r is not None and r != '':
                restriction = 'search:"%s"'%(r)
            else:
                restriction = ''
            self._apply_search_restriction(restriction, r)

    def clear_additional_restriction(self):
        self._apply_search_restriction('', '')

    def _apply_search_restriction(self, restriction, name):
        self.saved_search.clear()
        # The order below is important. Set the restriction, force a '' search
        # to apply it, reset the tag browser to take it into account, then set
        # the book count.
        self.library_view.model().db.data.set_search_restriction(restriction)
        self.library_view.model().db.data.set_search_restriction_name(name)
        self.search.clear(emit_search=True)
        self.tags_view.recount()
        self.set_number_of_books_shown()
        self.current_view().setFocus(Qt.OtherFocusReason)
        self.set_window_title()
        v = self.current_view()
        if not v.currentIndex().isValid():
            v.set_current_row()
        if not v.refresh_book_details():
            self.book_details.reset_info()

    def set_number_of_books_shown(self):
        db = self.library_view.model().db
        if self.current_view() == self.library_view and db is not None and \
                                            db.data.search_restriction_applied():
            restrictions = [x for x in (db.data.get_base_restriction_name(),
                            db.data.get_search_restriction_name()) if x]
            t = ' :: '.join(restrictions)
            if len(t) > 20:
                t = t[:19] + u'…'
            self.search_count.setStyleSheet(
                    'QLabel { border-radius: 6px; background-color: %s }' %
                    tweaks['highlight_virtual_library'])
            self.clear_vl.setVisible(True)
            self.search_count.setVisible(not gprefs['show_vl_tabs'])
        else:  # No restriction or not library view
            t = ''
            self.search_count.setStyleSheet(
                    'QLabel { background-color: transparent; }')
            self.clear_vl.setVisible(False)
            self.search_count.setVisible(False)
        self.search_count.setText(t)
コード例 #7
0
    def __init__(self, parent):
        QWidget.__init__(self, parent)
        self._layout = l = QHBoxLayout()
        self.setLayout(self._layout)
        self._layout.setContentsMargins(0, 5, 0, 0)

        x = ComboBoxWithHelp(self)
        x.setMaximumSize(QSize(150, 16777215))
        x.setObjectName("search_restriction")
        l.addWidget(x)
        parent.search_restriction = x

        x = QLabel(self)
        x.setObjectName("search_count")
        l.addWidget(x)
        parent.search_count = x
        x.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

        parent.advanced_search_button = x = QToolButton(self)
        parent.advanced_search_toggle_action = ac = QAction(parent)
        parent.addAction(ac)
        parent.keyboard.register_shortcut('advanced search toggle',
                                          _('Advanced search'),
                                          default_keys=(_("Shift+Ctrl+F"), ),
                                          action=ac)
        ac.triggered.connect(x.click)
        x.setIcon(QIcon(I('search.png')))
        l.addWidget(x)
        x.setToolTip(_("Advanced search"))

        x = parent.search = SearchBox2(self)
        x.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        x.setObjectName("search")
        x.setToolTip(
            _("<p>Search the list of books by title, author, publisher, "
              "tags, comments, etc.<br><br>Words separated by spaces are ANDed"
              ))
        l.addWidget(x)

        self.search_button = QToolButton()
        self.search_button.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.search_button.setText(_('&Go!'))
        l.addWidget(self.search_button)
        self.search_button.setSizePolicy(QSizePolicy.Minimum,
                                         QSizePolicy.Minimum)
        self.search_button.clicked.connect(parent.do_search_button)
        self.search_button.setToolTip(
            _('Do Quick Search (you can also press the Enter key)'))

        x = parent.clear_button = QToolButton(self)
        x.setIcon(QIcon(I('clear_left.png')))
        x.setObjectName("clear_button")
        l.addWidget(x)
        x.setToolTip(_("Reset Quick Search"))

        x = parent.highlight_only_button = QToolButton(self)
        x.setIcon(QIcon(I('arrow-down.png')))
        l.addWidget(x)

        x = parent.saved_search = SavedSearchBox(self)
        x.setMaximumSize(QSize(150, 16777215))
        x.setMinimumContentsLength(15)
        x.setObjectName("saved_search")
        l.addWidget(x)

        x = parent.copy_search_button = QToolButton(self)
        x.setIcon(QIcon(I("search_copy_saved.png")))
        x.setObjectName("copy_search_button")
        l.addWidget(x)
        x.setToolTip(_("Copy current search text (instead of search name)"))

        x = parent.save_search_button = QToolButton(self)
        x.setIcon(QIcon(I("search_add_saved.png")))
        x.setObjectName("save_search_button")
        l.addWidget(x)
コード例 #8
0
class SearchRestrictionMixin(object):

    no_restriction = _('<None>')

    def __init__(self, *args, **kwargs):
        pass

    def init_search_restriction_mixin(self):
        self.checked = QIcon(I('ok.png'))
        self.empty = QIcon(I('blank.png'))
        self.current_search_action = QAction(self.empty, _('*current search'),
                                             self)
        self.current_search_action.triggered.connect(
            partial(self.apply_virtual_library, library='*'))
        self.addAction(self.current_search_action)
        self.keyboard.register_shortcut(
            'vl-from-current-search',
            _('Virtual library from current search'),
            description=_(
                'Create a temporary Virtual library from the current search'),
            group=_('Miscellaneous'),
            default_keys=('Ctrl+*', ),
            action=self.current_search_action)

        self.search_based_vl_name = None
        self.search_based_vl = None

        self.virtual_library_menu = QMenu()

        self.virtual_library.clicked.connect(self.virtual_library_clicked)
        self.clear_vl.clicked.connect(lambda x: (self.apply_virtual_library(
        ), self.clear_additional_restriction()))

        self.virtual_library_tooltip = \
            _('Use a "virtual library" to show only a subset of the books present in this library')
        self.virtual_library.setToolTip(self.virtual_library_tooltip)

        self.search_restriction = ComboBoxWithHelp(self)
        self.search_restriction.setVisible(False)
        self.clear_vl.setText(_("(all books)"))
        self.ar_menu = QMenu(_('Additional restriction'))
        self.edit_menu = QMenu(_('Edit Virtual library'))
        self.rm_menu = QMenu(_('Remove Virtual library'))
        self.search_restriction_list_built = False

    def add_virtual_library(self, db, name, search):
        virt_libs = db.prefs.get('virtual_libraries', {})
        virt_libs[name] = search
        db.new_api.set_pref('virtual_libraries', virt_libs)

    def do_create_edit(self, name=None):
        db = self.library_view.model().db
        virt_libs = db.prefs.get('virtual_libraries', {})
        cd = CreateVirtualLibrary(self, virt_libs.keys(), editing=name)
        if cd.exec_() == cd.Accepted:
            if name:
                self._remove_vl(name, reapply=False)
            self.add_virtual_library(db, cd.library_name, cd.library_search)
            if not name or name == db.data.get_base_restriction_name():
                self.apply_virtual_library(cd.library_name)
            self.rebuild_vl_tabs()

    def virtual_library_clicked(self):
        m = self.virtual_library_menu
        m.clear()

        a = m.addAction(_('Create Virtual library'))
        a.triggered.connect(partial(self.do_create_edit, name=None))

        a = self.edit_menu
        self.build_virtual_library_list(a, self.do_create_edit)
        m.addMenu(a)

        a = self.rm_menu
        self.build_virtual_library_list(a, self.remove_vl_triggered)
        m.addMenu(a)

        if gprefs['show_vl_tabs']:
            m.addAction(_('Hide virtual library tabs'),
                        self.vl_tabs.disable_bar)
        else:
            m.addAction(_('Show virtual libraries as tabs'),
                        self.vl_tabs.enable_bar)

        m.addSeparator()

        db = self.library_view.model().db

        a = self.ar_menu
        a.clear()
        a.setIcon(self.checked if db.data.get_search_restriction_name(
        ) else self.empty)
        self.build_search_restriction_list()
        m.addMenu(a)

        m.addSeparator()

        current_lib = db.data.get_base_restriction_name()

        if current_lib == '':
            a = m.addAction(self.checked, self.no_restriction)
        else:
            a = m.addAction(self.empty, self.no_restriction)
        a.triggered.connect(partial(self.apply_virtual_library, library=''))

        a = m.addAction(self.current_search_action)

        if self.search_based_vl_name:
            a = m.addAction(
                self.checked
                if db.data.get_base_restriction_name().startswith('*') else
                self.empty, self.search_based_vl_name)
            a.triggered.connect(
                partial(self.apply_virtual_library,
                        library=self.search_based_vl_name))

        m.addSeparator()

        virt_libs = db.prefs.get('virtual_libraries', {})
        for vl in sorted(virt_libs.keys(), key=sort_key):
            a = m.addAction(self.checked if vl == current_lib else self.empty,
                            vl.replace('&', '&&'))
            a.triggered.connect(partial(self.apply_virtual_library,
                                        library=vl))

        p = QPoint(0, self.virtual_library.height())
        self.virtual_library_menu.popup(self.virtual_library.mapToGlobal(p))

    def rebuild_vl_tabs(self):
        self.vl_tabs.rebuild()

    def apply_virtual_library(self, library=None, update_tabs=True):
        db = self.library_view.model().db
        virt_libs = db.prefs.get('virtual_libraries', {})
        if not library:
            db.data.set_base_restriction('')
            db.data.set_base_restriction_name('')
        elif library == '*':
            if not self.search.current_text:
                error_dialog(self,
                             _('No search'),
                             _('There is no current search to use'),
                             show=True)
                return

            txt = _build_full_search_string(self)
            try:
                db.data.search_getting_ids('', txt, use_virtual_library=False)
            except ParseException as e:
                error_dialog(self,
                             _('Invalid search'),
                             _('The search in the search box is not valid'),
                             det_msg=e.msg,
                             show=True)
                return

            self.search_based_vl = txt
            db.data.set_base_restriction(txt)
            self.search_based_vl_name = self._trim_restriction_name('*' + txt)
            db.data.set_base_restriction_name(self.search_based_vl_name)
        elif library == self.search_based_vl_name:
            db.data.set_base_restriction(self.search_based_vl)
            db.data.set_base_restriction_name(self.search_based_vl_name)
        elif library in virt_libs:
            db.data.set_base_restriction(virt_libs[library])
            db.data.set_base_restriction_name(library)
        self.virtual_library.setToolTip(self.virtual_library_tooltip + '\n' +
                                        db.data.get_base_restriction())
        self._apply_search_restriction(db.data.get_search_restriction(),
                                       db.data.get_search_restriction_name())
        if update_tabs:
            self.vl_tabs.update_current()

    def build_virtual_library_list(self, menu, handler):
        db = self.library_view.model().db
        virt_libs = db.prefs.get('virtual_libraries', {})
        menu.clear()
        menu.setIcon(self.empty)

        def add_action(name, search):
            a = menu.addAction(name.replace('&', '&&'))
            a.triggered.connect(partial(handler, name=name))
            a.setIcon(self.empty)

        libs = sorted(virt_libs.keys(), key=sort_key)
        if libs:
            menu.setEnabled(True)
            for n in libs:
                add_action(n, virt_libs[n])
        else:
            menu.setEnabled(False)

    def remove_vl_triggered(self, name=None):
        if not confirm(_(
                'Are you sure you want to remove the virtual library <b>{0}</b>?'
        ).format(name),
                       'confirm_vl_removal',
                       parent=self):
            return
        self._remove_vl(name, reapply=True)

    def _remove_vl(self, name, reapply=True):
        db = self.library_view.model().db
        virt_libs = db.prefs.get('virtual_libraries', {})
        virt_libs.pop(name, None)
        db.new_api.set_pref('virtual_libraries', virt_libs)
        if reapply and db.data.get_base_restriction_name() == name:
            self.apply_virtual_library('')
        self.rebuild_vl_tabs()

    def _trim_restriction_name(self, name):
        return name[0:MAX_VIRTUAL_LIBRARY_NAME_LENGTH].strip()

    def build_search_restriction_list(self):
        self.search_restriction_list_built = True
        from calibre.gui2.ui import get_gui
        m = self.ar_menu
        m.clear()

        current_restriction_text = None

        if self.search_restriction.count() > 1:
            txt = unicode(self.search_restriction.itemText(2))
            if txt.startswith('*'):
                current_restriction_text = txt
        self.search_restriction.clear()

        current_restriction = self.library_view.model(
        ).db.data.get_search_restriction_name()
        m.setIcon(self.checked if current_restriction else self.empty)

        def add_action(txt, index):
            self.search_restriction.addItem(txt)
            txt = self._trim_restriction_name(txt)
            if txt == current_restriction:
                a = m.addAction(self.checked,
                                txt if txt else self.no_restriction)
            else:
                a = m.addAction(self.empty,
                                txt if txt else self.no_restriction)
            a.triggered.connect(
                partial(self.search_restriction_triggered,
                        action=a,
                        index=index))

        add_action('', 0)
        add_action(_('*current search'), 1)
        dex = 2
        if current_restriction_text:
            add_action(current_restriction_text, 2)
            dex += 1

        for n in sorted(get_gui().current_db.saved_search_names(),
                        key=sort_key):
            add_action(n, dex)
            dex += 1

    def search_restriction_triggered(self, action=None, index=None):
        self.search_restriction.setCurrentIndex(index)
        self.apply_search_restriction(index)

    def apply_named_search_restriction(self, name):
        if not self.search_restriction_list_built:
            self.build_search_restriction_list()
        if not name:
            r = 0
        else:
            r = self.search_restriction.findText(name)
            if r < 0:
                r = 0
        self.search_restriction.setCurrentIndex(r)
        self.apply_search_restriction(r)

    def apply_text_search_restriction(self, search):
        if not self.search_restriction_list_built:
            self.build_search_restriction_list()
        search = unicode(search)
        if not search:
            self.search_restriction.setCurrentIndex(0)
            self._apply_search_restriction('', '')
        else:
            s = '*' + search
            if self.search_restriction.count() > 1:
                txt = unicode(self.search_restriction.itemText(2))
                if txt.startswith('*'):
                    self.search_restriction.setItemText(2, s)
                else:
                    self.search_restriction.insertItem(2, s)
            else:
                self.search_restriction.insertItem(2, s)
            self.search_restriction.setCurrentIndex(2)
            self._apply_search_restriction(search,
                                           self._trim_restriction_name(s))

    def apply_search_restriction(self, i):
        if not self.search_restriction_list_built:
            self.build_search_restriction_list()
        if i == 1:
            self.apply_text_search_restriction(
                unicode(self.search.currentText()))
        elif i == 2 and unicode(
                self.search_restriction.currentText()).startswith('*'):
            self.apply_text_search_restriction(
                unicode(self.search_restriction.currentText())[1:])
        else:
            r = unicode(self.search_restriction.currentText())
            if r is not None and r != '':
                restriction = 'search:"%s"' % (r)
            else:
                restriction = ''
            self._apply_search_restriction(restriction, r)

    def clear_additional_restriction(self):
        self.search_restriction.setCurrentIndex(0)
        self._apply_search_restriction('', '')

    def _apply_search_restriction(self, restriction, name):
        self.saved_search.clear()
        # The order below is important. Set the restriction, force a '' search
        # to apply it, reset the tag browser to take it into account, then set
        # the book count.
        self.library_view.model().db.data.set_search_restriction(restriction)
        self.library_view.model().db.data.set_search_restriction_name(name)
        self.search.clear(emit_search=True)
        self.tags_view.recount()
        self.set_number_of_books_shown()
        self.current_view().setFocus(Qt.OtherFocusReason)
        self.set_window_title()
        v = self.current_view()
        if not v.currentIndex().isValid():
            v.set_current_row()
        if not v.refresh_book_details():
            self.book_details.reset_info()

    def set_number_of_books_shown(self):
        db = self.library_view.model().db
        if self.current_view() == self.library_view and db is not None and \
                                            db.data.search_restriction_applied():
            restrictions = [
                x for x in (db.data.get_base_restriction_name(),
                            db.data.get_search_restriction_name()) if x
            ]
            t = ' :: '.join(restrictions)
            if len(t) > 20:
                t = t[:19] + u'…'
            self.clear_vl.setVisible(True)
            self.clear_vl.setVisible(not gprefs['show_vl_tabs'])
        else:  # No restriction or not library view
            t = ''
            self.clear_vl.setVisible(False)
        self.clear_vl.setText(t.replace('&', '&&'))
コード例 #9
0
ファイル: layout.py プロジェクト: Eksmo/calibre
    def __init__(self, parent):
        QWidget.__init__(self, parent)
        self._layout = l = QHBoxLayout()
        self.setLayout(self._layout)
        self._layout.setContentsMargins(0,5,0,0)

        x = ComboBoxWithHelp(self)
        x.setMaximumSize(QSize(150, 16777215))
        x.setObjectName("search_restriction")
        l.addWidget(x)
        parent.search_restriction = x

        x = QLabel(self)
        x.setObjectName("search_count")
        l.addWidget(x)
        parent.search_count = x
        x.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

        parent.advanced_search_button = x = QToolButton(self)
        parent.advanced_search_toggle_action = ac = QAction(parent)
        parent.addAction(ac)
        parent.keyboard.register_shortcut('advanced search toggle',
                _('Advanced search'), default_keys=(_("Shift+Ctrl+F"),),
                action=ac)
        ac.triggered.connect(x.click)
        x.setIcon(QIcon(I('search.png')))
        l.addWidget(x)
        x.setToolTip(_("Advanced search"))

        x = parent.search = SearchBox2(self)
        x.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        x.setObjectName("search")
        x.setToolTip(_("<p>Search the list of books by title, author, publisher, "
                       "tags, comments, etc.<br><br>Words separated by spaces are ANDed"))
        l.addWidget(x)

        self.search_button = QToolButton()
        self.search_button.setToolButtonStyle(Qt.ToolButtonTextOnly)
        self.search_button.setText(_('&Go!'))
        l.addWidget(self.search_button)
        self.search_button.setSizePolicy(QSizePolicy.Minimum,
                QSizePolicy.Minimum)
        self.search_button.clicked.connect(parent.do_search_button)
        self.search_button.setToolTip(
            _('Do Quick Search (you can also press the Enter key)'))

        x = parent.clear_button = QToolButton(self)
        x.setIcon(QIcon(I('clear_left.png')))
        x.setObjectName("clear_button")
        l.addWidget(x)
        x.setToolTip(_("Reset Quick Search"))

        x = parent.highlight_only_button = QToolButton(self)
        x.setIcon(QIcon(I('arrow-down.png')))
        l.addWidget(x)

        x = parent.saved_search = SavedSearchBox(self)
        x.setMaximumSize(QSize(150, 16777215))
        x.setMinimumContentsLength(15)
        x.setObjectName("saved_search")
        l.addWidget(x)

        x = parent.copy_search_button = QToolButton(self)
        x.setIcon(QIcon(I("search_copy_saved.png")))
        x.setObjectName("copy_search_button")
        l.addWidget(x)
        x.setToolTip(_("Copy current search text (instead of search name)"))

        x = parent.save_search_button = QToolButton(self)
        x.setIcon(QIcon(I("search_add_saved.png")))
        x.setObjectName("save_search_button")
        l.addWidget(x)
コード例 #10
0
class SearchRestrictionMixin(object):

    no_restriction = _('<None>')

    def __init__(self):
        self.checked = QIcon(I('ok.png'))
        self.empty = QIcon(I('blank.png'))
        self.search_based_vl_name = None
        self.search_based_vl = None

        self.virtual_library_menu = QMenu()

        self.virtual_library.clicked.connect(self.virtual_library_clicked)

        self.virtual_library_tooltip = \
            _('Books display will show only those books matching the search')
        self.virtual_library.setToolTip(self.virtual_library_tooltip)

        self.search_restriction = ComboBoxWithHelp(self)
        self.search_restriction.setVisible(False)
        self.search_count.setText(_("(all books)"))
        self.ar_menu = QMenu(_('Additional restriction'))
        self.edit_menu = QMenu(_('Edit Virtual Library'))
        self.rm_menu = QMenu(_('Remove Virtual Library'))


    def add_virtual_library(self, db, name, search):
        virt_libs = db.prefs.get('virtual_libraries', {})
        virt_libs[name] = search
        db.prefs.set('virtual_libraries', virt_libs)

    def do_create_edit(self, name=None):
        db = self.library_view.model().db
        virt_libs = db.prefs.get('virtual_libraries', {})
        cd = CreateVirtualLibrary(self, virt_libs.keys(), editing=name)
        if cd.exec_() == cd.Accepted:
            if name:
                self._remove_vl(name, reapply=False)
            self.add_virtual_library(db, cd.library_name, cd.library_search)
            if not name or name == db.data.get_base_restriction_name():
                self.apply_virtual_library(cd.library_name)

    def virtual_library_clicked(self):
        m = self.virtual_library_menu
        m.clear()

        a = m.addAction(_('Create Virtual Library'))
        a.triggered.connect(partial(self.do_create_edit, name=None))

        a = self.edit_menu
        self.build_virtual_library_list(a, self.do_create_edit)
        m.addMenu(a)

        a = self.rm_menu
        self.build_virtual_library_list(a, self.remove_vl_triggered)
        m.addMenu(a)

        m.addSeparator()

        db = self.library_view.model().db

        a = self.ar_menu
        a.clear()
        a.setIcon(self.checked if db.data.get_search_restriction_name() else self.empty)
        self.build_search_restriction_list()
        m.addMenu(a)

        m.addSeparator()

        current_lib = db.data.get_base_restriction_name()

        if current_lib == '':
            a = m.addAction(self.checked, self.no_restriction)
        else:
            a = m.addAction(self.empty, self.no_restriction)
        a.triggered.connect(partial(self.apply_virtual_library, library=''))

        a = m.addAction(self.empty, _('*current search'))
        a.triggered.connect(partial(self.apply_virtual_library, library='*'))

        if self.search_based_vl_name:
            a = m.addAction(
                self.checked if db.data.get_base_restriction_name().startswith('*')
                                            else self.empty,
                             self.search_based_vl_name)
            a.triggered.connect(partial(self.apply_virtual_library,
                                library=self.search_based_vl_name))

        m.addSeparator()

        virt_libs = db.prefs.get('virtual_libraries', {})
        for vl in sorted(virt_libs.keys(), key=sort_key):
            a = m.addAction(self.checked if vl == current_lib else self.empty, vl)
            a.triggered.connect(partial(self.apply_virtual_library, library=vl))

        p = QPoint(0, self.virtual_library.height())
        self.virtual_library_menu.popup(self.virtual_library.mapToGlobal(p))

    def apply_virtual_library(self, library=None):
        db = self.library_view.model().db
        virt_libs = db.prefs.get('virtual_libraries', {})
        if not library:
            db.data.set_base_restriction('')
            db.data.set_base_restriction_name('')
        elif library == '*':
            if not self.search.current_text:
                error_dialog(self, _('No search'),
                     _('There is no current search to use'), show=True)
                return

            txt = _build_full_search_string(self)
            try:
                db.data.search_getting_ids('', txt, use_virtual_library=False)
            except ParseException as e:
                error_dialog(self, _('Invalid search'),
                             _('The search in the search box is not valid'),
                             det_msg=e.msg, show=True)
                return

            self.search_based_vl = txt
            db.data.set_base_restriction(txt)
            self.search_based_vl_name = self._trim_restriction_name('*' + txt)
            db.data.set_base_restriction_name(self.search_based_vl_name)
        elif library == self.search_based_vl_name:
            db.data.set_base_restriction(self.search_based_vl)
            db.data.set_base_restriction_name(self.search_based_vl_name)
        elif library in virt_libs:
            db.data.set_base_restriction(virt_libs[library])
            db.data.set_base_restriction_name(library)
        self.virtual_library.setToolTip(self.virtual_library_tooltip + '\n' +
                                        db.data.get_base_restriction())
        self._apply_search_restriction(db.data.get_search_restriction(),
                                       db.data.get_search_restriction_name())

    def build_virtual_library_list(self, menu, handler):
        db = self.library_view.model().db
        virt_libs = db.prefs.get('virtual_libraries', {})
        menu.clear()
        menu.setIcon(self.empty)

        def add_action(name, search):
            a = menu.addAction(name)
            a.triggered.connect(partial(handler, name=name))
            a.setIcon(self.empty)

        libs = sorted(virt_libs.keys(), key=sort_key)
        if libs:
            menu.setEnabled(True)
            for n in libs:
                add_action(n, virt_libs[n])
        else:
            menu.setEnabled(False)

    def remove_vl_triggered(self, name=None):
        if not question_dialog(self, _('Are you sure?'),
                     _('Are you sure you want to remove '
                       'the virtual library {0}').format(name),
                        default_yes=False):
            return
        self._remove_vl(name, reapply=True)

    def _remove_vl(self, name, reapply=True):
        db = self.library_view.model().db
        virt_libs = db.prefs.get('virtual_libraries', {})
        virt_libs.pop(name, None)
        db.prefs.set('virtual_libraries', virt_libs)
        if reapply and db.data.get_base_restriction_name() == name:
            self.apply_virtual_library('')

    def _trim_restriction_name(self, name):
        return name[0:MAX_VIRTUAL_LIBRARY_NAME_LENGTH].strip()

    def build_search_restriction_list(self):
        m = self.ar_menu
        m.clear()

        current_restriction_text = None

        if self.search_restriction.count() > 1:
            txt = unicode(self.search_restriction.itemText(2))
            if txt.startswith('*'):
                current_restriction_text = txt
        self.search_restriction.clear()

        current_restriction = self.library_view.model().db.data.get_search_restriction_name()
        m.setIcon(self.checked if current_restriction else self.empty)

        def add_action(txt, index):
            self.search_restriction.addItem(txt)
            txt = self._trim_restriction_name(txt)
            if txt == current_restriction:
                a = m.addAction(self.checked, txt if txt else self.no_restriction)
            else:
                a = m.addAction(self.empty, txt if txt else self.no_restriction)
            a.triggered.connect(partial(self.search_restriction_triggered,
                                        action=a, index=index))

        add_action('', 0)
        add_action(_('*current search'), 1)
        dex = 2
        if current_restriction_text:
            add_action(current_restriction_text, 2)
            dex += 1

        for n in sorted(saved_searches().names(), key=sort_key):
            add_action(n, dex)
            dex += 1

    def search_restriction_triggered(self, action=None, index=None):
        self.search_restriction.setCurrentIndex(index)
        self.apply_search_restriction(index)

    def apply_named_search_restriction(self, name):
        if not name:
            r = 0
        else:
            r = self.search_restriction.findText(name)
            if r < 0:
                r = 0
        self.search_restriction.setCurrentIndex(r)
        self.apply_search_restriction(r)

    def apply_text_search_restriction(self, search):
        search = unicode(search)
        if not search:
            self.search_restriction.setCurrentIndex(0)
            self._apply_search_restriction('', '')
        else:
            s = '*' + search
            if self.search_restriction.count() > 1:
                txt = unicode(self.search_restriction.itemText(2))
                if txt.startswith('*'):
                    self.search_restriction.setItemText(2, s)
                else:
                    self.search_restriction.insertItem(2, s)
            else:
                self.search_restriction.insertItem(2, s)
            self.search_restriction.setCurrentIndex(2)
            self._apply_search_restriction(search, self._trim_restriction_name(s))

    def apply_search_restriction(self, i):
        if i == 1:
            self.apply_text_search_restriction(unicode(self.search.currentText()))
        elif i == 2 and unicode(self.search_restriction.currentText()).startswith('*'):
            self.apply_text_search_restriction(
                                unicode(self.search_restriction.currentText())[1:])
        else:
            r = unicode(self.search_restriction.currentText())
            if r is not None and r != '':
                restriction = 'search:"%s"'%(r)
            else:
                restriction = ''
            self._apply_search_restriction(restriction, r)

    def _apply_search_restriction(self, restriction, name):
        self.saved_search.clear()
        # The order below is important. Set the restriction, force a '' search
        # to apply it, reset the tag browser to take it into account, then set
        # the book count.
        self.library_view.model().db.data.set_search_restriction(restriction)
        self.library_view.model().db.data.set_search_restriction_name(name)
        self.search.clear(emit_search=True)
        self.tags_view.recount()
        self.set_number_of_books_shown()
        self.current_view().setFocus(Qt.OtherFocusReason)
        self.set_window_title()

    def set_number_of_books_shown(self):
        db = self.library_view.model().db
        if self.current_view() == self.library_view and db is not None and \
                                            db.data.search_restriction_applied():
            rows = self.current_view().row_count()
            rbc = max(rows, db.data.get_search_restriction_book_count())
            t = _("({0} of {1})").format(rows, rbc)
            self.search_count.setStyleSheet(
                'QLabel { border-radius: 8px; background-color: yellow; }')
        else:  # No restriction or not library view
            if not self.search.in_a_search():
                t = _("(all books)")
            else:
                t = _("({0} of all)").format(self.current_view().row_count())
            self.search_count.setStyleSheet(
                    'QLabel { background-color: transparent; }')
        self.search_count.setText(t)
コード例 #11
0
class SearchRestrictionMixin(object):

    no_restriction = _("<None>")

    def __init__(self):
        self.checked = QIcon(I("ok.png"))
        self.empty = QIcon(I("blank.png"))
        self.search_based_vl_name = None
        self.search_based_vl = None

        self.virtual_library_menu = QMenu()

        self.virtual_library.clicked.connect(self.virtual_library_clicked)
        self.clear_vl.clicked.connect(lambda x: (self.apply_virtual_library(), self.clear_additional_restriction()))

        self.virtual_library_tooltip = _(
            'Use a "virtual library" to show only a subset of the books present in this library'
        )
        self.virtual_library.setToolTip(self.virtual_library_tooltip)

        self.search_restriction = ComboBoxWithHelp(self)
        self.search_restriction.setVisible(False)
        self.search_count.setText(_("(all books)"))
        self.ar_menu = QMenu(_("Additional restriction"))
        self.edit_menu = QMenu(_("Edit Virtual Library"))
        self.rm_menu = QMenu(_("Remove Virtual Library"))

    def add_virtual_library(self, db, name, search):
        virt_libs = db.prefs.get("virtual_libraries", {})
        virt_libs[name] = search
        db.prefs.set("virtual_libraries", virt_libs)

    def do_create_edit(self, name=None):
        db = self.library_view.model().db
        virt_libs = db.prefs.get("virtual_libraries", {})
        cd = CreateVirtualLibrary(self, virt_libs.keys(), editing=name)
        if cd.exec_() == cd.Accepted:
            if name:
                self._remove_vl(name, reapply=False)
            self.add_virtual_library(db, cd.library_name, cd.library_search)
            if not name or name == db.data.get_base_restriction_name():
                self.apply_virtual_library(cd.library_name)

    def virtual_library_clicked(self):
        m = self.virtual_library_menu
        m.clear()

        a = m.addAction(_("Create Virtual Library"))
        a.triggered.connect(partial(self.do_create_edit, name=None))

        a = self.edit_menu
        self.build_virtual_library_list(a, self.do_create_edit)
        m.addMenu(a)

        a = self.rm_menu
        self.build_virtual_library_list(a, self.remove_vl_triggered)
        m.addMenu(a)

        m.addSeparator()

        db = self.library_view.model().db

        a = self.ar_menu
        a.clear()
        a.setIcon(self.checked if db.data.get_search_restriction_name() else self.empty)
        self.build_search_restriction_list()
        m.addMenu(a)

        m.addSeparator()

        current_lib = db.data.get_base_restriction_name()

        if current_lib == "":
            a = m.addAction(self.checked, self.no_restriction)
        else:
            a = m.addAction(self.empty, self.no_restriction)
        a.triggered.connect(partial(self.apply_virtual_library, library=""))

        a = m.addAction(self.empty, _("*current search"))
        a.triggered.connect(partial(self.apply_virtual_library, library="*"))

        if self.search_based_vl_name:
            a = m.addAction(
                self.checked if db.data.get_base_restriction_name().startswith("*") else self.empty,
                self.search_based_vl_name,
            )
            a.triggered.connect(partial(self.apply_virtual_library, library=self.search_based_vl_name))

        m.addSeparator()

        virt_libs = db.prefs.get("virtual_libraries", {})
        for vl in sorted(virt_libs.keys(), key=sort_key):
            a = m.addAction(self.checked if vl == current_lib else self.empty, vl)
            a.triggered.connect(partial(self.apply_virtual_library, library=vl))

        p = QPoint(0, self.virtual_library.height())
        self.virtual_library_menu.popup(self.virtual_library.mapToGlobal(p))

    def apply_virtual_library(self, library=None):
        db = self.library_view.model().db
        virt_libs = db.prefs.get("virtual_libraries", {})
        if not library:
            db.data.set_base_restriction("")
            db.data.set_base_restriction_name("")
        elif library == "*":
            if not self.search.current_text:
                error_dialog(self, _("No search"), _("There is no current search to use"), show=True)
                return

            txt = _build_full_search_string(self)
            try:
                db.data.search_getting_ids("", txt, use_virtual_library=False)
            except ParseException as e:
                error_dialog(
                    self, _("Invalid search"), _("The search in the search box is not valid"), det_msg=e.msg, show=True
                )
                return

            self.search_based_vl = txt
            db.data.set_base_restriction(txt)
            self.search_based_vl_name = self._trim_restriction_name("*" + txt)
            db.data.set_base_restriction_name(self.search_based_vl_name)
        elif library == self.search_based_vl_name:
            db.data.set_base_restriction(self.search_based_vl)
            db.data.set_base_restriction_name(self.search_based_vl_name)
        elif library in virt_libs:
            db.data.set_base_restriction(virt_libs[library])
            db.data.set_base_restriction_name(library)
        self.virtual_library.setToolTip(self.virtual_library_tooltip + "\n" + db.data.get_base_restriction())
        self._apply_search_restriction(db.data.get_search_restriction(), db.data.get_search_restriction_name())

    def build_virtual_library_list(self, menu, handler):
        db = self.library_view.model().db
        virt_libs = db.prefs.get("virtual_libraries", {})
        menu.clear()
        menu.setIcon(self.empty)

        def add_action(name, search):
            a = menu.addAction(name)
            a.triggered.connect(partial(handler, name=name))
            a.setIcon(self.empty)

        libs = sorted(virt_libs.keys(), key=sort_key)
        if libs:
            menu.setEnabled(True)
            for n in libs:
                add_action(n, virt_libs[n])
        else:
            menu.setEnabled(False)

    def remove_vl_triggered(self, name=None):
        if not confirm(
            _("Are you sure you want to remove the virtual library <b>{0}</b>?").format(name),
            "confirm_vl_removal",
            parent=self,
        ):
            return
        self._remove_vl(name, reapply=True)

    def _remove_vl(self, name, reapply=True):
        db = self.library_view.model().db
        virt_libs = db.prefs.get("virtual_libraries", {})
        virt_libs.pop(name, None)
        db.prefs.set("virtual_libraries", virt_libs)
        if reapply and db.data.get_base_restriction_name() == name:
            self.apply_virtual_library("")

    def _trim_restriction_name(self, name):
        return name[0:MAX_VIRTUAL_LIBRARY_NAME_LENGTH].strip()

    def build_search_restriction_list(self):
        from calibre.gui2.ui import get_gui

        m = self.ar_menu
        m.clear()

        current_restriction_text = None

        if self.search_restriction.count() > 1:
            txt = unicode(self.search_restriction.itemText(2))
            if txt.startswith("*"):
                current_restriction_text = txt
        self.search_restriction.clear()

        current_restriction = self.library_view.model().db.data.get_search_restriction_name()
        m.setIcon(self.checked if current_restriction else self.empty)

        def add_action(txt, index):
            self.search_restriction.addItem(txt)
            txt = self._trim_restriction_name(txt)
            if txt == current_restriction:
                a = m.addAction(self.checked, txt if txt else self.no_restriction)
            else:
                a = m.addAction(self.empty, txt if txt else self.no_restriction)
            a.triggered.connect(partial(self.search_restriction_triggered, action=a, index=index))

        add_action("", 0)
        add_action(_("*current search"), 1)
        dex = 2
        if current_restriction_text:
            add_action(current_restriction_text, 2)
            dex += 1

        for n in sorted(get_gui().current_db.saved_search_names(), key=sort_key):
            add_action(n, dex)
            dex += 1

    def search_restriction_triggered(self, action=None, index=None):
        self.search_restriction.setCurrentIndex(index)
        self.apply_search_restriction(index)

    def apply_named_search_restriction(self, name):
        if not name:
            r = 0
        else:
            r = self.search_restriction.findText(name)
            if r < 0:
                r = 0
        self.search_restriction.setCurrentIndex(r)
        self.apply_search_restriction(r)

    def apply_text_search_restriction(self, search):
        search = unicode(search)
        if not search:
            self.search_restriction.setCurrentIndex(0)
            self._apply_search_restriction("", "")
        else:
            s = "*" + search
            if self.search_restriction.count() > 1:
                txt = unicode(self.search_restriction.itemText(2))
                if txt.startswith("*"):
                    self.search_restriction.setItemText(2, s)
                else:
                    self.search_restriction.insertItem(2, s)
            else:
                self.search_restriction.insertItem(2, s)
            self.search_restriction.setCurrentIndex(2)
            self._apply_search_restriction(search, self._trim_restriction_name(s))

    def apply_search_restriction(self, i):
        if i == 1:
            self.apply_text_search_restriction(unicode(self.search.currentText()))
        elif i == 2 and unicode(self.search_restriction.currentText()).startswith("*"):
            self.apply_text_search_restriction(unicode(self.search_restriction.currentText())[1:])
        else:
            r = unicode(self.search_restriction.currentText())
            if r is not None and r != "":
                restriction = 'search:"%s"' % (r)
            else:
                restriction = ""
            self._apply_search_restriction(restriction, r)

    def clear_additional_restriction(self):
        self._apply_search_restriction("", "")

    def _apply_search_restriction(self, restriction, name):
        self.saved_search.clear()
        # The order below is important. Set the restriction, force a '' search
        # to apply it, reset the tag browser to take it into account, then set
        # the book count.
        self.library_view.model().db.data.set_search_restriction(restriction)
        self.library_view.model().db.data.set_search_restriction_name(name)
        self.search.clear(emit_search=True)
        self.tags_view.recount()
        self.set_number_of_books_shown()
        self.current_view().setFocus(Qt.OtherFocusReason)
        self.set_window_title()
        v = self.current_view()
        if not v.currentIndex().isValid():
            v.set_current_row()
        v.refresh_book_details()

    def set_number_of_books_shown(self):
        db = self.library_view.model().db
        if self.current_view() == self.library_view and db is not None and db.data.search_restriction_applied():
            restrictions = [
                x for x in (db.data.get_base_restriction_name(), db.data.get_search_restriction_name()) if x
            ]
            t = " :: ".join(restrictions)
            if len(t) > 20:
                t = t[:19] + "…"
            self.search_count.setStyleSheet(
                "QLabel { border-radius: 6px; background-color: %s }" % tweaks["highlight_virtual_library"]
            )
            self.clear_vl.setVisible(True)
        else:  # No restriction or not library view
            t = ""
            self.search_count.setStyleSheet("QLabel { background-color: transparent; }")
            self.clear_vl.setVisible(False)
        self.search_count.setText(t)