コード例 #1
0
    def _setupmodel(self):
        self._treemodel = ManifestModel(
            self._repo,
            self._rev,
            statusfilter=self._statusfilter.status(),
            parent=self)
        self._treemodel.setNameFilter(self.le.text())

        oldmodel = self._treeview.model()
        oldselmodel = self._treeview.selectionModel()
        self._treeview.setModel(self._treemodel)
        if oldmodel:
            oldmodel.deleteLater()
        if oldselmodel:
            oldselmodel.deleteLater()

        selmodel = self._treeview.selectionModel()
        selmodel.currentChanged.connect(self._updatecontent)
        selmodel.currentChanged.connect(self._updateItemFileActions)
        selmodel.currentChanged.connect(self._emitPathChanged)

        self._statusfilter.statusChanged.connect(
            self._treemodel.setStatusFilter)
        self._statusfilter.statusChanged.connect(self._autoexpandtree)
        self._autoexpandtree()
コード例 #2
0
    def test_status_filter_change(self):
        m = ManifestModel(self.repo, rev=1)
        m.setStatusFilter('C')
        self.assertEqual(QModelIndex(), m.indexFromPath('bar'))  # modified
        self.assertNotEqual(QModelIndex(), m.indexFromPath('foo'))  # clean

        m.setStatusFilter('M')
        self.assertNotEqual(QModelIndex(), m.indexFromPath('bar'))  # modified
        self.assertEqual(QModelIndex(), m.indexFromPath('foo'))  # clean
コード例 #3
0
 def test_name_filter(self):
     m = ManifestModel(self.repo, rev=0)
     m.setNameFilter('ax')
     self.assertFalse(m.indexFromPath('bar').isValid())
     self.assertTrue(m.indexFromPath('baz/bax').isValid())
     self.assertFalse(m.indexFromPath('baz/box').isValid())
     self.assertFalse(m.indexFromPath('foo').isValid())
コード例 #4
0
 def test_status_filter_multi(self):
     m = ManifestModel(self.repo, rev=1)
     m.setStatusFilter('MC')
     self.assertNotEqual(QModelIndex(), m.indexFromPath('bar'))  # modified
     self.assertEqual(QModelIndex(), m.indexFromPath('zzz'))  # added
     self.assertEqual(QModelIndex(), m.indexFromPath('baz/box'))  # removed
     self.assertNotEqual(QModelIndex(), m.indexFromPath('foo'))  # clean
