Ejemplo n.º 1
0
 def onShowRevisionDetails(self):
     rev = self.selection[0]
     if not self.revdetails:
         from tortoisehg.hgqt.revdetails import RevDetailsDialog
         self.revdetails = RevDetailsDialog(self._repoagent, rev=rev)
     else:
         self.revdetails.setRev(rev)
     self.revdetails.show()
     self.revdetails.raise_()
Ejemplo n.º 2
0
class FileLogDialog(_AbstractFileDialog):
    """
    A dialog showing a revision graph for a file.
    """
    def __init__(self, repoagent, filename):
        super(FileLogDialog, self).__init__(repoagent, filename)
        self._readSettings()
        self.menu = None
        self.dualmenu = None
        self.revdetails = None

    def closeEvent(self, event):
        self._writeSettings()
        super(FileLogDialog, self).closeEvent(event)

    def _readSettings(self):
        s = QSettings()
        s.beginGroup('filelog')
        try:
            self.textView.loadSettings(s, 'fileview')
            self.restoreGeometry(s.value('geom').toByteArray())
            self.splitter.restoreState(s.value('splitter').toByteArray())
            self.revpanel.set_expanded(s.value('revpanel.expanded').toBool())
        finally:
            s.endGroup()

    def _writeSettings(self):
        s = QSettings()
        s.beginGroup('filelog')
        try:
            self.textView.saveSettings(s, 'fileview')
            s.setValue('revpanel.expanded', self.revpanel.is_expanded())
            s.setValue('geom', self.saveGeometry())
            s.setValue('splitter', self.splitter.saveState())
        finally:
            s.endGroup()

    def setupUi(self, o):
        self.editToolbar = QToolBar(self)
        self.editToolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        self.addToolBar(Qt.ToolBarArea(Qt.TopToolBarArea), self.editToolbar)
        self.actionClose = QAction(self)
        self.actionClose.setShortcuts(QKeySequence.Close)
        self.actionReload = QAction(self)
        self.actionReload.setShortcuts(QKeySequence.Refresh)
        self.editToolbar.addAction(self.actionReload)
        self.addAction(self.actionClose)

        self.splitter = QSplitter(Qt.Vertical)
        self.setCentralWidget(self.splitter)
        cs = ('fileLogDialog', _('File History Log Columns'))
        self.repoview = repoview.HgRepoView(self.repo, cs[0], cs, self.splitter)
        self.repoview.revisionSelectionChanged.connect(
            self._checkValidSelection)

        self.contentframe = QFrame(self.splitter)

        vbox = QVBoxLayout()
        vbox.setSpacing(0)
        vbox.setMargin(0)
        self.contentframe.setLayout(vbox)

        self.revpanel = revpanel.RevPanelWidget(self.repo)
        self.revpanel.linkActivated.connect(self.onLinkActivated)
        vbox.addWidget(self.revpanel, 0)

        self.textView = fileview.HgFileView(self._repoagent, self)
        self.textView.revisionSelected.connect(self.goto)
        vbox.addWidget(self.textView, 1)

    def setupViews(self):
        self.textView.showMessage.connect(self.statusBar().showMessage)

    def setupToolbars(self):
        self.editToolbar.addSeparator()
        self.editToolbar.addAction(self.actionBack)
        self.editToolbar.addAction(self.actionForward)

    def setupModels(self):
        self.filerevmodel = filerevmodel.FileRevModel(self.repo,
                                         self.repoview.colselect[0],
                                         parent=self)
        self.repoview.setModel(self.filerevmodel)
        self.repoview.revisionSelected.connect(self.onRevisionSelected)
        self.repoview.revisionActivated.connect(self.onRevisionActivated)
        self.repoview.menuRequested.connect(self.viewMenuRequest)
        self.filerevmodel.showMessage.connect(self.statusBar().showMessage)
        self.filerevmodel.filled.connect(self.modelFilled)
        self.filerevmodel.setFilename(self.filename)

    def createActions(self):
        self.actionClose.triggered.connect(self.close)
        self.actionReload.triggered.connect(self.reload)
        self.actionReload.setIcon(qtlib.geticon('view-refresh'))

        self.actionBack = QAction(_('Back'), self, enabled=False,
                                  icon=qtlib.geticon('go-previous'))
        self.actionForward = QAction(_('Forward'), self, enabled=False,
                                     icon=qtlib.geticon('go-next'))
        self.repoview.revisionSelected.connect(self._updateHistoryActions)
        self.actionBack.triggered.connect(self.repoview.back)
        self.actionForward.triggered.connect(self.repoview.forward)

    @pyqtSlot()
    def _updateHistoryActions(self):
        self.actionBack.setEnabled(self.repoview.canGoBack())
        self.actionForward.setEnabled(self.repoview.canGoForward())

    def modelFilled(self):
        self.repoview.resizeColumns()
        if self._show_rev is not None:
            index = self.filerevmodel.indexLinkedFromRev(self._show_rev)
            self._show_rev = None
        elif self.repoview.currentIndex().isValid():
            return  # already set by goto()
        else:
            index = self.filerevmodel.index(0,0)
        if index is not None:
            self.repoview.setCurrentIndex(index)

    @pyqtSlot(QPoint, object)
    def viewMenuRequest(self, point, selection):
        'User requested a context menu in repo view widget'
        if not selection or len(selection) > 2:
            return
        if len(selection) == 2:
            if self.dualmenu is None:
                self.dualmenu = menu = QMenu(self)
                a = menu.addAction(_('&Diff Selected Changesets'))
                a.triggered.connect(self.onVisualDiffRevs)
                a = menu.addAction(_('Diff Selected &File Revisions'))
                a.setIcon(qtlib.geticon('visualdiff'))
                a.triggered.connect(self.onVisualDiffFileRevs)
            else:
                menu = self.dualmenu
        elif self.menu is None:
            self.menu = menu = QMenu(self)
            a = menu.addAction(_('&Diff Changeset to Parent'))
            a.setIcon(qtlib.geticon('visualdiff'))
            a.triggered.connect(self.onVisualDiff)
            a = menu.addAction(_('Diff Changeset to &Local'))
            a.setIcon(qtlib.geticon('ldiff'))
            a.triggered.connect(self.onVisualDiffToLocal)
            menu.addSeparator()
            a = menu.addAction(_('Diff &File to Parent'))
            a.setIcon(qtlib.geticon('visualdiff'))
            a.triggered.connect(self.onVisualDiffFile)
            a = menu.addAction(_('Diff File to Lo&cal'))
            a.setIcon(qtlib.geticon('ldiff'))
            a.triggered.connect(self.onVisualDiffFileToLocal)
            menu.addSeparator()
            a = menu.addAction(_('&View at Revision'))
            a.setIcon(qtlib.geticon('view-at-revision'))
            a.triggered.connect(self.onViewFileAtRevision)
            a = menu.addAction(_('&Save at Revision...'))
            a.triggered.connect(self.onSaveFileAtRevision)
            a = menu.addAction(_('&Edit Local'))
            a.setIcon(qtlib.geticon('edit-file'))
            a.triggered.connect(self.onEditLocal)
            a = menu.addAction(_('&Revert to Revision...'))
            a.setIcon(qtlib.geticon('hg-revert'))
            a.triggered.connect(self.onRevertFileToRevision)
            menu.addSeparator()
            a = menu.addAction(_('Show Revision &Details'))
            a.setIcon(qtlib.geticon('hg-log'))
            a.triggered.connect(self.onShowRevisionDetails)
        else:
            menu = self.menu
        self.selection = selection
        menu.exec_(point)

    def onVisualDiff(self):
        opts = dict(change=self.selection[0])
        dlg = visdiff.visualdiff(self.repo.ui, self.repo, [], opts)
        if dlg:
            dlg.exec_()

    def onVisualDiffToLocal(self):
        opts = dict(rev=['rev(%d)' % self.selection[0]])
        dlg = visdiff.visualdiff(self.repo.ui, self.repo, [], opts)
        if dlg:
            dlg.exec_()

    def onVisualDiffRevs(self):
        revs = self.selection
        if len(revs) != 2:
            self.textView.showMessage.emit(_('You must select two revisions to diff'))
            return
        opts = dict(rev=revs)
        dlg = visdiff.visualdiff(self.repo.ui, self.repo, [], opts)
        if dlg:
            dlg.exec_()

    def onVisualDiffFile(self):
        rev = self.selection[0]
        paths = [self.filerevmodel.graph.filename(rev)]
        opts = dict(change=self.selection[0])
        dlg = visdiff.visualdiff(self.repo.ui, self.repo, paths, opts)
        if dlg:
            dlg.exec_()

    def onVisualDiffFileToLocal(self):
        rev = self.selection[0]
        paths = [self.filerevmodel.graph.filename(rev)]
        opts = dict(rev=['rev(%d)' % rev])
        dlg = visdiff.visualdiff(self.repo.ui, self.repo, paths, opts)
        if dlg:
            dlg.exec_()

    def onVisualDiffFileRevs(self):
        revs = self.selection
        if len(revs) != 2:
            self.textView.showMessage.emit(_('You must select two revisions to diff'))
            return
        paths = [self.filerevmodel.graph.filename(revs[0])]
        opts = dict(rev=['rev(%d)' % rev for rev in revs])
        dlg = visdiff.visualdiff(self.repo.ui, self.repo, paths, opts)
        if dlg:
            dlg.exec_()

    def onEditLocal(self):
        filenames = [self.filename]
        if not filenames:
            return
        qtlib.editfiles(self.repo, filenames, parent=self)

    def onRevertFileToRevision(self):
        rev = self.selection[0]
        if rev is None:
            rev = self.repo['.'].rev()
        fileSelection = [self.filerevmodel.graph.filename(rev)]
        if len(fileSelection) == 0:
            return
        dlg = revert.RevertDialog(self.repo, fileSelection, rev, self)
        if dlg:
            dlg.exec_()
            dlg.deleteLater()

    def onViewFileAtRevision(self):
        rev = self.selection[0]
        filenames = [self.filerevmodel.graph.filename(rev)]
        if not filenames:
            return
        if rev is None:
            qtlib.editfiles(self.repo, filenames, parent=self)
        else:
            base, _ = visdiff.snapshot(self.repo, filenames, self.repo[rev])
            files = [os.path.join(base, filename)
                     for filename in filenames]
            qtlib.editfiles(self.repo, files, parent=self)

    def onSaveFileAtRevision(self, rev):
        rev = self.selection[0]
        files = [self.filerevmodel.graph.filename(rev)]
        if not files or rev is None:
            return
        else:
            qtlib.savefiles(self.repo, files, rev, parent=self)

    def onShowRevisionDetails(self):
        rev = self.selection[0]
        if not self.revdetails:
            from tortoisehg.hgqt.revdetails import RevDetailsDialog
            self.revdetails = RevDetailsDialog(self._repoagent, rev=rev)
        else:
            self.revdetails.setRev(rev)
        self.revdetails.show()
        self.revdetails.raise_()

    @pyqtSlot(QString)
    def onLinkActivated(self, link):
        link = unicode(link)
        if ':' in link:
            scheme, param = link.split(':', 1)
            if scheme == 'cset':
                rev = self.repo[hglib.fromunicode(param)].rev()
                return self.goto(rev)
        QDesktopServices.openUrl(QUrl(link))

    def onRevisionSelected(self, rev):
        pos = self.textView.verticalScrollBar().value()
        ctx = self.filerevmodel.repo.changectx(rev)
        self.textView.setContext(ctx)
        self.textView.displayFile(self.filerevmodel.graph.filename(rev), None)
        self.textView.verticalScrollBar().setValue(pos)
        self.revpanel.set_revision(rev)
        self.revpanel.update(repo = self.repo)

    # It does not make sense to select more than two revisions at a time.
    # Rather than enforcing a max selection size we simply let the user
    # know when it has selected too many revisions by using the status bar
    @pyqtSlot()
    def _checkValidSelection(self):
        selection = self.repoview.selectedRevisions()
        if len(selection) > 2:
            msg = _('Too many rows selected for menu')
        else:
            msg = ''
        self.textView.showMessage.emit(msg)

    def goto(self, rev):
        index = self.filerevmodel.indexLinkedFromRev(rev)
        if index is not None:
            self.repoview.setCurrentIndex(index)
        else:
            self._show_rev = rev

    def showLine(self, line):
        self.textView.showLine(line - 1)  # fileview should do -1 instead?

    def setFileViewMode(self, mode):
        self.textView.setMode(mode)

    def setSearchPattern(self, text):
        self.textView.searchbar.setPattern(text)

    def setSearchCaseInsensitive(self, ignorecase):
        self.textView.searchbar.setCaseInsensitive(ignorecase)

    def reload(self):
        self.repoview.saveSettings()
        super(FileLogDialog, self).reload()
