Add keyboard shorcuts to find the next highlighted match

This commit is contained in:
Kovid Goyal 2011-01-13 10:02:33 -07:00
parent 215ad8c245
commit b2ad17d7ff
8 changed files with 134 additions and 17 deletions

View File

@ -705,13 +705,17 @@ class ActionTweakEpub(InterfaceActionBase):
name = 'Tweak ePub' name = 'Tweak ePub'
actual_plugin = 'calibre.gui2.actions.tweak_epub:TweakEpubAction' actual_plugin = 'calibre.gui2.actions.tweak_epub:TweakEpubAction'
class ActionNextMatch(InterfaceActionBase):
name = 'Next Match'
actual_plugin = 'calibre.gui2.actions.next_match:NextMatchAction'
plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog, plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog,
ActionConvert, ActionDelete, ActionEditMetadata, ActionView, ActionConvert, ActionDelete, ActionEditMetadata, ActionView,
ActionFetchNews, ActionSaveToDisk, ActionShowBookDetails, ActionFetchNews, ActionSaveToDisk, ActionShowBookDetails,
ActionRestart, ActionOpenFolder, ActionConnectShare, ActionRestart, ActionOpenFolder, ActionConnectShare,
ActionSendToDevice, ActionHelp, ActionPreferences, ActionSimilarBooks, ActionSendToDevice, ActionHelp, ActionPreferences, ActionSimilarBooks,
ActionAddToLibrary, ActionEditCollections, ActionChooseLibrary, ActionAddToLibrary, ActionEditCollections, ActionChooseLibrary,
ActionCopyToLibrary, ActionTweakEpub] ActionCopyToLibrary, ActionTweakEpub, ActionNextMatch]
# }}} # }}}

View File

@ -111,6 +111,9 @@ class InterfaceAction(QObject):
action.setWhatsThis(text) action.setWhatsThis(text)
action.setAutoRepeat(False) action.setAutoRepeat(False)
if shortcut: if shortcut:
if isinstance(shortcut, list):
action.setShortcuts(shortcut)
else:
action.setShortcut(shortcut) action.setShortcut(shortcut)
setattr(self, attr, action) setattr(self, attr, action)
return action return action
@ -170,6 +173,14 @@ class InterfaceAction(QObject):
''' '''
pass pass
def gui_layout_complete(self):
'''
Called once per action when the layout of the main GUI is
completed. If your action needs to make changes to the layout, they
should be done here, rather than in :meth:`initialization_complete`.
'''
pass
def initialization_complete(self): def initialization_complete(self):
''' '''
Called once per action when the initialization of the main GUI is Called once per action when the initialization of the main GUI is

View File

@ -0,0 +1,56 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from calibre.gui2.actions import InterfaceAction
class NextMatchAction(InterfaceAction):
name = 'Move to next highlighted book'
action_spec = (_('Move to next match'), 'arrow-down.png',
_('Move to next highlighted match'), [_('N'), _('F3')])
dont_add_to = frozenset(['toolbar-device', 'context-menu-device'])
action_type = 'current'
def genesis(self):
'''
Setup this plugin. Only called once during initialization. self.gui is
available. The action secified by :attr:`action_spec` is available as
``self.qaction``.
'''
self.can_move = None
self.qaction.triggered.connect(self.move_forward)
self.create_action(spec=(_('Move to previous item'), 'arrow-up.png',
_('Move to previous highlighted item'), [_('Shift+N'),
_('Shift+F3')]), attr='p_action')
self.gui.addAction(self.p_action)
self.p_action.triggered.connect(self.move_backward)
def gui_layout_complete(self):
self.gui.search_highlight_only.setVisible(True)
def location_selected(self, loc):
self.can_move = loc == 'library'
try:
self.gui.search_highlight_only.setVisible(self.can_move)
except:
import traceback
traceback.print_exc()
def move_forward(self):
if self.can_move is None:
self.can_move = self.gui.current_view() is self.gui.library_view
self.gui.search_highlight_only.setVisible(self.can_move)
if self.can_move:
self.gui.current_view().move_highlighted_row(forward=True)
def move_backward(self):
if self.can_move is None:
self.can_move = self.gui.current_view() is self.gui.library_view
self.gui.search_highlight_only.setVisible(self.can_move)
if self.can_move:
self.gui.current_view().move_highlighted_row(forward=False)

View File

@ -196,9 +196,11 @@ class SearchBar(QWidget): # {{{
x = parent.search_highlight_only = QCheckBox() x = parent.search_highlight_only = QCheckBox()
x.setText(_('&Highlight')) x.setText(_('&Highlight'))
x.setToolTip(_('Highlight matched books in the book list, instead ' x.setToolTip('<p>'+_('When searching, highlight matched books, instead '
'of restricting the book list to the matches.')) 'of restricting the book list to the matches.<p> You can use the '
'N or F3 keys to go to the next match.'))
l.addWidget(x) l.addWidget(x)
x.setVisible(False)
x = parent.saved_search = SavedSearchBox(self) x = parent.saved_search = SavedSearchBox(self)
x.setMaximumSize(QSize(150, 16777215)) x.setMaximumSize(QSize(150, 16777215))

View File

