diff --git a/resources/images/diff.png b/resources/images/diff.png new file mode 100644 index 0000000000..40e7d994a8 Binary files /dev/null and b/resources/images/diff.png differ 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