Ejemplo n.º 3
0
class FileLogDialog(_AbstractFileDialog):
    """
    A dialog showing a revision graph for a file.
    """
    def __init__(self, repoagent, filename):
        super(FileLogDialog, self).__init__(repoagent, filename)
        self._readSettings()
        self.revdetails = None

    def closeEvent(self, event):
        self._writeSettings()
        super(FileLogDialog, self).closeEvent(event)

    def _readSettings(self):
        s = QSettings()
        s.beginGroup('filelog')
        try:
            self.textView.loadSettings(s, 'fileview')
            self.restoreGeometry(s.value('geom').toByteArray())
            self.splitter.restoreState(s.value('splitter').toByteArray())
            self.revpanel.set_expanded(s.value('revpanel.expanded').toBool())
        finally:
            s.endGroup()

    def _writeSettings(self):
        s = QSettings()
        s.beginGroup('filelog')
        try:
            self.textView.saveSettings(s, 'fileview')
            s.setValue('revpanel.expanded', self.revpanel.is_expanded())
            s.setValue('geom', self.saveGeometry())
            s.setValue('splitter', self.splitter.saveState())
        finally:
            s.endGroup()

        self.repoview.saveSettings()

    def setupUi(self):
        self.editToolbar = QToolBar(self)
        self.editToolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        self.addToolBar(Qt.ToolBarArea(Qt.TopToolBarArea), self.editToolbar)
        self.actionClose = QAction(self)
        self.actionClose.setShortcuts(QKeySequence.Close)
        self.actionReload = QAction(self)
        self.actionReload.setShortcuts(QKeySequence.Refresh)
        self.editToolbar.addAction(self.actionReload)
        self.addAction(self.actionClose)

        self.splitter = QSplitter(Qt.Vertical)
        self.setCentralWidget(self.splitter)
        cs = ('fileLogDialog', _('File History Log Columns'))
        self.repoview = repoview.HgRepoView(self._repoagent, cs[0], cs,
                                            self.splitter)

        self.contentframe = QFrame(self.splitter)

        vbox = QVBoxLayout()
        vbox.setSpacing(0)
        vbox.setMargin(0)
        self.contentframe.setLayout(vbox)

        self.revpanel = revpanel.RevPanelWidget(self.repo)
        self.revpanel.linkActivated.connect(self.onLinkActivated)
        vbox.addWidget(self.revpanel, 0)

        self.textView = fileview.HgFileView(self._repoagent, self)
        self.textView.revisionSelected.connect(self.goto)
        vbox.addWidget(self.textView, 1)

    def setupViews(self):
        self.textView.showMessage.connect(self.statusBar().showMessage)

    def setupToolbars(self):
        self.editToolbar.addSeparator()
        self.editToolbar.addAction(self.actionBack)
        self.editToolbar.addAction(self.actionForward)

    def setupModels(self):
        self.filerevmodel = repomodel.FileRevModel(
            self._repoagent, self.filename, parent=self)
        self.repoview.setModel(self.filerevmodel)
        self.repoview.revisionSelected.connect(self.onRevisionSelected)
        self.repoview.revisionActivated.connect(self.onRevisionActivated)
        self.repoview.menuRequested.connect(self.viewMenuRequest)
        selmodel = self.repoview.selectionModel()
        selmodel.selectionChanged.connect(self._onRevisionSelectionChanged)
        self.filerevmodel.showMessage.connect(self.statusBar().showMessage)
        QTimer.singleShot(0, self._updateRepoViewForModel)

    def createActions(self):
        self.actionClose.triggered.connect(self.close)
        self.actionReload.triggered.connect(self.reload)
        self.actionReload.setIcon(qtlib.geticon('view-refresh'))

        self.actionBack = QAction(_('Back'), self, enabled=False,
                                  shortcut=QKeySequence.Back,
                                  icon=qtlib.geticon('go-previous'))
        self.actionForward = QAction(_('Forward'), self, enabled=False,
                                     shortcut=QKeySequence.Forward,
                                     icon=qtlib.geticon('go-next'))
        self.repoview.revisionSelected.connect(self._updateHistoryActions)
        self.actionBack.triggered.connect(self.repoview.back)
        self.actionForward.triggered.connect(self.repoview.forward)

        self._fileactions = filectxactions.FilectxActions(self._repoagent, self)
        self.addActions(self._fileactions.actions())

    def _updateFileActions(self):
        selmodel = self.repoview.selectionModel()
        selfds = _fileDataListForSelection(self.filerevmodel, selmodel)
        self._fileactions.setFileDataList(selfds)
        if len(selmodel.selectedRows()) > 1:
            texts = {'visualDiff': _('Diff Selected &Changesets'),
                     'visualDiffFile': _('&Diff Selected File Revisions')}
        else:
            texts = {'visualDiff': _('Diff &Changeset to Parent'),
                     'visualDiffFile': _('&Diff to Parent')}
        for n, t in texts.iteritems():
            self._fileactions.action(n).setText(t)

    @pyqtSlot()
    def _updateHistoryActions(self):
        self.actionBack.setEnabled(self.repoview.canGoBack())
        self.actionForward.setEnabled(self.repoview.canGoForward())

    @pyqtSlot()
    def _updateRepoViewForModel(self):
        self.repoview.resizeColumns()
        if self._show_rev is not None:
            index = self.filerevmodel.indexLinkedFromRev(self._show_rev)
            self._show_rev = None
        elif self.repoview.currentIndex().isValid():
            return  # already set by goto()
        else:
            index = self.filerevmodel.index(0,0)
        self.repoview.setCurrentIndex(index)

    @pyqtSlot(QPoint, object)
    def viewMenuRequest(self, point, selection):
        'User requested a context menu in repo view widget'
        if not selection or len(selection) > 2:
            return
        menu = QMenu(self)
        if len(selection) == 2:
            for name in ['visualDiff', 'visualDiffFile']:
                menu.addAction(self._fileactions.action(name))
        else:
            _setupFileMenu(menu, self._fileactions)
            menu.addSeparator()
            a = menu.addAction(_('Show Revision &Details'))
            a.setIcon(qtlib.geticon('hg-log'))
            a.triggered.connect(self.onShowRevisionDetails)
        menu.setAttribute(Qt.WA_DeleteOnClose)
        menu.popup(point)

    def onShowRevisionDetails(self):
        rev = self.repoview.selectedRevisions()[0]
        if not self.revdetails:
            from tortoisehg.hgqt.revdetails import RevDetailsDialog
            self.revdetails = RevDetailsDialog(self._repoagent, rev=rev)
        else:
            self.revdetails.setRev(rev)
        self.revdetails.show()
        self.revdetails.raise_()

    @pyqtSlot(str)
    def onLinkActivated(self, link):
        link = unicode(link)
        if ':' in link:
            scheme, param = link.split(':', 1)
            if scheme == 'cset':
                rev = self.repo[hglib.fromunicode(param)].rev()
                return self.goto(rev)
        QDesktopServices.openUrl(QUrl(link))

    def onRevisionSelected(self, rev):
        pos = self.textView.verticalScrollBar().value()
        fd = self.filerevmodel.fileData(self.repoview.currentIndex())
        self.textView.display(fd)
        self.textView.verticalScrollBar().setValue(pos)
        self.revpanel.set_revision(rev)
        self.revpanel.update(repo = self.repo)

    @pyqtSlot()
    def _onRevisionSelectionChanged(self):
        self._checkValidSelection()
        self._updateFileActions()

    # It does not make sense to select more than two revisions at a time.
    # Rather than enforcing a max selection size we simply let the user
    # know when it has selected too many revisions by using the status bar
    def _checkValidSelection(self):
        selection = self.repoview.selectedRevisions()
        if len(selection) > 2:
            msg = _('Too many rows selected for menu')
        else:
            msg = ''
        self.textView.showMessage.emit(msg)

    def goto(self, rev):
        index = self.filerevmodel.indexLinkedFromRev(rev)
        if index.isValid():
            self.repoview.setCurrentIndex(index)
        else:
            self._show_rev = rev

    def showLine(self, line):
        self.textView.showLine(line - 1)  # fileview should do -1 instead?

    def setFileViewMode(self, mode):
        self.textView.setMode(mode)

    def setSearchPattern(self, text):
        self.textView.searchbar.setPattern(text)

    def setSearchCaseInsensitive(self, ignorecase):
        self.textView.searchbar.setCaseInsensitive(ignorecase)
