class ImageGeneratorDialog(Dialog): '''Base class for use by plugins that generate and insert an image based on textual user input. This is used e.g. by the equation editor and similar plugins. The dialog provides text input and an image view for showing previews. ''' # TODO: use uistate to remember pane position def __init__(self, ui, title, generator, image=None, syntax=None, **opt): '''Constructor @param ui: L{GtkInterface} object or parent window @param title: the dialog title @param generator: an L{ImageGeneratorClass} object @param image: image data for an image in the L{TextBuffer<zim.gui.pageview.TextBuffer>} @param syntax: optional syntax name (as understood by gtksourceview) @param opt: any other arguments to pass to the L{Dialog} constructor ''' if ui_environment['platform'] == 'maemo': defaultsize = (450,480) # Use maximum available vertical space because decorations take # too much real state else: defaultsize = (450,300) Dialog.__init__(self, ui, title, defaultwindowsize=defaultsize, **opt) if ui_environment['platform'] == 'maemo': self.resize(450,480) # Force maximum dialog size under maemo, otherwise # we'll end with a too small dialog and no way to resize it self.generator = generator self.imagefile = None self.logfile = None self.vpane = VPaned() self.vpane.set_position(150) self.vbox.add(self.vpane) self.imageview = ImageView(bgcolor='#FFF', checkerboard=False) self.vpane.pack1(self.imageview, resize=True) # TODO scrolled window and option to zoom in / real size window, textview = ScrolledSourceView(syntax=syntax) self.textview = textview self.textview.set_editable(True) self.vpane.pack2(window, resize=False) hbox = gtk.HBox(spacing=5) self.vbox.pack_start(hbox, False) self.previewbutton = Button(_('_Preview'), stock='gtk-refresh') # T: button in e.g. equation editor dialog self.previewbutton.set_sensitive(False) self.previewbutton.connect_object( 'clicked', self.__class__.preview, self) hbox.pack_start(self.previewbutton, False) self.textview.get_buffer().connect('modified-changed', lambda b: self.previewbutton.set_sensitive(b.get_modified())) self.logbutton = Button(_('View _Log'), stock='gtk-file') # T: button in e.g. equation editor dialog self.logbutton.set_sensitive(False) self.logbutton.connect_object( 'clicked', self.__class__.show_log, self) if generator.uses_log_file: hbox.pack_start(self.logbutton, False) # else keep hidden self._existing_file = None if image: file = image['_src_file'] # FIXME ? textfile = self._stitch_fileextension(file, self.generator.scriptname) self._existing_file = textfile self.imageview.set_file(file) self.set_text(self.generator.filter_input(textfile.read())) self.textview.grab_focus() def _stitch_fileextension(self, file, basename): '''Stitches the file extension from 'basename' to the path of 'file' and returns a File object. ''' i = basename.rfind('.') j = file.path.rfind('.') return File(file.path[:j] + basename[i:]) def set_text(self, text): '''Set text in the buffer''' buffer = self.textview.get_buffer() buffer.set_text(text) buffer.set_modified(False) def get_text(self): '''Get the text from the buffer @returns: text as string ''' buffer = self.textview.get_buffer() bounds = buffer.get_bounds() return buffer.get_text(*bounds) def generate_image(self): '''Update the image based on the text in the text buffer''' self.imagefile = None self.logfile = None text = self.get_text() text = self.generator.process_input(text) try: imagefile, logfile = self.generator.generate_image(text) except: logger.exception('Could not generate image') # TODO set "error" image instead of "broken" image # TODO set exception text as log message else: self.imagefile = imagefile self.logfile = logfile self.textview.get_buffer().set_modified(False) def preview(self): '''Action for the "Preview" button''' self.generate_image() self.imageview.set_file(self.imagefile) # if None sets broken image self.logbutton.set_sensitive(not self.logfile is None) def show_log(self): '''Action for the "View Log" button''' assert self.logfile, 'BUG: no logfile set (yet)' LogFileDialog(self, self.logfile).run() def do_response_ok(self): if not self.imagefile \ or self.textview.get_buffer().get_modified(): self.generate_image() if not (self.imagefile and self.imagefile.exists()): dialog = QuestionDialog(self, _('An error occurred while generating the image.\nDo you want to save the source text anyway?')) # T: Question prompt when e.g. equation editor encountered an error generating the image to insert if not dialog.run(): return False if self._existing_file: textfile = self._existing_file else: page = self.ui.page dir = self.ui.notebook.get_attachments_dir(page) textfile = dir.new_file(self.generator.scriptname) textfile.write( self.generator.process_input(self.get_text()) ) imgfile = self._stitch_fileextension(textfile, self.generator.imagename) if self.imagefile and self.imagefile.exists(): self.imagefile.rename(imgfile) elif imgfile.exists(): imgfile.remove() if self._existing_file: self.ui.reload_page() else: pageview = self.ui.mainwindow.pageview # XXX pageview.insert_image(imgfile, type=self.generator.object_type, interactive=False, force=True) if self.logfile and self.logfile.exists(): self.logfile.remove() return True def destroy(self): self.generator.cleanup() Dialog.destroy(self)
class ImageGeneratorDialog(Dialog): '''Dialog that provides text input and an image view for showing previews for an L{ImageGeneratorClass} implementation. ''' # TODO: use uistate to remember pane position def __init__(self, window, title, generator, image=None, syntax=None, **opt): '''Constructor @param window: the L{MainWindow} @param title: the dialog title @param generator: an L{ImageGeneratorClass} object @param image: image data for an image in the L{TextBuffer<zim.gui.pageview.TextBuffer>} @param syntax: optional syntax name (as understood by gtksourceview) @param opt: any other arguments to pass to the L{Dialog} constructor ''' Dialog.__init__(self, window, title, defaultwindowsize=(450, 300), **opt) self.app_window = window self.generator = generator self.imagefile = None self.logfile = None self.vpane = VPaned() self.vpane.set_position(150) self.vbox.add(self.vpane) self.imageview = ImageView(bgcolor='#FFF', checkerboard=False) self.vpane.pack1(self.imageview, resize=True) # TODO scrolled window and option to zoom in / real size window, textview = ScrolledSourceView(syntax=syntax) self.textview = textview self.textview.set_editable(True) self.vpane.pack2(window, resize=False) hbox = gtk.HBox(spacing=5) self.vbox.pack_start(hbox, False) self.previewbutton = Button(_('_Preview'), stock='gtk-refresh') # T: button in e.g. equation editor dialog self.previewbutton.set_sensitive(False) self.previewbutton.connect_object('clicked', self.__class__.preview, self) hbox.pack_start(self.previewbutton, False) self.textview.get_buffer().connect( 'modified-changed', lambda b: self.previewbutton.set_sensitive(b.get_modified())) self.logbutton = Button(_('View _Log'), stock='gtk-file') # T: button in e.g. equation editor dialog self.logbutton.set_sensitive(False) self.logbutton.connect_object('clicked', self.__class__.show_log, self) if generator.uses_log_file: hbox.pack_start(self.logbutton, False) # else keep hidden if image: file = image['_src_file'] # FIXME ? textfile = self._stitch_fileextension(file, self.generator.scriptname) self._existing_file = textfile self.imageview.set_file(file) self.set_text(self.generator.filter_input(textfile.read())) else: self._existing_file = None self.set_text( self.generator.filter_input(self.generator.get_default_text())) self.textview.grab_focus() def _stitch_fileextension(self, file, basename): '''Stitches the file extension from 'basename' to the path of 'file' and returns a File object. ''' i = basename.rfind('.') j = file.path.rfind('.') return File(file.path[:j] + basename[i:]) def set_text(self, text): '''Set text in the buffer''' buffer = self.textview.get_buffer() buffer.set_text(text) buffer.set_modified(False) def get_text(self): '''Get the text from the buffer @returns: text as string ''' buffer = self.textview.get_buffer() bounds = buffer.get_bounds() return buffer.get_text(*bounds) def generate_image(self): '''Update the image based on the text in the text buffer''' self.imagefile = None self.logfile = None text = self.get_text() text = self.generator.process_input(text) try: imagefile, logfile = self.generator.generate_image(text) except: logger.exception('Could not generate image') # TODO set "error" image instead of "broken" image # TODO set exception text as log message else: self.imagefile = imagefile self.logfile = logfile self.textview.get_buffer().set_modified(False) def preview(self): '''Action for the "Preview" button''' self.generate_image() self.imageview.set_file(self.imagefile) # if None sets broken image self.logbutton.set_sensitive(not self.logfile is None) def show_log(self): '''Action for the "View Log" button''' assert self.logfile, 'BUG: no logfile set (yet)' LogFileDialog(self, self.logfile).run() def do_response_ok(self): if not self.imagefile \ or self.textview.get_buffer().get_modified(): self.generate_image() if not (self.imagefile and self.imagefile.exists()): dialog = QuestionDialog( self, _('An error occurred while generating the image.\nDo you want to save the source text anyway?' )) # T: Question prompt when e.g. equation editor encountered an error generating the image to insert if not dialog.run(): return False if self._existing_file: textfile = self._existing_file else: page = self.app_window.ui.page # XXX dir = self.app_window.ui.notebook.get_attachments_dir(page) # XXX textfile = dir.new_file(self.generator.scriptname) textfile.write(self.generator.process_input(self.get_text())) imgfile = self._stitch_fileextension(textfile, self.generator.imagename) if self.imagefile and self.imagefile.exists(): self.imagefile.rename(imgfile) elif imgfile.exists(): imgfile.remove() if self._existing_file: self.app_window.ui.reload_page() # XXX else: pageview = self.app_window.pageview pageview.insert_image(imgfile, type=self.generator.object_type, interactive=False, force=True) if self.logfile and self.logfile.exists(): self.logfile.remove() return True def destroy(self): self.generator.cleanup() Dialog.destroy(self)
class ImageGeneratorDialog(Dialog): '''Dialog that provides text input and an image view for showing previews for an L{ImageGeneratorClass} implementation. ''' @classmethod def run_dialog_for_model(cls, widget, model, label, syntax): text, image_file = cls(widget, label, model.generator, model.image_file, model.get_text(), syntax).run() if text is not None: model.set_from_generator(text, image_file) model.generator.cleanup() def __init__(self, widget, label, generator, image_file=None, text='', syntax=None): title = _( 'Edit %s' ) % label # T: dialog title, %s is the object name like "Equation" Dialog.__init__(self, widget, title, defaultwindowsize=(450, 300)) self.generator = generator self.log_file = None self.image_file = image_file self.result = None, None self.vpane = VPaned() self.vpane.set_position(150) self.vbox.pack_start(self.vpane, True, True, 0) self.imageview = ImageView(bgcolor='#FFF') swin = ScrolledWindow(self.imageview) swin.set_size_request(200, 50) self.vpane.pack1(swin, resize=True) # TODO scrolled window and option to zoom in / real size window, textview = ScrolledSourceView(syntax=syntax) self.textview = textview self.textview.set_editable(True) self.vpane.pack2(window, resize=False) hbox = Gtk.HBox(spacing=5) self.vbox.pack_start(hbox, False, True, 0) self.previewbutton = Gtk.Button.new_with_mnemonic(_('_Preview')) # T: button in e.g. equation editor dialog self.previewbutton.set_sensitive(False) self.previewbutton.connect('clicked', lambda o: self.update_image()) hbox.pack_start(self.previewbutton, False, True, 0) self.textview.get_buffer().connect( 'modified-changed', lambda b: self.previewbutton.set_sensitive(b.get_modified())) self.logbutton = Gtk.Button.new_with_mnemonic(_('View _Log')) # T: button in e.g. equation editor dialog self.logbutton.set_sensitive(False) self.logbutton.connect('clicked', lambda o: self.show_log()) hbox.pack_start(self.logbutton, False, True, 0) self.set_text(text) self.imageview.set_file(self.image_file) # if None sets broken image self.textview.grab_focus() def set_text(self, text): buffer = self.textview.get_buffer() buffer.set_text(text) buffer.set_modified(False) def get_text(self): buffer = self.textview.get_buffer() start, end = buffer.get_bounds() text = start.get_text(end) return self.generator.check_user_input(text) def update_image(self): text = self.get_text() try: self.image_file, self.log_file = self.generator.generate_image( text) except Error as error: self.image_file, self.log_file = None, None show_error(error) self.textview.get_buffer().set_modified(False) self.imageview.set_file(self.image_file) # if None sets broken image self.logbutton.set_sensitive(self.log_file is not None) def show_log(self): assert self.logfile, 'BUG: no logfile set (yet)' LogFileDialog(self, self.logfile).run() def do_response_ok(self): buffer = self.textview.get_buffer() if buffer.get_modified(): self.update_image() if not (self.image_file and self.image_file.exists()): dialog = QuestionDialog( self, _('An error occurred while generating the image.\nDo you want to save the source text anyway?' )) # T: Question prompt when e.g. equation editor encountered an error generating the image to insert if not dialog.run(): return False self.result = (self.get_text(), self.image_file) return True
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'