mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-08-07 09:01:38 -04:00
Temporary marking of books in the library
This allows you to select books from your calibre library manually and mark them. This "mark" will remain until you restart calibre, or clear the marks. You can easily work with only the marked subset of books. To use this feature, go to Preferences->Toolbars and add the "Mark Books" tool to the main toolbar.
This commit is contained in:
parent
ea87178c1d
commit
60c78bef61
@ -923,6 +923,11 @@ class ActionSortBy(InterfaceActionBase):
|
||||
actual_plugin = 'calibre.gui2.actions.sort:SortByAction'
|
||||
description = _('Sort the list of books')
|
||||
|
||||
class ActionMarkBooks(InterfaceActionBase):
|
||||
name = 'Mark Books'
|
||||
actual_plugin = 'calibre.gui2.actions.mark_books:MarkBooksAction'
|
||||
description = _('Temporarily mark books')
|
||||
|
||||
class ActionStore(InterfaceActionBase):
|
||||
name = 'Store'
|
||||
author = 'John Schember'
|
||||
@ -953,7 +958,8 @@ plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog,
|
||||
ActionSendToDevice, ActionHelp, ActionPreferences, ActionSimilarBooks,
|
||||
ActionAddToLibrary, ActionEditCollections, ActionMatchBooks, ActionChooseLibrary,
|
||||
ActionCopyToLibrary, ActionTweakEpub, ActionNextMatch, ActionStore,
|
||||
ActionPluginUpdater, ActionPickRandom, ActionEditToC, ActionSortBy]
|
||||
ActionPluginUpdater, ActionPickRandom, ActionEditToC, ActionSortBy,
|
||||
ActionMarkBooks]
|
||||
|
||||
# }}}
|
||||
|
||||
|
@ -382,6 +382,12 @@ class View(object):
|
||||
if func is not None:
|
||||
func(old_marked_ids, cmids)
|
||||
|
||||
def toggle_marked_ids(self, book_ids):
|
||||
book_ids = set(book_ids)
|
||||
mids = set(self.marked_ids)
|
||||
common = mids.intersection(book_ids)
|
||||
self.set_marked_ids((mids | book_ids) - common)
|
||||
|
||||
def refresh(self, field=None, ascending=True, clear_caches=True, do_search=True):
|
||||
self._map = tuple(sorted(self.cache.all_book_ids()))
|
||||
self._map_filtered = tuple(self._map)
|
||||
|
131
src/calibre/gui2/actions/mark_books.py
Normal file
131
src/calibre/gui2/actions/mark_books.py
Normal file
@ -0,0 +1,131 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=utf-8
|
||||
from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import QTimer, QApplication, Qt
|
||||
|
||||
from calibre.gui2 import error_dialog
|
||||
from calibre.gui2.actions import InterfaceAction
|
||||
|
||||
class MarkBooksAction(InterfaceAction):
|
||||
|
||||
name = 'Mark Books'
|
||||
action_spec = (_('Mark Books'), 'marked.png', _('Temporarily mark books'), 'Ctrl+M')
|
||||
action_type = 'current'
|
||||
action_add_menu = True
|
||||
dont_add_to = frozenset([
|
||||
'toolbar-device', 'context-menu-device', 'menubar-device', 'context-menu-cover-browser'])
|
||||
action_menu_clone_qaction = _('Toggle mark for selected books')
|
||||
|
||||
accepts_drops = True
|
||||
|
||||
def accept_enter_event(self, event, mime_data):
|
||||
if mime_data.hasFormat("application/calibre+from_library"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def accept_drag_move_event(self, event, mime_data):
|
||||
if mime_data.hasFormat("application/calibre+from_library"):
|
||||
return True
|
||||
return False
|
||||
|
||||
def drop_event(self, event, mime_data):
|
||||
mime = 'application/calibre+from_library'
|
||||
if mime_data.hasFormat(mime):
|
||||
self.dropped_ids = tuple(map(int, str(mime_data.data(mime)).split()))
|
||||
QTimer.singleShot(1, self.do_drop)
|
||||
return True
|
||||
return False
|
||||
|
||||
def do_drop(self):
|
||||
book_ids = self.dropped_ids
|
||||
del self.dropped_ids
|
||||
if book_ids:
|
||||
self.toggle_ids(book_ids)
|
||||
|
||||
def genesis(self):
|
||||
self.qaction.triggered.connect(self.toolbar_triggered)
|
||||
self.menu = m = self.qaction.menu()
|
||||
m.aboutToShow.connect(self.about_to_show_menu)
|
||||
ma = partial(self.create_menu_action, m)
|
||||
self.show_marked_action = a = ma('show-marked', _('Show marked books'), icon='search.png', shortcut='Shift+Ctrl+M')
|
||||
a.triggered.connect(self.show_marked)
|
||||
self.clear_marked_action = a = ma('clear-all-marked', _('Clear all marked books'), icon='clear_left.png')
|
||||
a.triggered.connect(self.clear_all_marked)
|
||||
m.addSeparator()
|
||||
self.mark_author_action = a = ma('mark-author', _('Mark all books by selected author(s)'), icon='plus.png')
|
||||
a.triggered.connect(partial(self.mark_field, 'authors', True))
|
||||
self.mark_series_action = a = ma('mark-series', _('Mark all books in the selected series'), icon='plus.png')
|
||||
a.triggered.connect(partial(self.mark_field, 'series', True))
|
||||
m.addSeparator()
|
||||
self.unmark_author_action = a = ma('unmark-author', _('Clear all books by selected author(s)'), icon='minus.png')
|
||||
a.triggered.connect(partial(self.mark_field, 'authors', False))
|
||||
self.unmark_series_action = a = ma('unmark-series', _('Clear all books in the selected series'), icon='minus.png')
|
||||
a.triggered.connect(partial(self.mark_field, 'series', False))
|
||||
|
||||
def about_to_show_menu(self):
|
||||
db = self.gui.current_db
|
||||
num = len(db.data.marked_ids)
|
||||
text = ngettext('Show marked book', 'Show marked books (%d)' % num, num)
|
||||
self.show_marked_action.setText(text)
|
||||
|
||||
def location_selected(self, loc):
|
||||
enabled = loc == 'library'
|
||||
self.qaction.setEnabled(enabled)
|
||||
|
||||
def toolbar_triggered(self):
|
||||
mods = QApplication.keyboardModifiers()
|
||||
if mods & Qt.ControlModifier or mods & Qt.ShiftModifier:
|
||||
self.show_marked()
|
||||
else:
|
||||
self.toggle_selected()
|
||||
|
||||
def toggle_selected(self):
|
||||
book_ids = self._get_selected_ids()
|
||||
if book_ids:
|
||||
self.toggle_ids(book_ids)
|
||||
|
||||
def _get_selected_ids(self):
|
||||
rows = self.gui.library_view.selectionModel().selectedRows()
|
||||
if not rows or len(rows) == 0:
|
||||
d = error_dialog(self.gui, _('Cannot mark'), _('No books selected'))
|
||||
d.exec_()
|
||||
return set([])
|
||||
return set(map(self.gui.library_view.model().id, rows))
|
||||
|
||||
def toggle_ids(self, book_ids):
|
||||
self.gui.current_db.data.toggle_marked_ids(book_ids)
|
||||
|
||||
def show_marked(self):
|
||||
self.gui.search.set_search_string('marked:true')
|
||||
|
||||
def clear_all_marked(self):
|
||||
self.gui.current_db.data.set_marked_ids(())
|
||||
if unicode(self.gui.search.text()).startswith('marked:'):
|
||||
self.gui.search.set_search_string('')
|
||||
|
||||
def mark_field(self, field, add):
|
||||
book_ids = self._get_selected_ids()
|
||||
if not book_ids:
|
||||
return
|
||||
db = self.gui.current_db
|
||||
items = set()
|
||||
for book_id in book_ids:
|
||||
items |= set(db.new_api.field_ids_for(field, book_id))
|
||||
book_ids = set()
|
||||
for item_id in items:
|
||||
book_ids |= db.new_api.books_for_field(field, item_id)
|
||||
mids = db.data.marked_ids.copy()
|
||||
for book_id in book_ids:
|
||||
if add:
|
||||
mids[book_id] = True
|
||||
else:
|
||||
mids.pop(book_id, None)
|
||||
db.data.set_marked_ids(mids)
|
||||
|
Loading…
x
Reference in New Issue
Block a user