diff --git a/src/calibre/gui2/tweak_book/boss.py b/src/calibre/gui2/tweak_book/boss.py index 411b5214ec..93d295bd06 100644 --- a/src/calibre/gui2/tweak_book/boss.py +++ b/src/calibre/gui2/tweak_book/boss.py @@ -374,6 +374,36 @@ class Boss(QObject): 'Currently selected text does not match the search query.')) return True + def count_message(action, count): + msg = _('%(action)s %(num)s occurrences of %(query)s' % dict(num=count, query=state['find'], action=action)) + info_dialog(self.gui, _('Searching done'), msg, show=True) + + def do_all(replace=True): + count = 0 + if not files and editor is None: + return 0 + lfiles = files or {name:editor.syntax} + + for n, syntax in lfiles.iteritems(): + if n in editors: + raw = editors[n].get_raw_data() + else: + raw = current_container().raw_data(n) + if replace: + raw, num = pat.subn(state['replace'], raw) + else: + num = len(pat.findall(raw)) + count += num + if replace and num > 0: + if n in editors: + editors[n].replace_data(raw) + else: + with current_container().open(n, 'wb') as f: + f.write(raw.encode('utf-8')) + QApplication.restoreOverrideCursor() + count_message(_('Replaced') if replace else _('Found'), count) + return count + QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) try: if action == 'find': @@ -382,6 +412,18 @@ class Boss(QObject): return do_replace() if action == 'replace-find' and do_replace(): return do_find() + if action == 'replace-all': + if marked: + return count_message(_('Replaced'), editor.all_in_marked(pat, state['replace'])) + self.add_savepoint(_('Replace all')) + count = do_all() + if count == 0: + self.rewind_savepoint() + return + if action == 'count': + if marked: + return count_message(_('Found'), editor.all_in_marked(pat)) + return do_all(replace=False) finally: QApplication.restoreOverrideCursor() diff --git a/src/calibre/gui2/tweak_book/editor/text.py b/src/calibre/gui2/tweak_book/editor/text.py index c9d4035aff..f2b2106fa9 100644 --- a/src/calibre/gui2/tweak_book/editor/text.py +++ b/src/calibre/gui2/tweak_book/editor/text.py @@ -141,6 +141,7 @@ class TextEdit(QPlainTextEdit): sel.append(self.current_search_mark) self.setExtraSelections(sel) + # Search and replace {{{ def mark_selected_text(self): sel = QTextEdit.ExtraSelection() sel.format.setBackground(self.highlight_color) @@ -196,6 +197,22 @@ class TextEdit(QPlainTextEdit): self.setTextCursor(c) return True + def all_in_marked(self, pat, template=None): + if self.current_search_mark is None: + return 0 + c = self.current_search_mark.cursor + raw = unicode(c.selectedText()).replace(PARAGRAPH_SEPARATOR, '\n') + if template is None: + count = len(pat.findall(raw)) + else: + raw, count = pat.subn(template, raw) + if count > 0: + c.setKeepPositionOnInsert(True) + c.insertText(raw) + c.setKeepPositionOnInsert(False) + self.update_extra_selections() + return count + def find(self, pat, wrap=False, marked=False, complete=False): if marked: return self.find_in_marked(pat, wrap=wrap) @@ -242,6 +259,7 @@ class TextEdit(QPlainTextEdit): text = m.expand(template) c.insertText(text) return True + # }}} # Line numbers and cursor line {{{ def highlight_cursor_line(self): diff --git a/src/calibre/gui2/tweak_book/editor/widget.py b/src/calibre/gui2/tweak_book/editor/widget.py index 19574e3be1..8182dfd478 100644 --- a/src/calibre/gui2/tweak_book/editor/widget.py +++ b/src/calibre/gui2/tweak_book/editor/widget.py @@ -67,6 +67,7 @@ class Editor(QMainWindow): def redo(self): self.editor.redo() + # Search and replace {{{ def mark_selected_text(self): self.editor.mark_selected_text() @@ -76,6 +77,10 @@ class Editor(QMainWindow): def replace(self, *args, **kwargs): return self.editor.replace(*args, **kwargs) + def all_in_marked(self, *args, **kwargs): + return self.editor.all_in_marked(*args, **kwargs) + # }}} + @property def has_marked_text(self): return self.editor.current_search_mark is not None