Ejemplo n.º 4
0
class FileLogDialog(_AbstractFileDialog):
    """
    A dialog showing a revision graph for a file.
    """
    def __init__(self, repoagent, filename):
        super(FileLogDialog, self).__init__(repoagent, filename)
        self._readSettings()
        self.revdetails = None

    def closeEvent(self, event):
        self._writeSettings()
        super(FileLogDialog, self).closeEvent(event)

    def _readSettings(self):
        s = QSettings()
        s.beginGroup('filelog')
        try:
            self.textView.loadSettings(s, 'fileview')
            self.restoreGeometry(qtlib.readByteArray(s, 'geom'))
            self.splitter.restoreState(qtlib.readByteArray(s, 'splitter'))
            self.revpanel.set_expanded(qtlib.readBool(s, 'revpanel.expanded'))
        finally:
            s.endGroup()

    def _writeSettings(self):
        s = QSettings()
        s.beginGroup('filelog')
        try:
            self.textView.saveSettings(s, 'fileview')
            s.setValue('revpanel.expanded', self.revpanel.is_expanded())
            s.setValue('geom', self.saveGeometry())
            s.setValue('splitter', self.splitter.saveState())
        finally:
            s.endGroup()

        self.repoview.saveSettings()

    def setupUi(self):
        self.editToolbar = QToolBar(self)
        self.editToolbar.setContextMenuPolicy(Qt.PreventContextMenu)
        self.addToolBar(Qt.ToolBarArea(Qt.TopToolBarArea), self.editToolbar)
        self.actionClose = QAction(self)
        self.actionClose.setShortcuts(QKeySequence.Close)
        self.actionReload = QAction(self)
        self.actionReload.setShortcuts(QKeySequence.Refresh)
        self.editToolbar.addAction(self.actionReload)
        self.addAction(self.actionClose)

        self.splitter = QSplitter(Qt.Vertical)
        self.setCentralWidget(self.splitter)
        cs = ('fileLogDialog', _('File History Log Columns'))
        self.repoview = repoview.HgRepoView(self._repoagent, cs[0], cs,
                                            self.splitter)

        self.contentframe = QFrame(self.splitter)

        vbox = QVBoxLayout()
        vbox.setSpacing(0)
        vbox.setContentsMargins(0, 0, 0, 0)
        self.contentframe.setLayout(vbox)

        self.revpanel = revpanel.RevPanelWidget(self.repo)
        self.revpanel.linkActivated.connect(self.onLinkActivated)
        vbox.addWidget(self.revpanel, 0)

        self.textView = fileview.HgFileView(self._repoagent, self)
        self.textView.revisionSelected.connect(self.goto)
        vbox.addWidget(self.textView, 1)

    def setupViews(self):
        self.textView.showMessage.connect(self.statusBar().showMessage)

    def setupToolbars(self):
        self.editToolbar.addSeparator()
        self.editToolbar.addAction(self.actionBack)
        self.editToolbar.addAction(self.actionForward)

    def setupModels(self):
        self.filerevmodel = repomodel.FileRevModel(
            self._repoagent, self.filename, parent=self)
        self.repoview.setModel(self.filerevmodel)
        self.repoview.revisionSelected.connect(self.onRevisionSelected)
        self.repoview.revisionActivated.connect(self.onRevisionActivated)
        self.repoview.menuRequested.connect(self.viewMenuRequest)
        selmodel = self.repoview.selectionModel()
        selmodel.selectionChanged.connect(self._onRevisionSelectionChanged)
        self.filerevmodel.showMessage.connect(self.statusBar().showMessage)
        QTimer.singleShot(0, self._updateRepoViewForModel)

    def createActions(self):
        self.actionClose.triggered.connect(self.close)
        self.actionReload.triggered.connect(self.reload)
        self.actionReload.setIcon(qtlib.geticon('view-refresh'))

        self.actionBack = QAction(_('Back'), self, enabled=False,
                                  shortcut=QKeySequence.Back,
                                  icon=qtlib.geticon('go-previous'))
        self.actionForward = QAction(_('Forward'), self, enabled=False,
                                     shortcut=QKeySequence.Forward,
                                     icon=qtlib.geticon('go-next'))
        self.repoview.revisionSelected.connect(self._updateHistoryActions)
        self.actionBack.triggered.connect(self.repoview.back)
        self.actionForward.triggered.connect(self.repoview.forward)

        self._fileactions = filectxactions.FilectxActions(self._repoagent, self)
        self.addActions(self._fileactions.actions())

    def _updateFileActions(self):
        selmodel = self.repoview.selectionModel()
        selfds = _fileDataListForSelection(self.filerevmodel, selmodel)
        self._fileactions.setFileDataList(selfds)
        if len(selmodel.selectedRows()) > 1:
            texts = {'visualDiff': _('Diff Selected &Changesets'),
                     'visualDiffFile': _('&Diff Selected File Revisions')}
        else:
            texts = {'visualDiff': _('Diff &Changeset to Parent'),
                     'visualDiffFile': _('&Diff to Parent')}
        for n, t in texts.iteritems():
            self._fileactions.action(n).setText(t)

    @pyqtSlot()
    def _updateHistoryActions(self):
        self.actionBack.setEnabled(self.repoview.canGoBack())
        self.actionForward.setEnabled(self.repoview.canGoForward())

    @pyqtSlot()
    def _updateRepoViewForModel(self):
        self.repoview.resizeColumns()
        if self._show_rev is not None:
            index = self.filerevmodel.indexLinkedFromRev(self._show_rev)
            self._show_rev = None
        elif self.repoview.currentIndex().isValid():
            return  # already set by goto()
        else:
            index = self.filerevmodel.index(0,0)
        self.repoview.setCurrentIndex(index)

    @pyqtSlot(QPoint, object)
    def viewMenuRequest(self, point, selection):
        'User requested a context menu in repo view widget'
        if not selection or len(selection) > 2:
            return
        menu = QMenu(self)
        if len(selection) == 2:
            for name in ['visualDiff', 'visualDiffFile']:
                menu.addAction(self._fileactions.action(name))
        else:
            _setupFileMenu(menu, self._fileactions)
            menu.addSeparator()
            a = menu.addAction(_('Show Revision &Details'))
            a.setIcon(qtlib.geticon('hg-log'))
            a.triggered.connect(self.onShowRevisionDetails)
        menu.setAttribute(Qt.WA_DeleteOnClose)
        menu.popup(point)

    def onShowRevisionDetails(self):
        rev = self.repoview.selectedRevisions()[0]
        if not self.revdetails:
            from tortoisehg.hgqt.revdetails import RevDetailsDialog
            self.revdetails = RevDetailsDialog(self._repoagent, rev=rev)
        else:
            self.revdetails.setRev(rev)
        self.revdetails.show()
        self.revdetails.raise_()

    @pyqtSlot(str)
    def onLinkActivated(self, link):
        link = unicode(link)
        if ':' in link:
            scheme, param = link.split(':', 1)
            if scheme == 'cset':
                rev = self.repo[hglib.fromunicode(param)].rev()
                return self.goto(rev)
        QDesktopServices.openUrl(QUrl(link))

    def onRevisionSelected(self, rev):
        pos = self.textView.verticalScrollBar().value()
        fd = self.filerevmodel.fileData(self.repoview.currentIndex())
        self.textView.display(fd)
        self.textView.verticalScrollBar().setValue(pos)
        self.revpanel.set_revision(rev)
        self.revpanel.update(repo = self.repo)

    @pyqtSlot()
    def _onRevisionSelectionChanged(self):
        self._checkValidSelection()
        self._updateFileActions()

    # It does not make sense to select more than two revisions at a time.
    # Rather than enforcing a max selection size we simply let the user
    # know when it has selected too many revisions by using the status bar
    def _checkValidSelection(self):
        selection = self.repoview.selectedRevisions()
        if len(selection) > 2:
            msg = _('Too many rows selected for menu')
        else:
            msg = ''
        self.textView.showMessage.emit(msg)

    def goto(self, rev):
        index = self.filerevmodel.indexLinkedFromRev(rev)
        if index.isValid():
            self.repoview.setCurrentIndex(index)
        else:
            self._show_rev = rev

    def showLine(self, line):
        self.textView.showLine(line - 1)  # fileview should do -1 instead?

    def setFileViewMode(self, mode):
        self.textView.setMode(mode)

    def setSearchPattern(self, text):
        self.textView.searchbar.setPattern(text)

    def setSearchCaseInsensitive(self, ignorecase):
        self.textView.searchbar.setCaseInsensitive(ignorecase)