From 4a34618df483726e596d57abf7c9817f7e2c43f3 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 20 Mar 2014 22:40:35 +0530 Subject: [PATCH] Edit Book: Add support for saved searches. Click Search->Saved searches to bring up a dialog where you can create and manage saved searches Needs testing --- src/calibre/gui2/tweak_book/boss.py | 23 +++++++++++++++++++++++ src/calibre/gui2/tweak_book/search.py | 25 ++++++++++++++++++++++++- src/calibre/gui2/tweak_book/ui.py | 5 +++++ 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/tweak_book/boss.py b/src/calibre/gui2/tweak_book/boss.py index 9c2168a43b..89ebd51e8c 100644 --- a/src/calibre/gui2/tweak_book/boss.py +++ b/src/calibre/gui2/tweak_book/boss.py @@ -106,6 +106,8 @@ class Boss(QObject): self.gui.image_browser.image_activated.connect(self.image_activated) self.gui.checkpoints.revert_requested.connect(self.revert_requested) self.gui.checkpoints.compare_requested.connect(self.compare_requested) + self.gui.saved_searches.run_saved_searches.connect(self.run_saved_searches) + self.gui.central.search_panel.save_search.connect(self.save_search) def preferences(self): p = Preferences(self.gui) @@ -683,6 +685,27 @@ class Boss(QObject): run_search(state, action, ed, name, searchable_names, self.gui, self.show_editor, self.edit_file, self.show_current_diff, self.add_savepoint, self.rewind_savepoint, self.set_modified) + def saved_searches(self): + self.gui.saved_searches.show(), self.gui.saved_searches.raise_() + + def save_search(self): + state = self.gui.central.search_panel.state + self.gui.saved_searches.show(), self.gui.saved_searches.raise_() + self.gui.saved_searches.add_predefined_search(state) + + def run_saved_searches(self, searches, action): + ed = self.gui.central.current_editor + name = None + for n, x in editors.iteritems(): + if x is ed: + name = n + break + searchable_names = self.gui.file_list.searchable_names + if not searches or not validate_search_request(name, searchable_names, getattr(ed, 'has_marked_text', False), searches[0], self.gui): + return + run_search(searches, action, ed, name, searchable_names, + self.gui, self.show_editor, self.edit_file, self.show_current_diff, self.add_savepoint, self.rewind_savepoint, self.set_modified) + def create_checkpoint(self): text, ok = QInputDialog.getText(self.gui, _('Choose name'), _( 'Choose a name for the checkpoint.\nYou can later restore the book' diff --git a/src/calibre/gui2/tweak_book/search.py b/src/calibre/gui2/tweak_book/search.py index aeadb40010..ea9759defc 100644 --- a/src/calibre/gui2/tweak_book/search.py +++ b/src/calibre/gui2/tweak_book/search.py @@ -39,6 +39,7 @@ class PushButton(QPushButton): class HistoryLineEdit(HistoryLineEdit2): max_history_items = 100 + save_search = pyqtSignal() def __init__(self, parent, clear_msg): HistoryLineEdit2.__init__(self, parent) @@ -51,6 +52,8 @@ class HistoryLineEdit(HistoryLineEdit2): menu.addAction(self.clear_msg, self.clear_history) menu.addAction((_('Enable completion based on search history') if self.disable_popup else _( 'Disable completion based on search history')), self.toggle_popups) + menu.addSeparator() + menu.addAction(_('Save current search'), self.save_search.emit) menu.exec_(event.globalPos()) def toggle_popups(self): @@ -123,6 +126,7 @@ class SearchWidget(QWidget): } search_triggered = pyqtSignal(object) + save_search = pyqtSignal() def __init__(self, parent=None): QWidget.__init__(self, parent) @@ -133,6 +137,7 @@ class SearchWidget(QWidget): self.fl = fl = QLabel(_('&Find:')) fl.setAlignment(Qt.AlignRight | Qt.AlignCenter) self.find_text = ft = HistoryLineEdit(self, _('Clear search history')) + ft.save_search.connect(self.save_search) ft.initialize('tweak_book_find_edit') ft.returnPressed.connect(lambda : self.search_triggered.emit('find')) fl.setBuddy(ft) @@ -142,6 +147,7 @@ class SearchWidget(QWidget): self.rl = rl = QLabel(_('&Replace:')) rl.setAlignment(Qt.AlignRight | Qt.AlignCenter) self.replace_text = rt = HistoryLineEdit(self, _('Clear replace history')) + rt.save_search.connect(self.save_search) rt.initialize('tweak_book_replace_edit') rl.setBuddy(rt) l.addWidget(rl, 1, 0) @@ -298,6 +304,7 @@ regex_cache = {} class SearchPanel(QWidget): # {{{ search_triggered = pyqtSignal(object) + save_search = pyqtSignal() def __init__(self, parent=None): QWidget.__init__(self, parent) @@ -316,6 +323,7 @@ class SearchPanel(QWidget): # {{{ l.addWidget(self.widget) self.restore_state, self.save_state = self.widget.restore_state, self.widget.save_state self.widget.search_triggered.connect(self.search_triggered) + self.widget.save_search.connect(self.save_search) self.pre_fill = self.widget.pre_fill def hide_panel(self): @@ -401,11 +409,16 @@ class SearchesModel(QAbstractListModel): class EditSearch(Dialog): # {{{ - def __init__(self, search=None, search_index=-1, parent=None): + def __init__(self, search=None, search_index=-1, parent=None, state=None): self.search = search or {} self.original_name = self.search.get('name', None) self.search_index = search_index Dialog.__init__(self, _('Edit search'), 'edit-saved-search', parent=parent) + if state is not None: + self.find.setText(state['find']) + self.replace.setText(state['replace']) + self.case_sensitive.setChecked(state['case_sensitive']) + self.dot_all.setChecked(state['dot_all']) def sizeHint(self): ans = Dialog.sizeHint(self) @@ -481,6 +494,8 @@ class SearchDelegate(QStyledItemDelegate): class SavedSearches(Dialog): + run_saved_searches = pyqtSignal(object, object) + def __init__(self, parent=None): Dialog.__init__(self, _('Saved Searches'), 'saved-searches', parent=parent) @@ -633,6 +648,7 @@ class SavedSearches(Dialog): searches.append(search) if not searches: return + self.run_saved_searches.emit(searches, action) def move_entry(self, delta): rows = {index.row() for index in self.searches.selectionModel().selectedIndexes()} - {-1} @@ -661,6 +677,9 @@ class SavedSearches(Dialog): def add_search(self): d = EditSearch(parent=self) + self._add_search(d) + + def _add_search(self, d): if d.exec_() == d.Accepted: self.model.add_search() index = self.model.index(self.model.rowCount() - 1) @@ -669,6 +688,10 @@ class SavedSearches(Dialog): sm.setCurrentIndex(index, sm.ClearAndSelect) self.show_details() + def add_predefined_search(self, state): + d = EditSearch(parent=self, state=state) + self._add_search(d) + def show_details(self): self.description.setText(' \n \n ') i = self.searches.currentIndex() diff --git a/src/calibre/gui2/tweak_book/ui.py b/src/calibre/gui2/tweak_book/ui.py index f478738b1a..1aa1d60adf 100644 --- a/src/calibre/gui2/tweak_book/ui.py +++ b/src/calibre/gui2/tweak_book/ui.py @@ -29,6 +29,7 @@ from calibre.gui2.tweak_book.undo import CheckpointView from calibre.gui2.tweak_book.preview import Preview from calibre.gui2.tweak_book.search import SearchPanel from calibre.gui2.tweak_book.check import Check +from calibre.gui2.tweak_book.search import SavedSearches from calibre.gui2.tweak_book.toc import TOCViewer from calibre.gui2.tweak_book.char_select import CharSelect from calibre.gui2.tweak_book.editor.widget import register_text_editor_actions @@ -221,6 +222,7 @@ class Main(MainWindow): self.setCentralWidget(self.central) self.check_book = Check(self) self.toc_view = TOCViewer(self) + self.saved_searches = SavedSearches(self) self.image_browser = InsertImage(self, for_browsing=True) self.insert_char = CharSelect(self) @@ -393,6 +395,7 @@ class Main(MainWindow): 'count', keys=('Ctrl+N'), description=_('Count number of matches')) self.action_mark = reg(None, _('&Mark selected text'), self.boss.mark_selected_text, 'mark-selected-text', ('Ctrl+Shift+M',), _('Mark selected text')) self.action_go_to_line = reg(None, _('Go to &line'), self.boss.go_to_line_number, 'go-to-line-number', ('Ctrl+.',), _('Go to line number')) + self.action_saved_searches = reg(None, _('Sa&ved searches'), self.boss.saved_searches, 'saved-searches', (), _('Show the saved searches dialog')) # Check Book actions group = _('Check Book') @@ -507,6 +510,8 @@ class Main(MainWindow): a(self.action_mark) e.addSeparator() a(self.action_go_to_line) + e.addSeparator() + a(self.action_saved_searches) e = b.addMenu(_('&Help')) a = e.addAction