@ -93,8 +93,9 @@ class BooksModel(QAbstractTableModel): # {{{
self.bool_no_icon = QIcon(I('list_remove.png')) self.bool_no_icon = QIcon(I('list_remove.png'))
self.bool_blank_icon = QIcon(I('blank.png')) self.bool_blank_icon = QIcon(I('blank.png'))
self.device_connected = False self.device_connected = False
self.rows_matching = set() self.rows_to_highlight = []
self.lowest_row_matching = None self.rows_to_highlight_set = set()
self.current_highlighted_row = None
self.highlight_only = False self.highlight_only = False
self.read_config() self.read_config()
@ -130,6 +131,9 @@ class BooksModel(QAbstractTableModel): # {{{
self.book_on_device = func self.book_on_device = func
def set_database(self, db): def set_database(self, db):
self.rows_to_highlight = []
self.rows_to_highlight_set = set()
self.current_highlighted_row = None
self.db = db self.db = db
self.custom_columns = self.db.field_metadata.custom_field_metadata() self.custom_columns = self.db.field_metadata.custom_field_metadata()
self.column_map = list(self.orig_headers.keys()) + \ self.column_map = list(self.orig_headers.keys()) + \
@ -237,21 +241,43 @@ class BooksModel(QAbstractTableModel): # {{{
if self.last_search: if self.last_search:
self.research() self.research()
def get_current_highlighted_row(self):
if len(self.rows_to_highlight) == 0 or self.current_highlighted_row is None:
return None
try:
return self.rows_to_highlight[self.current_highlighted_row]
except:
return None
def get_next_highlighted_row(self, forward):
if len(self.rows_to_highlight) == 0 or self.current_highlighted_row is None:
return None
self.current_highlighted_row += 1 if forward else -1
if self.current_highlighted_row < 0:
self.current_highlighted_row = len(self.rows_to_highlight) - 1;
elif self.current_highlighted_row >= len(self.rows_to_highlight):
self.current_highlighted_row = 0
return self.get_current_highlighted_row()
def search(self, text, reset=True): def search(self, text, reset=True):
try: try:
if self.highlight_only: if self.highlight_only:
self.db.search('') self.db.search('')
if not text: if not text:
self.rows_matching = set() self.rows_to_highlight = []
self.lowest_row_matching = None self.rows_to_highlight_set = set()
self.current_highlighted_row = None
else: else:
self.rows_matching = self.db.search(text, return_matches=True) self.rows_to_highlight = self.db.search(text, return_matches=True)
if self.rows_matching: self.rows_to_highlight_set = set(self.rows_to_highlight)
self.lowest_row_matching = self.db.row(self.rows_matching[0]) if self.rows_to_highlight:
self.rows_matching = set(self.rows_matching) self.current_highlighted_row = 0
else: else:
self.rows_matching = set() self.current_highlighted_row = None
self.lowest_row_matching = None else:
self.rows_to_highlight = []
self.rows_to_highlight_set = set()
self.current_highlighted_row = None
self.db.search(text) self.db.search(text)
except ParseException as e: except ParseException as e:
self.searched.emit(e.msg) self.searched.emit(e.msg)
@ -674,7 +700,7 @@ class BooksModel(QAbstractTableModel): # {{{
if role in (Qt.DisplayRole, Qt.EditRole): if role in (Qt.DisplayRole, Qt.EditRole):
return self.column_to_dc_map[col](index.row()) return self.column_to_dc_map[col](index.row())
elif role == Qt.BackgroundColorRole: elif role == Qt.BackgroundColorRole:
if self.id(index) in self.rows_matching: if self.id(index) in self.rows_to_highlight_set:
return QColor('lightgreen') return QColor('lightgreen')
elif role == Qt.DecorationRole: elif role == Qt.DecorationRole:
if self.column_to_dc_decorator_map[col] is not None: if self.column_to_dc_decorator_map[col] is not None:

View File

@ -680,10 +680,16 @@ class BooksView(QTableView): # {{{
def set_editable(self, editable, supports_backloading): def set_editable(self, editable, supports_backloading):
self._model.set_editable(editable) self._model.set_editable(editable)
def move_highlighted_row(self, forward):
id_to_select = self._model.get_next_highlighted_row(forward)
if id_to_select is not None:
self.select_rows([id_to_select], using_ids=True)
def search_proxy(self, txt): def search_proxy(self, txt):
self._model.search(txt) self._model.search(txt)
if self._model.lowest_row_matching is not None: id_to_select = self._model.get_current_highlighted_row()
self.select_rows([self._model.lowest_row_matching], using_ids=False) if id_to_select is not None:
self.select_rows([id_to_select], using_ids=True)
self.setFocus(Qt.OtherFocusReason) self.setFocus(Qt.OtherFocusReason)
def connect_to_search_box(self, sb, search_done): def connect_to_search_box(self, sb, search_done):

View File

@ -256,6 +256,14 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
self.height()) self.height())
self.resize(self.width(), self._calculated_available_height) self.resize(self.width(), self._calculated_available_height)
for ac in self.iactions.values():
try:
ac.gui_layout_complete()
except:
import traceback
traceback.print_exc()
if ac.plugin_path is None:
raise
if config['autolaunch_server']: if config['autolaunch_server']:
self.start_content_server() self.start_content_server()

View File

@ -478,6 +478,10 @@ Calibre has several keyboard shortcuts to save you time and mouse movement. Thes
- Focus the search bar - Focus the search bar
* - :kbd:`Shift+Ctrl+F` * - :kbd:`Shift+Ctrl+F`
- Open the advanced search dialog - Open the advanced search dialog
* - :kbd:`N or F3`
- Find the next book that matches the current search (only works if the highlight checkbox next to the search bar is checked)
* - :kbd:`Shift+N or Shift+F3`
- Find the next book that matches the current search (only works if the highlight checkbox next to the search bar is checked)
* - :kbd:`Ctrl+D` * - :kbd:`Ctrl+D`
- Download metadata and shortcuts - Download metadata and shortcuts
* - :kbd:`Ctrl+R` * - :kbd:`Ctrl+R`