コード例 #5
0
 def test_indexfrompath(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertEqual(QModelIndex(), m.indexFromPath(''))
     self.assertEqual(m.index(1, 0), m.indexFromPath('bar'))
     self.assertEqual(m.index(0, 0), m.indexFromPath('baz'))
     self.assertEqual(m.index(0, 0, m.index(0, 0)),
                      m.indexFromPath('baz/bax'))
コード例 #6
0
    def _setupmodel(self):
        self._treemodel = ManifestModel(self._repo, self._rev, statusfilter=self._statusfilter.status(), parent=self)
        oldmodel = self._treeview.model()
        oldselmodel = self._treeview.selectionModel()
        self._treeview.setModel(self._treemodel)
        if oldmodel:
            oldmodel.deleteLater()
        if oldselmodel:
            oldselmodel.deleteLater()

        selmodel = self._treeview.selectionModel()
        selmodel.currentChanged.connect(self._updatecontent)
        selmodel.currentChanged.connect(self._emitPathChanged)

        self._statusfilter.statusChanged.connect(self._treemodel.setStatusFilter)
        self._statusfilter.statusChanged.connect(self._autoexpandtree)
        self._autoexpandtree()
コード例 #7
0
 def test_rowcount_invalid(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertEqual(0, m.rowCount(m.index(1, 0)))
コード例 #8
0
 def test_rowcount_subdirs(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertEqual(2, m.rowCount(m.index(0, 0)))
コード例 #9
0
    def test_status_role(self):
        m = ManifestModel(self.repo, rev=0)
        self.assertEqual('A', m.data(m.indexFromPath('foo'),
                                     role=ManifestModel.StatusRole))

        m = ManifestModel(self.repo, rev=1)
        m.setStatusFilter('MARC')
        self.assertEqual('C', m.data(m.indexFromPath('foo'),
                                     role=ManifestModel.StatusRole))
        self.assertEqual('R', m.data(m.indexFromPath('baz/box'),
                                     role=ManifestModel.StatusRole))
コード例 #10
0
 def test_indexfrompath_qstr(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertEqual(m.index(1, 0), m.indexFromPath(QString('bar')))
コード例 #11
0
 def test_fileicon_path_concat(self):
     m = ManifestModel(self.repo, rev=0)
     m.fileIcon(m.indexFromPath(_aloha_ja + '.txt'))  # no unicode error
コード例 #12
0
 def test_indexfrompath(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertEqual(m.index(0, 0), m.indexFromPath(_aloha_ja))
コード例 #13
0
 def test_pathfromindex(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertEqual(_aloha_ja, m.filePath(m.index(0, 0)))
コード例 #14
0
 def test_data(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertEqual(_aloha_ja, m.data(m.index(0, 0)))
コード例 #15
0
 def test_pathfromindex(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertEqual('', m.filePath(QModelIndex()))
     self.assertEqual('bar', m.filePath(m.index(1, 0)))
     self.assertEqual('baz', m.filePath(m.index(0, 0)))
     self.assertEqual('baz/bax', m.filePath(m.index(0, 0, m.index(0, 0))))
コード例 #16
0
 def test_data(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertEqual('bar', m.data(m.index(1, 0)))
     self.assertEqual('baz', m.data(m.index(0, 0)))
     self.assertEqual('foo', m.data(m.index(2, 0)))
コード例 #17
0
 def test_data_subdir(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertEqual('bax', m.data(m.index(0, 0, m.index(0, 0))))
     self.assertEqual('box', m.data(m.index(1, 0, m.index(0, 0))))
コード例 #18
0
 def test_removed_should_be_listed(self):
     m = ManifestModel(self.repo, rev=1)
     m.setStatusFilter('MARC')
     self.assertTrue(m.indexFromPath('baz/box').isValid())
コード例 #19
0
 def test_data_inexistent(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertEqual(None, m.data(QModelIndex()))
     self.assertEqual(None, m.data(m.index(0, 0, m.index(1, 0))))
コード例 #20
0
class ManifestWidget(QWidget, qtlib.TaskWidget):
    """Display file tree and contents at the specified revision"""

    revChanged = pyqtSignal(object)
    """Emitted (rev) when the current revision changed"""

    pathChanged = pyqtSignal(unicode)
    """Emitted (path) when the current file path changed"""

    showMessage = pyqtSignal(unicode)
    """Emitted when to show revision summary as a hint"""

    grepRequested = pyqtSignal(unicode, dict)
    """Emitted (pattern, opts) when user request to search changelog"""

    linkActivated = pyqtSignal(QString)
    """Emitted (path) when user clicks on link"""

    revsetFilterRequested = pyqtSignal(QString)
    """Ask the repowidget to change its revset filter"""

    runCustomCommandRequested = pyqtSignal(str, list)
    """Emitted when selects a custom tool on the context menu"""
    def canswitch(self):
        return False

    def __init__(self, repoagent, rev=None, parent=None):
        super(ManifestWidget, self).__init__(parent)
        self._repoagent = repoagent
        # TODO: replace by repoagent if setRepo(bundlerepo) can be removed
        self._repo = repoagent.rawRepo()
        self._rev = rev
        self._selectedrev = rev

        self._initwidget()
        self._initactions()
        self._setupmodel()
        self._setupfilterupdater()

        self._treeview.setCurrentIndex(self._treemodel.index(0, 0))
        self.setRev(self._rev)

    def _initwidget(self):
        self.setLayout(QVBoxLayout())
        self._splitter = QSplitter()
        self.layout().addWidget(self._splitter)
        self.layout().setContentsMargins(2, 2, 2, 2)

        navlayout = QVBoxLayout(spacing=0)
        navlayout.setContentsMargins(0, 0, 0, 0)
        self._toolbar = QToolBar()
        self._toolbar.setIconSize(QSize(16, 16))
        self._toolbar.setStyleSheet(qtlib.tbstylesheet)
        self._treeview = QManifestTreeView(self,
                                           headerHidden=True,
                                           dragEnabled=True)
        self._treeview.setContextMenuPolicy(Qt.CustomContextMenu)
        self._treeview.customContextMenuRequested.connect(self.menuRequest)
        self._treeview.doubleClicked.connect(self.onDoubleClick)
        navlayout.addWidget(self._toolbar)
        navlayout.addWidget(self._treeview)
        navlayoutw = QWidget()
        navlayoutw.setLayout(navlayout)

        self._splitter.addWidget(navlayoutw)
        self._splitter.setStretchFactor(0, 1)

        vbox = QVBoxLayout(spacing=0)
        vbox.setMargin(0)
        self.revpanel = revpanel.RevPanelWidget(self._repo)
        self.revpanel.linkActivated.connect(self.linkActivated)
        vbox.addWidget(self.revpanel, 0)
        self._fileview = fileview.HgFileView(self._repoagent, self)
        vbox.addWidget(self._fileview, 0)
        w = QWidget()
        w.setLayout(vbox)
        self._splitter.addWidget(w)

        self._splitter.setStretchFactor(1, 3)
        self._fileview.revisionSelected.connect(self.setRev)
        self._fileview.linkActivated.connect(self.linkActivated)
        for name in ('showMessage', 'grepRequested'):
            getattr(self._fileview, name).connect(getattr(self, name))

    def loadSettings(self, qs, prefix):
        prefix += '/manifest'
        self._fileview.loadSettings(qs, prefix + '/fileview')
        self._splitter.restoreState(
            qs.value(prefix + '/splitter').toByteArray())
        expanded = qs.value(prefix + '/revpanel.expanded', False).toBool()
        self.revpanel.set_expanded(expanded)

    def saveSettings(self, qs, prefix):
        prefix += '/manifest'
        self._fileview.saveSettings(qs, prefix + '/fileview')
        qs.setValue(prefix + '/splitter', self._splitter.saveState())
        qs.setValue(prefix + '/revpanel.expanded', self.revpanel.is_expanded())

    def _initactions(self):
        self.le = QManifestLineEdit()  #QLineEdit()
        if hasattr(self.le, 'setPlaceholderText'):  # Qt >= 4.7
            self.le.setPlaceholderText(_('### filter text ###'))
        else:
            lbl = QLabel(_('Filter:'))
            self._toolbar.addWidget(lbl)
        self.le.keypressed.connect(self._treeview.setFocus)
        self._treeview.topreached.connect(self.le.setFocus)
        self._toolbar.addWidget(self.le)

        self._statusfilter = status.StatusFilterButton(statustext='MASC',
                                                       text=_('Status'))
        self._toolbar.addWidget(self._statusfilter)

        self._fileactions = filectxactions.FilectxActions(self._repo,
                                                          self,
                                                          rev=self._rev)
        self._fileactions.linkActivated.connect(self.linkActivated)
        self._fileactions.filterRequested.connect(self.revsetFilterRequested)
        self._fileactions.runCustomCommandRequested.connect(
            self.runCustomCommandRequested)
        self.addActions(self._fileactions.actions())

    def showEvent(self, event):
        QWidget.showEvent(self, event)
        if self._selectedrev != self._rev:
            # If the selected revision is not the same as the current revision
            # we must "reload" the manifest contents with the selected revision
            self.setRev(self._selectedrev)

    #@pyqtSlot(QModelIndex)
    def onDoubleClick(self, index):
        itemissubrepo = (self._treemodel.fileStatus(index) == 'S')
        if itemissubrepo:
            self._fileactions.opensubrepo()
        elif not self._treemodel.isDir(index):
            if self._treemodel.fileStatus(index) in 'C?':
                self._fileactions.editfile()
            else:
                self._fileactions.vdiff()

    def menuRequest(self, point):
        selmodel = self._treeview.selectionModel()
        if not selmodel.selectedRows():
            return
        point = self._treeview.viewport().mapToGlobal(point)

        contextmenu = self._fileactions.menu()
        if contextmenu:
            contextmenu.exec_(point)

    #@pyqtSlot(QModelIndex)
    def _updateItemFileActions(self, index):
        itemissubrepo = (self._treemodel.fileStatus(index) == 'S')
        itemisdir = self._treemodel.isDir(index)
        self._fileactions.setPaths([self.path],
                                   itemissubrepo=itemissubrepo,
                                   itemisdir=itemisdir)

    @property
    def toolbar(self):
        """Return toolbar for manifest widget"""
        return self._toolbar

    @pyqtSlot(unicode, bool, bool, bool)
    def find(self, pattern, icase=False, wrap=False, forward=True):
        return self._fileview.find(pattern, icase, wrap, forward)

    @pyqtSlot(unicode, bool)
    def highlightText(self, pattern, icase=False):
        self._fileview.highlightText(pattern, icase)

    def _setupmodel(self):
        self._treemodel = ManifestModel(
            self._repo,
            self._rev,
            statusfilter=self._statusfilter.status(),
            parent=self)
        self._treemodel.setNameFilter(self.le.text())

        oldmodel = self._treeview.model()
        oldselmodel = self._treeview.selectionModel()
        self._treeview.setModel(self._treemodel)
        if oldmodel:
            oldmodel.deleteLater()
        if oldselmodel:
            oldselmodel.deleteLater()

        selmodel = self._treeview.selectionModel()
        selmodel.currentChanged.connect(self._updatecontent)
        selmodel.currentChanged.connect(self._updateItemFileActions)
        selmodel.currentChanged.connect(self._emitPathChanged)

        self._statusfilter.statusChanged.connect(
            self._treemodel.setStatusFilter)
        self._statusfilter.statusChanged.connect(self._autoexpandtree)
        self._autoexpandtree()

    def _setupfilterupdater(self):
        self._filterupdatetimer = QTimer(self, interval=200, singleShot=True)
        self.le.returnPressed.connect(self._treeview.expandAll)
        self.le.textChanged.connect(self._filterupdatetimer.start)
        self._filterupdatetimer.timeout.connect(self._applyFilter)

    @pyqtSlot()
    def _applyFilter(self):
        filtertext = self.le.text()
        self._treemodel.setNameFilter(filtertext)
        self._treeview.enablefilterpalette(filtertext)

    @pyqtSlot()
    def _autoexpandtree(self):
        """expand file tree if the number of the items isn't large"""
        if 'C' not in self._statusfilter.status():
            self._treeview.expandAll()

    def reload(self):
        # TODO
        pass

    def setRepo(self, repo):
        self._repo = repo
        #self._fileview.setRepo(repo)
        self._fileview.repo = repo
        if len(repo) <= self._rev:
            self._rev = len(repo) - 1
        self._setupmodel()
        self._fileactions.setRepo(repo)

    @property
    def rev(self):
        """Return current revision"""
        return self._rev

    def selectRev(self, rev):
        """
        Select the revision that must be set when the dialog is shown again
        """
        self._selectedrev = rev

    @pyqtSlot(int)
    @pyqtSlot(object)
    def setRev(self, rev):
        """Change revision to show"""
        self._selectedrev = rev
        self.revpanel.set_revision(rev)
        self.revpanel.update(repo=self._repo)
        if rev == self._rev:
            return
        self._rev = rev
        path = self.path
        self.revChanged.emit(rev)
        self._setupmodel()
        ctx = self._repo[rev]
        if path and hglib.fromunicode(path) in ctx:
            # recover file selection after reloading the model
            self.setPath(path)
            self._fileview.setContext(ctx)
            self._fileview.displayFile(self.path, self.status)
        self._fileactions.setRev(rev)

    @pyqtSlot(unicode, object)
    @pyqtSlot(unicode, object, int)
    def setSource(self, path, rev, line=None):
        """Change path and revision to show at once"""
        if self._rev != rev:
            self._rev = rev
            self._setupmodel()
            self._fileactions.setRev(rev)
            self.revChanged.emit(rev)
        if path != self.path:
            self.setPath(path)
            ctx = self._repo[rev]
            if hglib.fromunicode(self.path) in ctx:
                self._fileview.displayFile(path, self.status)
            else:
                self._fileview.clearDisplay()
                return
        if line:
            self._fileview.showLine(line - 1)

    @property
    def path(self):
        """Return currently selected path [unicode]"""
        return self._treemodel.filePath(self._treeview.currentIndex())

    @property
    def status(self):
        """Return currently selected path"""
        return self._treemodel.fileStatus(self._treeview.currentIndex())

    @pyqtSlot(unicode)
    def setPath(self, path):
        """Change path to show"""
        self._treeview.setCurrentIndex(self._treemodel.indexFromPath(path))

    def displayFile(self):
        ctx, path = self._treemodel.fileSubrepoCtxFromPath(self.path)
        if ctx is None:
            ctx = self._repo[self._rev]
        else:
            ctx._repo.tabwidth = self._repo.tabwidth
            ctx._repo.maxdiff = self._repo.maxdiff
        self._fileview.setContext(ctx)
        self._fileview.displayFile(path, self.status)

    @pyqtSlot()
    def _updatecontent(self):
        self.displayFile()

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

    @pyqtSlot()
    def _emitPathChanged(self):
        self.pathChanged.emit(self.path)
コード例 #21
0
 def test_isdir(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertTrue(m.isDir(m.indexFromPath('')))
     self.assertTrue(m.isDir(m.indexFromPath('baz')))
     self.assertFalse(m.isDir(m.indexFromPath('foo')))
コード例 #22
0
class ManifestWidget(QWidget, qtlib.TaskWidget):
    """Display file tree and contents at the specified revision"""

    revChanged = pyqtSignal(object)
    """Emitted (rev) when the current revision changed"""

    pathChanged = pyqtSignal(unicode)
    """Emitted (path) when the current file path changed"""

    showMessage = pyqtSignal(unicode)
    """Emitted when to show revision summary as a hint"""

    grepRequested = pyqtSignal(unicode, dict)
    """Emitted (pattern, opts) when user request to search changelog"""

    linkActivated = pyqtSignal(QString)
    """Emitted (path) when user clicks on link"""

    revsetFilterRequested = pyqtSignal(QString)
    """Ask the repowidget to change its revset filter"""

    runCustomCommandRequested = pyqtSignal(str, list)
    """Emitted when selects a custom tool on the context menu"""

    def canswitch(self):
        return False

    def __init__(self, repoagent, rev=None, parent=None):
        super(ManifestWidget, self).__init__(parent)
        self._repoagent = repoagent
        # TODO: replace by repoagent if setRepo(bundlerepo) can be removed
        self._repo = repoagent.rawRepo()
        self._rev = rev
        self._selectedrev = rev

        self._initwidget()
        self._initactions()
        self._setupmodel()
        self._setupfilterupdater()

        self._treeview.setCurrentIndex(self._treemodel.index(0, 0))
        self.setRev(self._rev)

    def _initwidget(self):
        self.setLayout(QVBoxLayout())
        self._splitter = QSplitter()
        self.layout().addWidget(self._splitter)
        self.layout().setContentsMargins(2, 2, 2, 2)

        navlayout = QVBoxLayout(spacing=0)
        navlayout.setContentsMargins(0, 0, 0, 0)
        self._toolbar = QToolBar()
        self._toolbar.setIconSize(QSize(16,16))
        self._toolbar.setStyleSheet(qtlib.tbstylesheet)
        self._treeview = QManifestTreeView(self, headerHidden=True, dragEnabled=True)
        self._treeview.setContextMenuPolicy(Qt.CustomContextMenu)
        self._treeview.customContextMenuRequested.connect(self.menuRequest)
        self._treeview.doubleClicked.connect(self.onDoubleClick)
        navlayout.addWidget(self._toolbar)
        navlayout.addWidget(self._treeview)
        navlayoutw = QWidget()
        navlayoutw.setLayout(navlayout)

        self._splitter.addWidget(navlayoutw)
        self._splitter.setStretchFactor(0, 1)

        vbox = QVBoxLayout(spacing=0)
        vbox.setMargin(0)
        self.revpanel = revpanel.RevPanelWidget(self._repo)
        self.revpanel.linkActivated.connect(self.linkActivated)
        vbox.addWidget(self.revpanel, 0)
        self._fileview = fileview.HgFileView(self._repoagent, self)
        vbox.addWidget(self._fileview, 0)
        w = QWidget()
        w.setLayout(vbox)
        self._splitter.addWidget(w)

        self._splitter.setStretchFactor(1, 3)
        self._fileview.revisionSelected.connect(self.setRev)
        self._fileview.linkActivated.connect(self.linkActivated)
        for name in ('showMessage', 'grepRequested'):
            getattr(self._fileview, name).connect(getattr(self, name))

    def loadSettings(self, qs, prefix):
        prefix += '/manifest'
        self._fileview.loadSettings(qs, prefix+'/fileview')
        self._splitter.restoreState(qs.value(prefix+'/splitter').toByteArray())
        expanded = qs.value(prefix+'/revpanel.expanded', False).toBool()
        self.revpanel.set_expanded(expanded)

    def saveSettings(self, qs, prefix):
        prefix += '/manifest'
        self._fileview.saveSettings(qs, prefix+'/fileview')
        qs.setValue(prefix+'/splitter', self._splitter.saveState())
        qs.setValue(prefix+'/revpanel.expanded', self.revpanel.is_expanded())

    def _initactions(self):
        self.le = QManifestLineEdit() #QLineEdit()
        if hasattr(self.le, 'setPlaceholderText'): # Qt >= 4.7
            self.le.setPlaceholderText(_('### filter text ###'))
        else:
            lbl = QLabel(_('Filter:'))
            self._toolbar.addWidget(lbl)
        self.le.keypressed.connect(self._treeview.setFocus)
        self._treeview.topreached.connect(self.le.setFocus)
        self._toolbar.addWidget(self.le)

        self._statusfilter = status.StatusFilterButton(
          statustext='MASC', text=_('Status'))
        self._toolbar.addWidget(self._statusfilter)

        self._fileactions = filectxactions.FilectxActions(self._repo, self,
                                                          rev=self._rev)
        self._fileactions.linkActivated.connect(self.linkActivated)
        self._fileactions.filterRequested.connect(self.revsetFilterRequested)
        self._fileactions.runCustomCommandRequested.connect(
            self.runCustomCommandRequested)
        self.addActions(self._fileactions.actions())

    def showEvent(self, event):
        QWidget.showEvent(self, event)
        if self._selectedrev != self._rev:
            # If the selected revision is not the same as the current revision
            # we must "reload" the manifest contents with the selected revision
            self.setRev(self._selectedrev)

    #@pyqtSlot(QModelIndex)
    def onDoubleClick(self, index):
        itemissubrepo = (self._treemodel.fileStatus(index) == 'S')
        if itemissubrepo:
            self._fileactions.opensubrepo()
        elif not self._treemodel.isDir(index):
            if self._treemodel.fileStatus(index) in 'C?':
                self._fileactions.editfile()
            else:
                self._fileactions.vdiff()

    def menuRequest(self, point):
        selmodel = self._treeview.selectionModel()
        if not selmodel.selectedRows():
            return
        point = self._treeview.viewport().mapToGlobal(point)

        contextmenu = self._fileactions.menu()
        if contextmenu:
            contextmenu.exec_(point)

    #@pyqtSlot(QModelIndex)
    def _updateItemFileActions(self, index):
        itemissubrepo = (self._treemodel.fileStatus(index) == 'S')
        itemisdir = self._treemodel.isDir(index)
        self._fileactions.setPaths([self.path], itemissubrepo=itemissubrepo,
                                   itemisdir=itemisdir)

    @property
    def toolbar(self):
        """Return toolbar for manifest widget"""
        return self._toolbar

    @pyqtSlot(unicode, bool, bool, bool)
    def find(self, pattern, icase=False, wrap=False, forward=True):
        return self._fileview.find(pattern, icase, wrap, forward)

    @pyqtSlot(unicode, bool)
    def highlightText(self, pattern, icase=False):
        self._fileview.highlightText(pattern, icase)

    def _setupmodel(self):
        self._treemodel = ManifestModel(self._repo, self._rev,
                                        statusfilter=self._statusfilter.status(),
                                        parent=self)
        self._treemodel.setNameFilter(self.le.text())

        oldmodel = self._treeview.model()
        oldselmodel = self._treeview.selectionModel()
        self._treeview.setModel(self._treemodel)
        if oldmodel:
            oldmodel.deleteLater()
        if oldselmodel:
            oldselmodel.deleteLater()

        selmodel = self._treeview.selectionModel()
        selmodel.currentChanged.connect(self._updatecontent)
        selmodel.currentChanged.connect(self._updateItemFileActions)
        selmodel.currentChanged.connect(self._emitPathChanged)

        self._statusfilter.statusChanged.connect(self._treemodel.setStatusFilter)
        self._statusfilter.statusChanged.connect(self._autoexpandtree)
        self._autoexpandtree()

    def _setupfilterupdater(self):
        self._filterupdatetimer = QTimer(self, interval=200, singleShot=True)
        self.le.returnPressed.connect(self._treeview.expandAll)
        self.le.textChanged.connect(self._filterupdatetimer.start)
        self._filterupdatetimer.timeout.connect(self._applyFilter)

    @pyqtSlot()
    def _applyFilter(self):
        filtertext = self.le.text()
        self._treemodel.setNameFilter(filtertext)
        self._treeview.enablefilterpalette(filtertext)

    @pyqtSlot()
    def _autoexpandtree(self):
        """expand file tree if the number of the items isn't large"""
        if 'C' not in self._statusfilter.status():
            self._treeview.expandAll()

    def reload(self):
        # TODO
        pass

    def setRepo(self, repo):
        self._repo = repo
        #self._fileview.setRepo(repo)
        self._fileview.repo = repo
        if len(repo) <= self._rev:
            self._rev = len(repo)-1
        self._setupmodel()
        self._fileactions.setRepo(repo)

    @property
    def rev(self):
        """Return current revision"""
        return self._rev

    def selectRev(self, rev):
        """
        Select the revision that must be set when the dialog is shown again
        """
        self._selectedrev = rev

    @pyqtSlot(int)
    @pyqtSlot(object)
    def setRev(self, rev):
        """Change revision to show"""
        self._selectedrev = rev
        self.revpanel.set_revision(rev)
        self.revpanel.update(repo = self._repo)
        if rev == self._rev:
            return
        self._rev = rev
        path = self.path
        self.revChanged.emit(rev)
        self._setupmodel()
        ctx = self._repo[rev]
        if path and hglib.fromunicode(path) in ctx:
            # recover file selection after reloading the model
            self.setPath(path)
            self._fileview.setContext(ctx)
            self._fileview.displayFile(self.path, self.status)
        self._fileactions.setRev(rev)

    @pyqtSlot(unicode, object)
    @pyqtSlot(unicode, object, int)
    def setSource(self, path, rev, line=None):
        """Change path and revision to show at once"""
        if self._rev != rev:
            self._rev = rev
            self._setupmodel()
            self._fileactions.setRev(rev)
            self.revChanged.emit(rev)
        if path != self.path:
            self.setPath(path)
            ctx = self._repo[rev]
            if hglib.fromunicode(self.path) in ctx:
                self._fileview.displayFile(path, self.status)
            else:
                self._fileview.clearDisplay()
                return
        if line:
            self._fileview.showLine(line - 1)

    @property
    def path(self):
        """Return currently selected path [unicode]"""
        return self._treemodel.filePath(self._treeview.currentIndex())

    @property
    def status(self):
        """Return currently selected path"""
        return self._treemodel.fileStatus(self._treeview.currentIndex())

    @pyqtSlot(unicode)
    def setPath(self, path):
        """Change path to show"""
        self._treeview.setCurrentIndex(self._treemodel.indexFromPath(path))

    def displayFile(self):
        ctx, path = self._treemodel.fileSubrepoCtxFromPath(self.path)
        if ctx is None:
            ctx = self._repo[self._rev]
        else:
            ctx._repo.tabwidth = self._repo.tabwidth
            ctx._repo.maxdiff = self._repo.maxdiff
        self._fileview.setContext(ctx)
        self._fileview.displayFile(path, self.status)

    @pyqtSlot()
    def _updatecontent(self):
        self.displayFile()

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

    @pyqtSlot()
    def _emitPathChanged(self):
        self.pathChanged.emit(self.path)
コード例 #23
0
 def test_rowcount(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertEqual(3, m.rowCount())
コード例 #24
0
class ManifestWidget(QWidget, qtlib.TaskWidget):
    """Display file tree and contents at the specified revision"""

    revChanged = pyqtSignal(object)
    """Emitted (rev) when the current revision changed"""

    pathChanged = pyqtSignal(unicode)
    """Emitted (path) when the current file path changed"""

    showMessage = pyqtSignal(unicode)
    """Emitted when to show revision summary as a hint"""

    grepRequested = pyqtSignal(unicode, dict)
    """Emitted (pattern, opts) when user request to search changelog"""

    linkActivated = pyqtSignal(QString)
    """Emitted (path) when user clicks on link"""

    filecontextmenu = None
    subrepocontextmenu = None

    def canswitch(self):
        return False

    def __init__(self, repo, rev=None, parent=None):
        super(ManifestWidget, self).__init__(parent)
        self._repo = repo
        self._rev = rev
        self._selectedrev = rev
        self._diff_dialogs = {}
        self._nav_dialogs = {}

        self._initwidget()
        self._initactions()
        self._setupmodel()
        self._treeview.setCurrentIndex(self._treemodel.index(0, 0))

        self.setRev(self._rev)

    def _initwidget(self):
        self.setLayout(QVBoxLayout())
        self._splitter = QSplitter()
        self.layout().addWidget(self._splitter)
        self.layout().setContentsMargins(2, 2, 2, 2)

        navlayout = QVBoxLayout(spacing=0)
        navlayout.setContentsMargins(0, 0, 0, 0)
        self._toolbar = QToolBar()
        self._toolbar.setIconSize(QSize(16, 16))
        self._toolbar.setStyleSheet(qtlib.tbstylesheet)
        self._treeview = QTreeView(self, headerHidden=True, dragEnabled=True)
        self._treeview.setContextMenuPolicy(Qt.CustomContextMenu)
        self._treeview.customContextMenuRequested.connect(self.menuRequest)
        self._treeview.doubleClicked.connect(self.onDoubleClick)
        navlayout.addWidget(self._toolbar)
        navlayout.addWidget(self._treeview)
        navlayoutw = QWidget()
        navlayoutw.setLayout(navlayout)

        self._splitter.addWidget(navlayoutw)
        self._splitter.setStretchFactor(0, 1)

        vbox = QVBoxLayout(spacing=0)
        vbox.setMargin(0)
        self.revpanel = revpanel.RevPanelWidget(self._repo)
        self.revpanel.linkActivated.connect(self.linkActivated)
        vbox.addWidget(self.revpanel, 0)
        self._fileview = fileview.HgFileView(self._repo, self)
        vbox.addWidget(self._fileview, 0)
        w = QWidget()
        w.setLayout(vbox)
        self._splitter.addWidget(w)

        self._splitter.setStretchFactor(1, 3)
        self._fileview.revisionSelected.connect(self.setRev)
        self._fileview.linkActivated.connect(self.linkActivated)
        for name in ("showMessage", "grepRequested"):
            getattr(self._fileview, name).connect(getattr(self, name))

    def loadSettings(self, qs, prefix):
        prefix += "/manifest"
        self._fileview.loadSettings(qs, prefix + "/fileview")
        self._splitter.restoreState(qs.value(prefix + "/splitter").toByteArray())
        expanded = qs.value(prefix + "/revpanel.expanded", False).toBool()
        self.revpanel.set_expanded(expanded)

    def saveSettings(self, qs, prefix):
        prefix += "/manifest"
        self._fileview.saveSettings(qs, prefix + "/fileview")
        qs.setValue(prefix + "/splitter", self._splitter.saveState())
        qs.setValue(prefix + "/revpanel.expanded", self.revpanel.is_expanded())

    def _initactions(self):
        self._statusfilter = status.StatusFilterButton(statustext="MASC", text=_("Status"))
        self._toolbar.addWidget(self._statusfilter)

        self._actions = {}
        for name, desc, icon, key, tip, cb in [
            (
                "navigate",
                _("File history"),
                "hg-log",
                "Shift+Return",
                _("Show the history of the selected file"),
                self.navigate,
            ),
            (
                "diffnavigate",
                _("Compare file revisions"),
                "compare-files",
                None,
                _("Compare revisions of the selected file"),
                self.diffNavigate,
            ),
            (
                "diff",
                _("Visual Diff"),
                "visualdiff",
                "Ctrl+D",
                _("View file changes in external diff tool"),
                self.vdiff,
            ),
            (
                "ldiff",
                _("Visual Diff to Local"),
                "ldiff",
                "Shift+Ctrl+D",
                _("View changes to current in external diff tool"),
                self.vdifflocal,
            ),
            (
                "edit",
                _("View at Revision"),
                "view-at-revision",
                "Alt+Ctrl+E",
                _("View file as it appeared at this revision"),
                self.editfile,
            ),
            (
                "ledit",
                _("Edit Local"),
                "edit-file",
                "Shift+Ctrl+E",
                _("Edit current file in working copy"),
                self.editlocal,
            ),
            (
                "revert",
                _("Revert to Revision"),
                "hg-revert",
                "Alt+Ctrl+T",
                _("Revert file(s) to contents at this revision"),
                self.revertfile,
            ),
            (
                "opensubrepo",
                _("Open subrepository"),
                "thg-repository-open",
                "Alt+Ctrl+O",
                _("Open the selected subrepository"),
                self.opensubrepo,
            ),
            (
                "explore",
                _("Explore subrepository"),
                "system-file-manager",
                "Alt+Ctrl+E",
                _("Open the selected subrepository in a file browser"),
                self.explore,
            ),
            (
                "terminal",
                _("Open terminal in subrepository"),
                "utilities-terminal",
                "Alt+Ctrl+T",
                _("Open a shell terminal in the selected subrepository root"),
                self.terminal,
            ),
        ]:
            act = QAction(desc, self)
            if icon:
                act.setIcon(qtlib.getmenuicon(icon))
            if key:
                act.setShortcut(key)
            if tip:
                act.setStatusTip(tip)
            if cb:
                act.triggered.connect(cb)
            self._actions[name] = act
            self.addAction(act)

    def navigate(self, filename=None):
        self._navigate(filename, FileLogDialog, self._nav_dialogs)

    def diffNavigate(self, filename=None):
        self._navigate(filename, FileDiffDialog, self._diff_dialogs)

    def vdiff(self):
        if self.path is None:
            return
        pats = [hglib.fromunicode(self.path)]
        opts = {"change": self.rev}
        dlg = visdiff.visualdiff(self._repo.ui, self._repo, pats, opts)
        if dlg:
            dlg.exec_()

    def vdifflocal(self):
        if self.path is None:
            return
        pats = [hglib.fromunicode(self.path)]
        assert type(self.rev) is int
        opts = {"rev": ["rev(%d)" % self.rev]}
        dlg = visdiff.visualdiff(self._repo.ui, self._repo, pats, opts)
        if dlg:
            dlg.exec_()

    def editfile(self):
        if self.path is None:
            return
        if self.rev is None:
            qtlib.editfiles(self._repo, [hglib.fromunicode(self.path)], parent=self)
        else:
            base, _ = visdiff.snapshot(self._repo, [hglib.fromunicode(self.path)], self._repo[self.rev])
            files = [os.path.join(base, hglib.fromunicode(self.path))]
            qtlib.editfiles(self._repo, files, parent=self)

    def editlocal(self):
        if self.path is None:
            return
        qtlib.editfiles(self._repo, [hglib.fromunicode(self.path)], parent=self)

    def revertfile(self):
        if self.path is None:
            return
        rev = self.rev
        if rev is None:
            rev = self._repo["."].rev()
        dlg = revert.RevertDialog(self._repo, [hglib.fromunicode(self.path)], rev, self)
        dlg.exec_()

    def _navigate(self, filename, dlgclass, dlgdict):
        if not filename:
            filename = hglib.fromunicode(self.path)
        if filename not in dlgdict:
            repoviewer = self.window()
            if not isinstance(repoviewer, workbench.Workbench):
                repoviewer = None
            dlg = dlgclass(self._repo, filename, repoviewer)
            dlgdict[filename] = dlg
            ufname = hglib.tounicode(filename)
            dlg.setWindowTitle(_("Hg file log viewer - %s") % ufname)
        dlg = dlgdict[filename]
        dlg.goto(self.rev)
        dlg.show()
        dlg.raise_()
        dlg.activateWindow()

    def opensubrepo(self):
        path = self._repo.wjoin(hglib.fromunicode(self.path))
        if os.path.isdir(path):
            self.linkActivated.emit(u"subrepo:" + hglib.tounicode(path))
        else:
            QMessageBox.warning(
                self,
                _("Cannot open subrepository"),
                _("The selected subrepository does not exist on the working directory"),
            )

    def explore(self):
        root = self._repo.wjoin(hglib.fromunicode(self.path))
        if os.path.isdir(root):
            qtlib.openlocalurl(root)

    def terminal(self):
        root = self._repo.wjoin(hglib.fromunicode(self.path))
        if os.path.isdir(root):
            qtlib.openshell(root, hglib.fromunicode(self.path))

    def showEvent(self, event):
        QWidget.showEvent(self, event)
        if self._selectedrev != self._rev:
            # If the selected revision is not the same as the current revision
            # we must "reload" the manifest contents with the selected revision
            self.setRev(self._selectedrev)

    # @pyqtSlot(QModelIndex)
    def onDoubleClick(self, index):
        itemissubrepo = self._treemodel.fileStatus(index) == "S"
        if itemissubrepo:
            self.opensubrepo()
        else:
            self.vdiff()

    def menuRequest(self, point):
        selmodel = self._treeview.selectionModel()
        if not selmodel.selectedRows():
            return
        point = self._treeview.viewport().mapToGlobal(point)

        currentindex = self._treeview.currentIndex()
        itemissubrepo = self._treemodel.fileStatus(currentindex) == "S"

        # Subrepos and regular items have different context menus
        if itemissubrepo:
            contextmenu = self.subrepocontextmenu
            actionlist = ["opensubrepo", "explore", "terminal"]
        else:
            contextmenu = self.filecontextmenu
            actionlist = ["diff", "ldiff", "edit", "ledit", "revert", "navigate", "diffnavigate"]

        if not contextmenu:
            contextmenu = QMenu(self)
            for act in actionlist:
                if act:
                    contextmenu.addAction(self._actions[act])
                else:
                    contextmenu.addSeparator()

            if itemissubrepo:
                self.subrepocontextmenu = contextmenu
            else:
                self.filecontextmenu = contextmenu

        if actionlist:
            contextmenu.exec_(point)

    @property
    def toolbar(self):
        """Return toolbar for manifest widget"""
        return self._toolbar

    @pyqtSlot(unicode, bool, bool, bool)
    def find(self, pattern, icase=False, wrap=False, forward=True):
        return self._fileview.find(pattern, icase, wrap, forward)

    @pyqtSlot(unicode, bool)
    def highlightText(self, pattern, icase=False):
        self._fileview.highlightText(pattern, icase)

    def _setupmodel(self):
        self._treemodel = ManifestModel(self._repo, self._rev, statusfilter=self._statusfilter.status(), parent=self)
        oldmodel = self._treeview.model()
        oldselmodel = self._treeview.selectionModel()
        self._treeview.setModel(self._treemodel)
        if oldmodel:
            oldmodel.deleteLater()
        if oldselmodel:
            oldselmodel.deleteLater()

        selmodel = self._treeview.selectionModel()
        selmodel.currentChanged.connect(self._updatecontent)
        selmodel.currentChanged.connect(self._emitPathChanged)

        self._statusfilter.statusChanged.connect(self._treemodel.setStatusFilter)
        self._statusfilter.statusChanged.connect(self._autoexpandtree)
        self._autoexpandtree()

    @pyqtSlot()
    def _autoexpandtree(self):
        """expand file tree if the number of the items isn't large"""
        if "C" not in self._statusfilter.status():
            self._treeview.expandAll()

    def reload(self):
        # TODO
        pass

    def setRepo(self, repo):
        self._repo = repo
        # self._fileview.setRepo(repo)
        self._fileview.repo = repo
        if len(repo) <= self._rev:
            self._rev = len(repo) - 1
        self._setupmodel()

    @property
    def rev(self):
        """Return current revision"""
        return self._rev

    def selectRev(self, rev):
        """
        Select the revision that must be set when the dialog is shown again
        """
        self._selectedrev = rev

    @pyqtSlot(int)
    @pyqtSlot(object)
    def setRev(self, rev):
        """Change revision to show"""
        self._selectedrev = rev
        self.revpanel.set_revision(rev)
        self.revpanel.update(repo=self._repo)
        if rev == self._rev:
            return
        self._rev = rev
        path = self.path
        self.revChanged.emit(rev)
        self._setupmodel()
        ctx = self._repo[rev]
        if path and hglib.fromunicode(path) in ctx:
            # recover file selection after reloading the model
            self.setPath(path)
            self._fileview.setContext(ctx)
            self._fileview.displayFile(self.path, self.status)
        # update sensitivity of actions
        real = type(rev) is int
        self._actions["ldiff"].setEnabled(real)
        for act in ["diff", "edit"]:
            self._actions[act].setEnabled(real or rev is None)
        self._actions["revert"].setEnabled(real)

    @pyqtSlot(unicode, object)
    @pyqtSlot(unicode, object, int)
    def setSource(self, path, rev, line=None):
        """Change path and revision to show at once"""
        if self._rev != rev:
            self._rev = rev
            self._setupmodel()
            self.revChanged.emit(rev)
        if path != self.path:
            self.setPath(path)
            ctx = self._repo[rev]
            if hglib.fromunicode(self.path) in ctx:
                self._fileview.displayFile(path, self.status)
                if line:
                    self._fileview.showLine(int(line) - 1)
            else:
                self._fileview.clearDisplay()

    @property
    def path(self):
        """Return currently selected path [unicode]"""
        return self._treemodel.filePath(self._treeview.currentIndex())

    @property
    def status(self):
        """Return currently selected path"""
        return self._treemodel.fileStatus(self._treeview.currentIndex())

    @pyqtSlot(unicode)
    def setPath(self, path):
        """Change path to show"""
        self._treeview.setCurrentIndex(self._treemodel.indexFromPath(path))

    def displayFile(self):
        ctx, path = self._treemodel.fileSubrepoCtxFromPath(self.path)
        if ctx is None:
            ctx = self._repo[self._rev]
        else:
            ctx._repo.tabwidth = self._repo.tabwidth
            ctx._repo.maxdiff = self._repo.maxdiff
        self._fileview.setContext(ctx)
        self._fileview.displayFile(path, self.status)

    @pyqtSlot()
    def _updatecontent(self):
        self.displayFile()

    @pyqtSlot()
    def _emitPathChanged(self):
        self.pathChanged.emit(self.path)
コード例 #25
0
 def test_status_role_invalid(self):
     m = ManifestModel(self.repo, rev=0)
     self.assertEqual(None, m.data(QModelIndex(),
                                   role=ManifestModel.StatusRole))