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)
Esempio n. 2
0
    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
Esempio n. 4
0
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'