From f630484554d32abec667d5927d3c0687d77f3824 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Wed, 29 Jan 2014 12:42:41 +0530 Subject: [PATCH] Edit Book: Add a button to show diffs after any Polish action --- resources/images/diff.png | Bin 0 -> 6644 bytes src/calibre/gui2/tweak_book/boss.py | 25 +++++++++++++++++++++++ src/calibre/gui2/tweak_book/diff/main.py | 20 ++++++++++++++++-- src/calibre/gui2/tweak_book/undo.py | 10 +++++++++ 4 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 resources/images/diff.png diff --git a/resources/images/diff.png b/resources/images/diff.png new file mode 100644 index 0000000000000000000000000000000000000000..40e7d994a8e69dd6b7cf2f0b7d52d2bec0a19c75 GIT binary patch literal 6644 zcmX9@2{=^k7r!&pjAiVyWDR2}`)A)(!q`*U8cftJ`)=$;d?8T=F_!3SQc~h0MxhBI z1~n~~EMrfNEkd^bx9>mCGtYhBbI&>N{yV?(-b^P4D{f9PP5=P7vDOyO004uEFn}Ee zJ#gWVKFnzmx&hIYO=7BLE=7`p+MBng2Nw5*~>>?G|}91dJqH48IHz z2n031;D89Cg6X#+|m&OVCUgtk`udUb#yoiKz+^7Z4U}RVC zb6%5ewK)@e>I@hB8aoR4fDLoT&{_)xM=!F&kf#?j*h^&D(T5J7u(3X=o{~o2?T$q$ z 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 literal 0 HcmV?d00001 diff --git a/src/calibre/gui2/tweak_book/boss.py b/src/calibre/gui2/tweak_book/boss.py index e114806730..8f9eae010f 100644 --- a/src/calibre/gui2/tweak_book/boss.py +++ b/src/calibre/gui2/tweak_book/boss.py @@ -38,6 +38,8 @@ from calibre.gui2.tweak_book.editor.insert_resource import get_resource_data, Ne from calibre.gui2.tweak_book.preferences import Preferences from calibre.gui2.tweak_book.widgets import RationalizeFolders, MultiSplit +_diff_dialogs = [] + def get_container(*args, **kwargs): kwargs['tweak_mode'] = True container = _gc(*args, **kwargs) @@ -384,12 +386,35 @@ class Boss(QObject): d.l.addWidget(d.e) d.e.setHtml(report) d.bb = QDialogButtonBox(QDialogButtonBox.Close) + b = d.b = d.bb.addButton(_('See what changed'), d.bb.AcceptRole) + b.setIcon(QIcon(I('diff.png'))) + b.clicked.connect(partial(self.show_current_diff, allow_revert=True)) d.l.addWidget(d.bb) d.bb.rejected.connect(d.reject) d.bb.accepted.connect(d.accept) d.resize(600, 400) d.exec_() + def create_diff_dialog(self, revert_msg=_('&Revert changes')): + global _diff_dialogs + from calibre.gui2.tweak_book.diff.main import Diff + d = Diff(revert_button_msg=revert_msg, parent=self.gui) + [x.break_cycles() for x in _diff_dialogs if not x.isVisible()] + _diff_dialogs = [x for x in _diff_dialogs if x.isVisible()] + [d] + d.show(), d.raise_(), d.setFocus(Qt.OtherFocusReason) + return d + + def show_current_diff(self, allow_revert=True): + self.commit_all_editors_to_container() + d = self.create_diff_dialog() + d.revert_requested.connect(partial(self.revert_requested, self.global_undo.previous_container)) + d.container_diff(self.global_undo.previous_container, self.global_undo.current_container) + + def revert_requested(self, container): + nc = self.global_undo.revert_to(container) + set_current_container(nc) + self.apply_container_update_to_gui() + # Renaming {{{ def rationalize_folders(self): diff --git a/src/calibre/gui2/tweak_book/diff/main.py b/src/calibre/gui2/tweak_book/diff/main.py index 8cf786976f..5edb9e7780 100644 --- a/src/calibre/gui2/tweak_book/diff/main.py +++ b/src/calibre/gui2/tweak_book/diff/main.py @@ -11,7 +11,7 @@ from functools import partial from PyQt4.Qt import ( QGridLayout, QToolButton, QIcon, QRadioButton, QMenu, QApplication, Qt, QSize, QWidget, QLabel, QStackedLayout, QPainter, QRect, QVBoxLayout, - QCursor, QEventLoop, QKeySequence) + QCursor, QEventLoop, QKeySequence, pyqtSignal) from calibre.ebooks.oeb.polish.container import Container from calibre.gui2 import info_dialog @@ -128,9 +128,12 @@ def ebook_diff(path1, path2): class Diff(Dialog): - def __init__(self, parent=None): + revert_requested = pyqtSignal() + + def __init__(self, revert_button_msg=None, parent=None): self.context = 3 self.apply_diff_calls = [] + self.revert_button_msg = revert_button_msg Dialog.__init__(self, _('Differences between books'), 'diff-dialog', parent=parent) def sizeHint(self): @@ -187,10 +190,23 @@ class Diff(Dialog): l.addWidget(b, l.rowCount() - 1, l.columnCount(), 1, 1) self.bb.setStandardButtons(self.bb.Close) + if self.revert_button_msg is not None: + self.rvb = b = self.bb.addButton(self.revert_button_msg, self.bb.RejectRole) + b.setIcon(QIcon(I('edit-undo.png'))) + b.clicked.connect(self.revert_requested) + self.bb.button(self.bb.Close).setDefault(True) l.addWidget(self.bb, l.rowCount(), 0, 1, -1) self.view.setFocus(Qt.OtherFocusReason) + def break_cycles(self): + self.view = None + for x in ('revert_requested',): + try: + getattr(self, x).disconnect() + except: + pass + def do_search(self, reverse): text = unicode(self.search.text()) if not text.strip(): diff --git a/src/calibre/gui2/tweak_book/undo.py b/src/calibre/gui2/tweak_book/undo.py index 00a25a3e31..39d59ff691 100644 --- a/src/calibre/gui2/tweak_book/undo.py +++ b/src/calibre/gui2/tweak_book/undo.py @@ -33,6 +33,10 @@ class GlobalUndoHistory(object): def current_container(self): return self.states[self.pos].container + @property + def previous_container(self): + return self.states[self.pos - 1].container + def open_book(self, container): self.states = [State(container)] self.pos = 0 @@ -76,6 +80,12 @@ class GlobalUndoHistory(object): self.pos += 1 return self.current_container + def revert_to(self, container): + for i, state in enumerate(self.states): + if state.container is container: + self.pos = i + return container + @property def can_undo(self): return self.pos > 0