def __init__(self, parent, vcs, notebook, page=None): Dialog.__init__( self, parent, _('Versions'), # T: dialog title buttons=Gtk.ButtonsType.CLOSE, help='Plugins:Version Control') self.notebook = notebook self.vcs = vcs self._side_by_side_app = get_side_by_side_app() self.uistate.setdefault('windowsize', (600, 500), check=value_is_coord) self.uistate.setdefault('vpanepos', 300) self.vpaned = VPaned() self.vpaned.set_position(self.uistate['vpanepos']) self.vbox.pack_start(self.vpaned, True, True, 0) vbox = Gtk.VBox(spacing=5) self.vpaned.pack1(vbox, resize=True) # Choice between whole notebook or page label = Gtk.Label(label='<b>' + _('Versions') + ':</b>') # section label label.set_use_markup(True) label.set_alignment(0, 0.5) vbox.pack_start(label, False, True, 0) self.notebook_radio = Gtk.RadioButton.new_with_mnemonic_from_widget( None, _('Complete _notebook')) # T: Option in versions dialog to show version for complete notebook self.page_radio = Gtk.RadioButton.new_with_mnemonic_from_widget( self.notebook_radio, _('_Page') + ':') # T: Option in versions dialog to show version for single page #~ recursive_box = Gtk.CheckButton.new_with_mnemonic('Recursive') vbox.pack_start(self.notebook_radio, False, True, 0) # Page entry hbox = Gtk.HBox(spacing=5) vbox.pack_start(hbox, False, True, 0) hbox.pack_start(self.page_radio, False, True, 0) self.page_entry = PageEntry(self.notebook) if page: self.page_entry.set_path(page) hbox.pack_start(self.page_entry, False, True, 0) # View annotated button ann_button = Gtk.Button.new_with_mnemonic( _('View _Annotated')) # T: Button label ann_button.connect('clicked', lambda o: self.show_annotated()) hbox.pack_start(ann_button, False, True, 0) # Help text label = Gtk.Label(label='<i>\n' + _('''\ Select a version to see changes between that version and the current state. Or select multiple versions to see changes between those versions. ''').strip() + '</i>') # T: Help text in versions dialog label.set_use_markup(True) #~ label.set_alignment(0, 0.5) vbox.pack_start(label, False, True, 0) # Version list self.versionlist = VersionsTreeView() self.versionlist.load_versions(vcs.list_versions()) scrolled = ScrolledWindow(self.versionlist) vbox.add(scrolled) col = self.uistate.setdefault('sortcol', self.versionlist.REV_SORT_COL) order = self.uistate.setdefault('sortorder', Gtk.SortType.DESCENDING) try: self.versionlist.get_model().set_sort_column_id(col, order) except: logger.exception('Invalid sort column: %s %s', col, order) # ----- vbox = Gtk.VBox(spacing=5) self.vpaned.pack2(vbox, resize=False) label = Gtk.Label(label='<b>' + _('Comment') + '</b>') # T: version details label.set_use_markup(True) label.set_alignment(0.0, 0.5) vbox.pack_start(label, False, True, 0) # Comment text window, textview = ScrolledTextView() self.comment_textview = textview vbox.add(window) buttonbox = Gtk.HButtonBox() buttonbox.set_layout(Gtk.ButtonBoxStyle.END) vbox.pack_start(buttonbox, False, True, 0) # Restore version button revert_button = Gtk.Button.new_with_mnemonic( _('_Restore Version')) # T: Button label revert_button.connect('clicked', lambda o: self.restore_version()) buttonbox.add(revert_button) # Notebook Changes button diff_button = Gtk.Button.new_with_mnemonic(_('Show _Changes')) # T: button in versions dialog for diff diff_button.connect('clicked', lambda o: self.show_changes()) buttonbox.add(diff_button) # Compare page button comp_button = Gtk.Button.new_with_mnemonic(_('_Side by Side')) # T: button in versions dialog for side by side comparison comp_button.connect('clicked', lambda o: self.show_side_by_side()) buttonbox.add(comp_button) # UI interaction between selections and buttons def on_row_activated(o, iter, path): model = self.versionlist.get_model() comment = model[iter][VersionsTreeView.MSG_COL] buffer = textview.get_buffer() buffer.set_text(comment) self.versionlist.connect('row-activated', on_row_activated) def on_ui_change(o): usepage = self.page_radio.get_active() self.page_entry.set_sensitive(usepage) ann_button.set_sensitive(usepage) # side by side comparison can only be done for one page # revert can only be done to one version, not multiple selection = self.versionlist.get_selection() model, rows = selection.get_selected_rows() if not rows: revert_button.set_sensitive(False) diff_button.set_sensitive(False) comp_button.set_sensitive(False) elif len(rows) == 1: revert_button.set_sensitive(usepage) diff_button.set_sensitive(True) comp_button.set_sensitive( bool(usepage and self._side_by_side_app)) else: revert_button.set_sensitive(False) diff_button.set_sensitive(True) comp_button.set_sensitive( bool(usepage and self._side_by_side_app)) def on_page_change(o): pagesource = self._get_file() if pagesource: self.versionlist.load_versions( vcs.list_versions(self._get_file())) def on_book_change(o): self.versionlist.load_versions(vcs.list_versions()) self.page_radio.connect('toggled', on_ui_change) self.notebook_radio.connect('toggled', on_book_change) self.page_radio.connect('toggled', on_page_change) self.page_entry.connect('changed', on_page_change) selection = self.versionlist.get_selection() selection.connect('changed', on_ui_change) # select last version self.versionlist.get_selection().select_path((0, )) col = self.versionlist.get_column(0) self.versionlist.row_activated(Gtk.TreePath((0, )), col)
def __init__(self, ui, vcs): Dialog.__init__(self, ui, _('Versions'), # T: dialog title buttons=gtk.BUTTONS_CLOSE, help='Plugins:Version Control') self.vcs = vcs self.uistate.setdefault('windowsize', (600, 500), check=value_is_coord) self.uistate.setdefault('vpanepos', 300) self.vpaned = VPaned() self.vpaned.set_position(self.uistate['vpanepos']) self.vbox.add(self.vpaned) vbox = gtk.VBox(spacing=5) self.vpaned.pack1(vbox, resize=True) # Choice between whole notebook or page label = gtk.Label('<b>'+_('Versions')+':</b>') # section label label.set_use_markup(True) label.set_alignment(0, 0.5) vbox.pack_start(label, False) self.notebook_radio = gtk.RadioButton(None, _('Complete _notebook')) # T: Option in versions dialog to show version for complete notebook self.page_radio = gtk.RadioButton(self.notebook_radio, _('_Page')+':') # T: Option in versions dialog to show version for single page #~ recursive_box = gtk.CheckButton('Recursive') vbox.pack_start(self.notebook_radio, False) # Page entry hbox = gtk.HBox(spacing=5) vbox.pack_start(hbox, False) hbox.pack_start(self.page_radio, False) self.page_entry = PageEntry(self.ui.notebook) self.page_entry.set_path(ui.page) hbox.pack_start(self.page_entry, False) # View annotated button ann_button = gtk.Button(_('View _Annotated')) # T: Button label ann_button.connect('clicked', lambda o: self.show_annotated()) hbox.pack_start(ann_button, False) # Help text label = gtk.Label('<i>\n'+_( '''\ Select a version to see changes between that version and the current state. Or select multiple versions to see changes between those versions. ''' ).strip()+'</i>') # T: Help text in versions dialog label.set_use_markup(True) #~ label.set_alignment(0, 0.5) vbox.pack_start(label, False) # Version list self.versionlist = VersionsTreeView() self.versionlist.load_versions(vcs.list_versions()) scrolled = ScrolledWindow(self.versionlist) vbox.add(scrolled) # ----- vbox = gtk.VBox(spacing=5) self.vpaned.pack2(vbox, resize=False) label = gtk.Label('<b>'+_('Comment')+'</b>') # T: version details label.set_use_markup(True) label.set_alignment(0.0, 0.5) vbox.pack_start(label, False) # Comment text window, textview = ScrolledTextView() self.comment_textview = textview vbox.add(window) buttonbox = gtk.HButtonBox() buttonbox.set_layout(gtk.BUTTONBOX_END) vbox.pack_start(buttonbox, False) # Restore version button revert_button = gtk.Button(_('_Restore Version')) # T: Button label revert_button.connect('clicked', lambda o: self.restore_version()) buttonbox.add(revert_button) # Notebook Changes button diff_button = gtk.Button(_('Show _Changes')) # T: button in versions dialog for diff diff_button.connect('clicked', lambda o: self.show_changes()) buttonbox.add(diff_button) # Compare page button comp_button = gtk.Button(_('_Side by Side')) # T: button in versions dialog for side by side comparison comp_button.connect('clicked', lambda o: self.show_side_by_side()) buttonbox.add(comp_button) # UI interaction between selections and buttons def on_row_activated(o, iter, path): model = self.versionlist.get_model() comment = model[iter][VersionsTreeView.MSG_COL] buffer = textview.get_buffer() buffer.set_text(comment) self.versionlist.connect('row-activated', on_row_activated) def on_ui_change(o): usepage = self.page_radio.get_active() self.page_entry.set_sensitive(usepage) ann_button.set_sensitive(usepage) # side by side comparison can only be done for one page # revert can only be done to one version, not multiple selection = self.versionlist.get_selection() model, rows = selection.get_selected_rows() if not rows: revert_button.set_sensitive(False) diff_button.set_sensitive(False) comp_button.set_sensitive(False) elif len(rows) == 1: revert_button.set_sensitive(usepage) diff_button.set_sensitive(True) comp_button.set_sensitive(usepage) else: revert_button.set_sensitive(False) diff_button.set_sensitive(True) comp_button.set_sensitive(usepage) def on_page_change(o): pagesource = self._get_file() if pagesource: self.versionlist.load_versions(vcs.list_versions(self._get_file())) def on_book_change(o): self.versionlist.load_versions(vcs.list_versions()) self.page_radio.connect('toggled', on_ui_change) self.notebook_radio.connect('toggled', on_book_change) self.page_radio.connect('toggled', on_page_change) self.page_entry.connect('changed', on_page_change) selection = self.versionlist.get_selection() selection.connect('changed', on_ui_change) # select last version self.versionlist.get_selection().select_path((0,)) col = self.versionlist.get_column(0) self.versionlist.row_activated(0, col)
class VersionsDialog(Dialog): def __init__(self, parent, vcs, notebook, page=None): Dialog.__init__( self, parent, _('Versions'), # T: dialog title buttons=Gtk.ButtonsType.CLOSE, help='Plugins:Version Control') self.notebook = notebook self.vcs = vcs self._side_by_side_app = get_side_by_side_app() self.uistate.setdefault('windowsize', (600, 500), check=value_is_coord) self.uistate.setdefault('vpanepos', 300) self.vpaned = VPaned() self.vpaned.set_position(self.uistate['vpanepos']) self.vbox.pack_start(self.vpaned, True, True, 0) vbox = Gtk.VBox(spacing=5) self.vpaned.pack1(vbox, resize=True) # Choice between whole notebook or page label = Gtk.Label(label='<b>' + _('Versions') + ':</b>') # section label label.set_use_markup(True) label.set_alignment(0, 0.5) vbox.pack_start(label, False, True, 0) self.notebook_radio = Gtk.RadioButton.new_with_mnemonic_from_widget( None, _('Complete _notebook')) # T: Option in versions dialog to show version for complete notebook self.page_radio = Gtk.RadioButton.new_with_mnemonic_from_widget( self.notebook_radio, _('_Page') + ':') # T: Option in versions dialog to show version for single page #~ recursive_box = Gtk.CheckButton.new_with_mnemonic('Recursive') vbox.pack_start(self.notebook_radio, False, True, 0) # Page entry hbox = Gtk.HBox(spacing=5) vbox.pack_start(hbox, False, True, 0) hbox.pack_start(self.page_radio, False, True, 0) self.page_entry = PageEntry(self.notebook) if page: self.page_entry.set_path(page) hbox.pack_start(self.page_entry, False, True, 0) # View annotated button ann_button = Gtk.Button.new_with_mnemonic( _('View _Annotated')) # T: Button label ann_button.connect('clicked', lambda o: self.show_annotated()) hbox.pack_start(ann_button, False, True, 0) # Help text label = Gtk.Label(label='<i>\n' + _('''\ Select a version to see changes between that version and the current state. Or select multiple versions to see changes between those versions. ''').strip() + '</i>') # T: Help text in versions dialog label.set_use_markup(True) #~ label.set_alignment(0, 0.5) vbox.pack_start(label, False, True, 0) # Version list self.versionlist = VersionsTreeView() self.versionlist.load_versions(vcs.list_versions()) scrolled = ScrolledWindow(self.versionlist) vbox.add(scrolled) col = self.uistate.setdefault('sortcol', self.versionlist.REV_SORT_COL) order = self.uistate.setdefault('sortorder', Gtk.SortType.DESCENDING) try: self.versionlist.get_model().set_sort_column_id(col, order) except: logger.exception('Invalid sort column: %s %s', col, order) # ----- vbox = Gtk.VBox(spacing=5) self.vpaned.pack2(vbox, resize=False) label = Gtk.Label(label='<b>' + _('Comment') + '</b>') # T: version details label.set_use_markup(True) label.set_alignment(0.0, 0.5) vbox.pack_start(label, False, True, 0) # Comment text window, textview = ScrolledTextView() self.comment_textview = textview vbox.add(window) buttonbox = Gtk.HButtonBox() buttonbox.set_layout(Gtk.ButtonBoxStyle.END) vbox.pack_start(buttonbox, False, True, 0) # Restore version button revert_button = Gtk.Button.new_with_mnemonic( _('_Restore Version')) # T: Button label revert_button.connect('clicked', lambda o: self.restore_version()) buttonbox.add(revert_button) # Notebook Changes button diff_button = Gtk.Button.new_with_mnemonic(_('Show _Changes')) # T: button in versions dialog for diff diff_button.connect('clicked', lambda o: self.show_changes()) buttonbox.add(diff_button) # Compare page button comp_button = Gtk.Button.new_with_mnemonic(_('_Side by Side')) # T: button in versions dialog for side by side comparison comp_button.connect('clicked', lambda o: self.show_side_by_side()) buttonbox.add(comp_button) # UI interaction between selections and buttons def on_row_activated(o, iter, path): model = self.versionlist.get_model() comment = model[iter][VersionsTreeView.MSG_COL] buffer = textview.get_buffer() buffer.set_text(comment) self.versionlist.connect('row-activated', on_row_activated) def on_ui_change(o): usepage = self.page_radio.get_active() self.page_entry.set_sensitive(usepage) ann_button.set_sensitive(usepage) # side by side comparison can only be done for one page # revert can only be done to one version, not multiple selection = self.versionlist.get_selection() model, rows = selection.get_selected_rows() if not rows: revert_button.set_sensitive(False) diff_button.set_sensitive(False) comp_button.set_sensitive(False) elif len(rows) == 1: revert_button.set_sensitive(usepage) diff_button.set_sensitive(True) comp_button.set_sensitive( bool(usepage and self._side_by_side_app)) else: revert_button.set_sensitive(False) diff_button.set_sensitive(True) comp_button.set_sensitive( bool(usepage and self._side_by_side_app)) def on_page_change(o): pagesource = self._get_file() if pagesource: self.versionlist.load_versions( vcs.list_versions(self._get_file())) def on_book_change(o): self.versionlist.load_versions(vcs.list_versions()) self.page_radio.connect('toggled', on_ui_change) self.notebook_radio.connect('toggled', on_book_change) self.page_radio.connect('toggled', on_page_change) self.page_entry.connect('changed', on_page_change) selection = self.versionlist.get_selection() selection.connect('changed', on_ui_change) # select last version self.versionlist.get_selection().select_path((0, )) col = self.versionlist.get_column(0) self.versionlist.row_activated(Gtk.TreePath((0, )), col) def save_uistate(self): self.uistate['vpanepos'] = self.vpaned.get_position() col, order = self.versionlist.get_model().get_sort_column_id() self.uistate['sortcol'] = col self.uistate['sortorder'] = order def _get_file(self): if self.notebook_radio.get_active(): return None else: path = self.page_entry.get_path() if path: page = self.notebook.get_page(path) else: return None # TODO error message valid page name? if page \ and page.source_file is not None \ and page.source_file.ischild(self.vcs.root): return page.source else: return None # TODO error message ? def show_annotated(self): # TODO check for gannotated file = self._get_file() assert not file is None annotated = self.vcs.annotated(file) TextDialog(self, _('Annotated Page Source'), annotated).run() # T: dialog title def restore_version(self): file = self._get_file() path = self.page_entry.get_path() version = self.versionlist.get_versions()[0] assert not file is None if QuestionDialog( self, ( _('Restore page to saved version?' ), # T: Confirmation question _('Do you want to restore page: %(page)s\n' 'to saved version: %(version)s ?\n\n' 'All changes since the last saved version will be lost !') % { 'page': path.name, 'version': str(version) } # T: Detailed question, "%(page)s" is replaced by the page, "%(version)s" by the version id )).run(): self.vcs.revert(file, version) page = self.notebook.get_page(path) page.check_source_changed() def show_changes(self): # TODO check for gdiff file = self._get_file() versions = self.versionlist.get_versions() diff = self.vcs.diff(file=file, versions=versions) or ['=== No Changes\n'] TextDialog(self, _('Changes'), diff).run() # T: dialog title def show_side_by_side(self): file = self._get_file() versions = self.versionlist.get_versions() if not (file and versions): raise AssertionError files = [self._get_tmp_file(file, v) for v in versions] if len(files) == 1: tmp = TmpFile(file.basename + '--CURRENT', persistent=True) # need to be persistent, else it is cleaned up before application spawned tmp.writelines(file.readlines()) files.insert(0, tmp) self._side_by_side_app.spawn(files) def _get_tmp_file(self, file, version): text = self.vcs.cat(file, version) tmp = TmpFile(file.basename + '--REV%s' % version, persistent=True) # need to be persistent, else it is cleaned up before application spawned tmp.writelines(text) return tmp
class VersionsDialog(Dialog): # TODO put state in uistate .. def __init__(self, ui, vcs): Dialog.__init__(self, ui, _('Versions'), # T: dialog title buttons=gtk.BUTTONS_CLOSE, help='Plugins:Version Control') self.vcs = vcs self.uistate.setdefault('windowsize', (600, 500), check=value_is_coord) self.uistate.setdefault('vpanepos', 300) self.vpaned = VPaned() self.vpaned.set_position(self.uistate['vpanepos']) self.vbox.add(self.vpaned) vbox = gtk.VBox(spacing=5) self.vpaned.pack1(vbox, resize=True) # Choice between whole notebook or page label = gtk.Label('<b>'+_('Versions')+':</b>') # section label label.set_use_markup(True) label.set_alignment(0, 0.5) vbox.pack_start(label, False) self.notebook_radio = gtk.RadioButton(None, _('Complete _notebook')) # T: Option in versions dialog to show version for complete notebook self.page_radio = gtk.RadioButton(self.notebook_radio, _('_Page')+':') # T: Option in versions dialog to show version for single page #~ recursive_box = gtk.CheckButton('Recursive') vbox.pack_start(self.notebook_radio, False) # Page entry hbox = gtk.HBox(spacing=5) vbox.pack_start(hbox, False) hbox.pack_start(self.page_radio, False) self.page_entry = PageEntry(self.ui.notebook) self.page_entry.set_path(ui.page) hbox.pack_start(self.page_entry, False) # View annotated button ann_button = gtk.Button(_('View _Annotated')) # T: Button label ann_button.connect('clicked', lambda o: self.show_annotated()) hbox.pack_start(ann_button, False) # Help text label = gtk.Label('<i>\n'+_( '''\ Select a version to see changes between that version and the current state. Or select multiple versions to see changes between those versions. ''' ).strip()+'</i>') # T: Help text in versions dialog label.set_use_markup(True) #~ label.set_alignment(0, 0.5) vbox.pack_start(label, False) # Version list self.versionlist = VersionsTreeView() self.versionlist.load_versions(vcs.list_versions()) scrolled = ScrolledWindow(self.versionlist) vbox.add(scrolled) # ----- vbox = gtk.VBox(spacing=5) self.vpaned.pack2(vbox, resize=False) label = gtk.Label('<b>'+_('Comment')+'</b>') # T: version details label.set_use_markup(True) label.set_alignment(0.0, 0.5) vbox.pack_start(label, False) # Comment text window, textview = ScrolledTextView() self.comment_textview = textview vbox.add(window) buttonbox = gtk.HButtonBox() buttonbox.set_layout(gtk.BUTTONBOX_END) vbox.pack_start(buttonbox, False) # Restore version button revert_button = gtk.Button(_('_Restore Version')) # T: Button label revert_button.connect('clicked', lambda o: self.restore_version()) buttonbox.add(revert_button) # Notebook Changes button diff_button = gtk.Button(_('Show _Changes')) # T: button in versions dialog for diff diff_button.connect('clicked', lambda o: self.show_changes()) buttonbox.add(diff_button) # Compare page button comp_button = gtk.Button(_('_Side by Side')) # T: button in versions dialog for side by side comparison comp_button.connect('clicked', lambda o: self.show_side_by_side()) buttonbox.add(comp_button) # UI interaction between selections and buttons def on_row_activated(o, iter, path): model = self.versionlist.get_model() comment = model[iter][VersionsTreeView.MSG_COL] buffer = textview.get_buffer() buffer.set_text(comment) self.versionlist.connect('row-activated', on_row_activated) def on_ui_change(o): usepage = self.page_radio.get_active() self.page_entry.set_sensitive(usepage) ann_button.set_sensitive(usepage) # side by side comparison can only be done for one page # revert can only be done to one version, not multiple selection = self.versionlist.get_selection() model, rows = selection.get_selected_rows() if not rows: revert_button.set_sensitive(False) diff_button.set_sensitive(False) comp_button.set_sensitive(False) elif len(rows) == 1: revert_button.set_sensitive(usepage) diff_button.set_sensitive(True) comp_button.set_sensitive(usepage) else: revert_button.set_sensitive(False) diff_button.set_sensitive(True) comp_button.set_sensitive(usepage) def on_page_change(o): pagesource = self._get_file() if pagesource: self.versionlist.load_versions(vcs.list_versions(self._get_file())) def on_book_change(o): self.versionlist.load_versions(vcs.list_versions()) self.page_radio.connect('toggled', on_ui_change) self.notebook_radio.connect('toggled', on_book_change) self.page_radio.connect('toggled', on_page_change) self.page_entry.connect('changed', on_page_change) selection = self.versionlist.get_selection() selection.connect('changed', on_ui_change) # select last version self.versionlist.get_selection().select_path((0,)) col = self.versionlist.get_column(0) self.versionlist.row_activated(0, col) def save_uistate(self): self.uistate['vpanepos'] = self.vpaned.get_position() def _get_file(self): if self.notebook_radio.get_active(): if self.ui.page.modified: self.ui.save_page() return None else: path = self.page_entry.get_path() if path: page = self.ui.notebook.get_page(path) if page == self.ui.page and page.modified: self.ui.save_page() else: return None # TODO error message valid page name? if page \ and hasattr(page, 'source') \ and isinstance(page.source, File) \ and page.source.ischild(self.vcs.root): return page.source else: return None # TODO error message ? def show_annotated(self): # TODO check for gannotated file = self._get_file() assert not file is None annotated = self.vcs.get_annotated(file) TextDialog(self, _('Annotated Page Source'), annotated).run() # T: dialog title def restore_version(self): file = self._get_file() path = self.page_entry.get_path() version = self.versionlist.get_versions()[0] assert not file is None if QuestionDialog(self, ( _('Restore page to saved version?'), # T: Confirmation question _('Do you want to restore page: %(page)s\n' 'to saved version: %(version)s ?\n\n' 'All changes since the last saved version will be lost !') % {'page': path.name, 'version': str(version)} # T: Detailed question, "%(page)s" is replaced by the page, "%(version)s" by the version id ) ).run(): self.vcs.revert(file=file, version=version) self.ui.reload_page() # TODO trigger vcs autosave here? def show_changes(self): # TODO check for gdiff file = self._get_file() versions = self.versionlist.get_versions() diff = self.vcs.get_diff(file=file, versions=versions) TextDialog(self, _('Changes'), diff).run() # T: dialog title def show_side_by_side(self): print 'TODO - need config for an application like meld'