[PATCH 1 of 9] Add extra tests for registry

11 views
Skip to first unread message

mvdw...@gmail.com

unread,
Jul 24, 2021, 4:01:16 AM7/24/21
to thg...@googlegroups.com
# HG changeset patch
# User KPOP
# Date 1619459899 -7200
# Mon Apr 26 19:58:19 2021 +0200
# Node ID 26d6c2d13e47479cec083154ca21572e876c46af
# Parent 5849ec046555ce24a28268c086ab171ff41ad268
Add extra tests for registry

diff -r 5849ec046555 -r 26d6c2d13e47 tests/qt_repotreemodel_test.py
--- a/tests/qt_repotreemodel_test.py Tue Jul 13 19:50:10 2021 +0900
+++ b/tests/qt_repotreemodel_test.py Mon Apr 26 19:58:19 2021 +0200
@@ -3,8 +3,11 @@
from xml.dom import minidom

from tortoisehg.hgqt.qtcore import (
+ pyqtSignal,
QByteArray,
QBuffer,
+ QModelIndex,
+ QObject,
QIODevice,
)

@@ -124,3 +127,77 @@
repr(subroot.child(0))
assert type(subroot.child(1)) is repotreeitem.SubrepoItem, \
repr(subroot.child(1))
+
+filter_data = br'''<?xml version="1.0" encoding="UTF-8"?>
+<reporegistry>
+ <treeitem>
+ <allgroup name="default">
+ <repo root="/standalone" shortname="standalone" basenode="6c30f00cc82daff63b1260eec198256a9c8e5a56"/>
+ <repo root="/subroot" shortname="subroot" basenode="b986218ba1c9b0d6a259fac9b050b1724ed8e545">
+ <subrepo root="/subroot/svnsub" repotype="svn" shortname="svn"/>
+ <subrepo root="/subroot/sub" shortname="sub" basenode="2f425e331c8cdffa5103f3b181358092245bdc10"/>
+ </repo>
+ </allgroup>
+ <group name="fooGroup">
+ <group name="barGroup">
+ <repo root="/subsubroot" shortname="subsubroot2" basenode="b986218ba1c9b0d6a259fac9b050b1724ed8e545">
+ <subrepo root="/subsubroot/subroot2" shortname="subroot2" basenode="b986218ba1c9b0d6a259fac9b050b1724ed8e545">
+ <subrepo root="/subsubroot/subroot2/svnsub2" repotype="svn"/>
+ <subrepo root="/subsubroot/subroot2/sub2" shortname="sub2" basenode="2f425e331c8cdffa5103f3b181358092245bdc10"/>
+ </subrepo>
+ </repo>
+ </group>
+ </group>
+ </treeitem>
+</reporegistry>
+'''
+
+class DummyRepoManager(QObject):
+ configChanged = pyqtSignal(str)
+ repositoryChanged = pyqtSignal(str)
+ repositoryOpened = pyqtSignal(str)
+
+@with_qbuffer(filter_data)
+def test_repotreemodel(f):
+ """Test data used for the filtering tests"""
+ repomanager = DummyRepoManager()
+ model = repotreemodel.RepoTreeModel(f, repomanager)
+
+ rootIndex = QModelIndex()
+ assert model.rowCount(rootIndex) is 2
+
+ assert model.data(model.index(0, 1, rootIndex)) is ''
+ allGroupIndex = model.index(0, 0, rootIndex)
+ assert model.data(allGroupIndex) == 'default'
+ assert model.rowCount(allGroupIndex) is 2
+ assert model.data(model.index(0, 0, allGroupIndex)) == 'standalone'
+ assert model.data(model.index(0, 1, allGroupIndex)) == '/standalone'
+ assert model.data(model.index(1, 1, allGroupIndex)) == '/subroot'
+ subrootIndex = model.index(1, 0, allGroupIndex)
+ assert model.data(subrootIndex) == 'subroot'
+ assert model.rowCount(subrootIndex) is 2
+ assert model.data(model.index(0, 0, subrootIndex)) == 'svnsub'
+ assert model.data(model.index(0, 1, subrootIndex)) == '/subroot/svnsub'
+ assert model.data(model.index(1, 0, subrootIndex)) == 'sub'
+ assert model.data(model.index(1, 1, subrootIndex)) == '/subroot/sub'
+
+ assert model.data(model.index(1, 1, rootIndex)) is ''
+ fooGroupIndex = model.index(1, 0, rootIndex)
+ assert model.data(fooGroupIndex) == 'fooGroup'
+ assert model.rowCount(fooGroupIndex) is 1
+ assert model.data(model.index(0, 1, fooGroupIndex)) == ''
+ barGroupIndex = model.index(0, 0, fooGroupIndex)
+ assert model.data(barGroupIndex) == 'barGroup'
+ assert model.rowCount(barGroupIndex) is 1
+ assert model.data(model.index(0, 1, barGroupIndex)) == '/subsubroot'
+ subsubroot2Index = model.index(0, 0, barGroupIndex)
+ assert model.data(subsubroot2Index) == 'subsubroot2'
+ assert model.rowCount(subsubroot2Index) is 1
+ assert model.data(model.index(0, 1, subsubroot2Index)) == '/subsubroot/subroot2'
+ subroot2Index = model.index(0, 0, subsubroot2Index)
+ assert model.data(subroot2Index) == 'subroot2'
+ assert model.rowCount(subroot2Index) is 2
+ assert model.data(model.index(0, 0, subroot2Index)) == 'svnsub2'
+ assert model.data(model.index(0, 1, subroot2Index)) == '/subsubroot/subroot2/svnsub2'
+ assert model.data(model.index(1, 0, subroot2Index)) == 'sub2'
+ assert model.data(model.index(1, 1, subroot2Index)) == '/subsubroot/subroot2/sub2'
diff -r 5849ec046555 -r 26d6c2d13e47 tortoisehg/hgqt/reporegistry.py
--- a/tortoisehg/hgqt/reporegistry.py Tue Jul 13 19:50:10 2021 +0900
+++ b/tortoisehg/hgqt/reporegistry.py Mon Apr 26 19:58:19 2021 +0200
@@ -10,6 +10,7 @@
import os

from .qtcore import (
+ QFile,
QFileSystemWatcher,
QModelIndex,
QPoint,
@@ -263,7 +264,7 @@
self._updateSettingActions()

sfile = settingsfilename()
- model = repotreemodel.RepoTreeModel(sfile, repomanager, self,
+ model = repotreemodel.RepoTreeModel(QFile(sfile), repomanager, self,
showShortPaths=self._isSettingEnabled('showShortPaths'))
tv.setModel(model)

@@ -383,7 +384,7 @@
oldmodel = self.tview.model()
assert oldmodel is not None
activeroot = oldmodel.repoRoot(oldmodel.activeRepoIndex())
- newmodel = repotreemodel.RepoTreeModel(settingsfilename(),
+ newmodel = repotreemodel.RepoTreeModel(QFile(settingsfilename()),
self._repomanager, self,
self._isSettingEnabled('showShortPaths'))
self.tview.setModel(newmodel)
@@ -433,7 +434,7 @@
self._scanAddedRepo(index)

def setActiveTabRepo(self, root):
- """"The selected tab has changed on the workbench"""
+ """The selected tab has changed on the workbench"""
m = self.tview.model()
assert m is not None
index = m.indexFromRepoRoot(root)
diff -r 5849ec046555 -r 26d6c2d13e47 tortoisehg/hgqt/repotreemodel.py
--- a/tortoisehg/hgqt/repotreemodel.py Tue Jul 13 19:50:10 2021 +0900
+++ b/tortoisehg/hgqt/repotreemodel.py Mon Apr 26 19:58:19 2021 +0200
@@ -90,7 +90,7 @@


class RepoTreeModel(QAbstractItemModel):
- def __init__(self, filename, repomanager, parent=None,
+ def __init__(self, f, repomanager, parent=None,
showShortPaths=False):
QAbstractItemModel.__init__(self, parent)

@@ -103,8 +103,7 @@
self._activeRepoItem = None

root = None
- if filename:
- f = QFile(filename)
+ if f:
if f.open(QIODevice.ReadOnly):
root = readXml(f, reporegistryXmlElementName)
f.close()

mvdw...@gmail.com

unread,
Jul 24, 2021, 4:01:16 AM7/24/21
to thg...@googlegroups.com
# HG changeset patch
# User KPOP
# Date 1627111490 -7200
# Sat Jul 24 09:24:50 2021 +0200
# Node ID cd0578829cffec43109c43712e936f9cf35d4c48
# Parent 26d6c2d13e47479cec083154ca21572e876c46af
Add case insensitive filtering based on repository name

diff -r 26d6c2d13e47 -r cd0578829cff tests/qt_repotreemodel_test.py
--- a/tests/qt_repotreemodel_test.py Mon Apr 26 19:58:19 2021 +0200
+++ b/tests/qt_repotreemodel_test.py Sat Jul 24 09:24:50 2021 +0200
@@ -201,3 +201,87 @@
assert model.data(model.index(0, 1, subroot2Index)) == '/subsubroot/subroot2/svnsub2'
assert model.data(model.index(1, 0, subroot2Index)) == 'sub2'
assert model.data(model.index(1, 1, subroot2Index)) == '/subsubroot/subroot2/sub2'
+@with_qbuffer(filter_data)
+def test_repotreemodel_filter_name(f):
+ """Test filtering based on the repo's name"""
+ repomanager = DummyRepoManager()
+ model = repotreemodel.RepoTreeModel(f, repomanager)
+ rootIndex = QModelIndex()
+ allGroupIndex = model.index(0, 0, rootIndex)
+ subrootIndex = model.index(1, 0, allGroupIndex)
+ svnsubIndex = model.index(0, 0, subrootIndex)
+ subIndex = model.index(1, 1, subrootIndex)
+ fooGroupIndex = model.index(1, 0, rootIndex)
+ barGroupIndex = model.index(0, 0, fooGroupIndex)
+ subsubroot2Index = model.index(0, 0, barGroupIndex)
+ subroot2Index = model.index(0, 0, subsubroot2Index)
+ svnsub2Index = model.index(0, 0, subroot2Index)
+ sub2Index = model.index(1, 0, subroot2Index)
+ def isFaded(modelIndex):
+ return modelIndex.internalPointer().faded()
+ model.setRevisionSet("")
+ assert not isFaded(allGroupIndex)
+ assert not isFaded(subrootIndex)
+ assert not isFaded(svnsubIndex)
+ assert not isFaded(subIndex)
+ assert not isFaded(fooGroupIndex)
+ assert not isFaded(barGroupIndex)
+ assert not isFaded(subsubroot2Index)
+ assert not isFaded(subroot2Index)
+ assert not isFaded(svnsub2Index)
+ assert not isFaded(sub2Index)
+ model.setRevisionSet("keyword('GROUP')")
+ assert isFaded(allGroupIndex)
+ assert isFaded(subrootIndex)
+ assert isFaded(svnsubIndex)
+ assert isFaded(subIndex)
+ assert not isFaded(fooGroupIndex)
+ assert not isFaded(barGroupIndex)
+ assert isFaded(subsubroot2Index)
+ assert isFaded(subroot2Index)
+ assert isFaded(svnsub2Index)
+ assert isFaded(sub2Index)
+ model.setRevisionSet("keyword('ROOT')")
+ assert isFaded(allGroupIndex)
+ assert not isFaded(subrootIndex)
+ assert isFaded(svnsubIndex)
+ assert isFaded(subIndex)
+ assert isFaded(fooGroupIndex)
+ assert isFaded(barGroupIndex)
+ assert not isFaded(subsubroot2Index)
+ assert not isFaded(subroot2Index)
+ assert isFaded(svnsub2Index)
+ assert isFaded(sub2Index)
+ model.setRevisionSet("keyword('2')")
+ assert isFaded(allGroupIndex)
+ assert isFaded(subrootIndex)
+ assert isFaded(svnsubIndex)
+ assert isFaded(subIndex)
+ assert isFaded(fooGroupIndex)
+ assert isFaded(barGroupIndex)
+ assert not isFaded(subsubroot2Index)
+ assert not isFaded(subroot2Index)
+ assert isFaded(svnsub2Index)
+ assert not isFaded(sub2Index)
+ model.setRevisionSet("keyword('SVN')")
+ assert isFaded(allGroupIndex)
+ assert isFaded(subrootIndex)
+ assert not isFaded(svnsubIndex)
+ assert isFaded(subIndex)
+ assert isFaded(fooGroupIndex)
+ assert isFaded(barGroupIndex)
+ assert isFaded(subsubroot2Index)
+ assert isFaded(subroot2Index)
+ assert not isFaded(svnsub2Index)
+ assert isFaded(sub2Index)
+ model.setRevisionSet("")
+ assert not isFaded(allGroupIndex)
+ assert not isFaded(subrootIndex)
+ assert not isFaded(svnsubIndex)
+ assert not isFaded(subIndex)
+ assert not isFaded(fooGroupIndex)
+ assert not isFaded(barGroupIndex)
+ assert not isFaded(subsubroot2Index)
+ assert not isFaded(subroot2Index)
+ assert not isFaded(svnsub2Index)
+ assert not isFaded(sub2Index)
diff -r 26d6c2d13e47 -r cd0578829cff tortoisehg/hgqt/repotreeitem.py
--- a/tortoisehg/hgqt/repotreeitem.py Mon Apr 26 19:58:19 2021 +0200
+++ b/tortoisehg/hgqt/repotreeitem.py Sat Jul 24 09:24:50 2021 +0200
@@ -77,6 +77,7 @@

# '/' for path separator, '#n' for index of duplicated names
_quotenamere = re.compile(r'[%/#]')
+_keywordrevisionsetre = re.compile(r"^keyword\('(?P<keyword>[^']*)'\)$")

def _quotename(s):
r"""Replace special characters to %xx (minimal set of urllib.quote)
@@ -179,6 +180,7 @@
self._parent = parent
self.childs = []
self._row = 0
+ self._matchesRevSet = True

def appendChild(self, child):
child._row = len(self.childs)
@@ -255,6 +257,33 @@
def getSupportedDragDropActions(self):
return Qt.MoveAction

+ def faded(self):
+ return not self._matchesRevSet
+
+ def setRevisionSet(self, revisionSet, changedCallback):
+ if revisionSet == '':
+ self._setMatchesRevSet(True, changedCallback)
+ else:
+ self._setMatchesRevSet(self._testRevisionSet(revisionSet), changedCallback)
+ for c in self.childs:
+ c.setRevisionSet(revisionSet, changedCallback)
+
+ def _setMatchesRevSet(self, matches, changedCallback):
+ if self._matchesRevSet == matches:
+ return
+ self._matchesRevSet = matches
+ changedCallback(self)
+
+ def _testRevisionSet(self, revisionSet):
+ print('Unsupported syntax: "%s" for %s' % (revisionSet, self.__class__.__name__))
+ return False
+
+ def _testRevisionSetKeyword(self, revisionSet, keywordString):
+ """Helper method for keyword based searching"""
+ keywordm = _keywordrevisionsetre.search(revisionSet)
+ if keywordm:
+ return re.search(keywordm.group('keyword'), keywordString, re.IGNORECASE) is not None
+ return None

class RepoItem(RepoTreeItem):
xmltagname = 'repo'
@@ -460,6 +489,11 @@
return True
return False

+ def _testRevisionSet(self, revisionSet):
+ keywordMatch = self._testRevisionSetKeyword(revisionSet, self.shortname())
+ if keywordMatch is not None:
+ return keywordMatch
+ return False

_subrepoType2IcoMap = {
'hg': 'hg',
@@ -551,6 +585,12 @@
def appendSubrepos(self, repo=None):
raise Exception('unsupported by non-hg subrepo')

+ def _testRevisionSet(self, revisionSet):
+ keywordMatch = self._testRevisionSetKeyword(revisionSet, self._repotype)
+ if keywordMatch is not None:
+ return keywordMatch
+ return False
+
def _newSubrepoItem(root, repotype):
if repotype == 'hg':
return SubrepoItem(root)
@@ -649,6 +689,12 @@
def getCommonPath(self):
return self._commonpath

+ def _testRevisionSet(self, revisionSet):
+ keywordMatch = self._testRevisionSetKeyword(revisionSet, self.name)
+ if keywordMatch is not None:
+ return keywordMatch
+ return False
+
class AllRepoGroupItem(RepoGroupItem):
xmltagname = 'allgroup'

diff -r 26d6c2d13e47 -r cd0578829cff tortoisehg/hgqt/repotreemodel.py
--- a/tortoisehg/hgqt/repotreemodel.py Mon Apr 26 19:58:19 2021 +0200
+++ b/tortoisehg/hgqt/repotreemodel.py Sat Jul 24 09:24:50 2021 +0200
@@ -434,3 +434,6 @@
self.layoutAboutToBeChanged.emit()
childs.sort(key=keyfunc)
self.layoutChanged.emit()
+ def setRevisionSet(self, revisionSet):
+ self.rootItem.setRevisionSet(revisionSet,
+ lambda item : self._emitItemDataChanged(item))

mvdw...@gmail.com

unread,
Jul 24, 2021, 4:01:17 AM7/24/21
to thg...@googlegroups.com
# HG changeset patch
# User KPOP
# Date 1627110828 -7200
# Sat Jul 24 09:13:48 2021 +0200
# Node ID 17848c398d3818a208bd517c2c665f18e1716a3d
# Parent cd0578829cffec43109c43712e936f9cf35d4c48
Do not store the repo agent and make it optional

diff -r cd0578829cff -r 17848c398d38 tortoisehg/hgqt/revset.py
--- a/tortoisehg/hgqt/revset.py Sat Jul 24 09:24:50 2021 +0200
+++ b/tortoisehg/hgqt/revset.py Sat Jul 24 09:13:48 2021 +0200
@@ -133,14 +133,15 @@

queryIssued = pyqtSignal(str)

- def __init__(self, repoagent, parent=None):
+ def __init__(self, optionalRepoAgent, parent=None):
QDialog.__init__(self, parent)

- self._repoagent = repoagent
+ self.setWindowTitle(_('Revision Set Query'))
# Since the revset dialot belongs to a repository, we display
# the repository name in the dialog title
- self.setWindowTitle(_('Revision Set Query')
- + ' - ' + repoagent.displayName())
+ if optionalRepoAgent is not None:
+ self.setWindowTitle(self.windowTitle()
+ + ' - ' + optionalRepoAgent.displayName())
self.setWindowFlags(Qt.Window)

layout = QVBoxLayout()
@@ -149,13 +150,13 @@

logical = _logical
ancestry = _ancestry
-
- repo = repoagent.rawRepo()
- if b'hgsubversion' in repo.extensions():
- logical = list(logical) + [('fromsvn()',
- _('all revisions converted from subversion')),]
- ancestry = list(ancestry) + [('svnrev(rev)',
- _('changeset which represents converted svn revision')),]
+ if optionalRepoAgent is not None:
+ repo = optionalRepoAgent.rawRepo()
+ if b'hgsubversion' in repo.extensions():
+ logical = list(logical) + [('fromsvn()',
+ _('all revisions converted from subversion')),]
+ ancestry = list(ancestry) + [('svnrev(rev)',
+ _('changeset which represents converted svn revision')),]

self.stbar = cmdui.ThgStatusBar(self)
self.stbar.setSizeGripEnabled(False)

mvdw...@gmail.com

unread,
Jul 24, 2021, 4:01:18 AM7/24/21
to thg...@googlegroups.com
# HG changeset patch
# User KPOP
# Date 1627110887 -7200
# Sat Jul 24 09:14:47 2021 +0200
# Node ID 14546c73a780bf78bb284352c87729c75b132ef0
# Parent 17848c398d3818a208bd517c2c665f18e1716a3d
Extract RepoFilterBarBase from RepoFilterBar and derive RepoRegistryFilterBar for use in the RepoRegistry

diff -r 17848c398d38 -r 14546c73a780 tortoisehg/hgqt/repofilter.py
--- a/tortoisehg/hgqt/repofilter.py Sat Jul 24 09:13:48 2021 +0200
+++ b/tortoisehg/hgqt/repofilter.py Sat Jul 24 09:14:47 2021 +0200
@@ -80,50 +80,6 @@
except error.ParseError:
pass

-def _querytype(repo, query):
- # type: (localrepo.localrepository, Text) -> Optional[Text]
- r"""
- >>> # TODO: maybe replace with real repo
- >>> origisrevsymbol = scmutil.isrevsymbol
- >>> scmutil.isrevsymbol = lambda repo, changeid: changeid in repo
- >>> repo = set(b'0 1 2 3 . stable'.split())
- >>> _querytype(repo, u'') is None
- True
- >>> _querytype(repo, u'quick fox')
- 'keyword'
- >>> _querytype(repo, u'0')
- 'revset'
- >>> _querytype(repo, u'stable')
- 'revset'
- >>> _querytype(repo, u'0::2') # symbol
- 'revset'
- >>> _querytype(repo, u'::"stable"') # string
- 'revset'
- >>> _querytype(repo, u'"') # unterminated string
- 'keyword'
- >>> _querytype(repo, u'tagged()')
- 'revset'
- >>> _querytype(repo, u'\u3000') # UnicodeEncodeError
- 'revset'
- >>> scmutil.isrevsymbol = origisrevsymbol
- """
- if not query:
- return
- if '(' in query:
- return 'revset'
- try:
- changeid = _firstword(query)
- except UnicodeEncodeError:
- return 'revset' # avoid further error on formatspec()
- if not changeid:
- return 'keyword'
- try:
- if scmutil.isrevsymbol(repo, changeid):
- return 'revset'
- except error.LookupError: # ambiguous changeid
- pass
- return 'keyword'
-

class SelectAllLineEdit(QLineEdit):
def __init__(self, parent=None):
@@ -143,46 +99,23 @@
super(SelectAllLineEdit, self).mouseReleaseEvent(ev)


-class RepoFilterBar(QToolBar):
- """Toolbar for RepoWidget to filter changesets"""
+class RepoFilterBarBase(QToolBar):
+ """Toolbar for filtering based on changesets"""

setRevisionSet = pyqtSignal(str)
- filterToggled = pyqtSignal(bool)

- branchChanged = pyqtSignal(str, bool)
- """Emitted (branch, allparents) when branch selection changed"""
-
- showHiddenChanged = pyqtSignal(bool)
- showGraftSourceChanged = pyqtSignal(bool)
-
- _allBranchesLabel = u'\u2605 ' + _('Show all') + u' \u2605'
-
- def __init__(self, repoagent, parent=None):
- # type: (thgrepo.RepoAgent, Optional[QWidget]) -> None
- super(RepoFilterBar, self).__init__(parent)
+ def __init__(self, optionalRepoAgent, parent=None):
+ # type: (Optional[thgrepo.RepoAgent], Optional[QWidget]) -> None
+ super(RepoFilterBarBase, self).__init__(parent)
self.layout().setContentsMargins(0, 0, 0, 0)
self.setIconSize(qtlib.smallIconSize())
- self._repoagent = repoagent
- self._permanent_queries = list(_permanent_queries)
- repo = repoagent.rawRepo()
- username = hglib.configuredusername(repo.ui)
- if username:
- self._permanent_queries.insert(0,
- hglib.formatrevspec(
- 'author(%s)',
- hglib.tounicode(os.path.expandvars(username))
- )
- )
- self.filterEnabled = True

- #Check if the font contains the glyph needed by the branch combo
- if not QFontMetrics(self.font()).inFont(u'\u2605'):
- self._allBranchesLabel = u'*** %s ***' % _('Show all')
-
- self.entrydlg = revset.RevisionSetQuery(repoagent, self)
+ self.entrydlg = revset.RevisionSetQuery(optionalRepoAgent, self)
self.entrydlg.queryIssued.connect(self.queryIssued)
self.entrydlg.hide()

+ self._permanent_queries = list()
+
self.revsetcombo = combo = QComboBox()
combo.setEditable(True)
combo.setInsertPolicy(QComboBox.NoInsert)
@@ -235,37 +168,8 @@
self.deleteBtn.clicked.connect(self.deleteFromHistory)
self.deleteBtn.setEnabled(False)
self.addWidget(self.deleteBtn)
- self.addSeparator()

- self.filtercb = f = QCheckBox(_('filter'))
- f.clicked.connect(self.filterToggled)
- f.setToolTip(_('Toggle filtering of non-matched changesets'))
- self.addWidget(f)
- self.addSeparator()
-
- self.showHiddenBtn = QToolButton()
- self.showHiddenBtn.setIcon(qtlib.geticon('view-hidden'))
- self.showHiddenBtn.setCheckable(True)
- self.showHiddenBtn.setToolTip(_('Show/Hide hidden changesets'))
- self.showHiddenBtn.clicked.connect(self.showHiddenChanged)
- self.addWidget(self.showHiddenBtn)
-
- self.showGraftSourceBtn = QToolButton()
- self.showGraftSourceBtn.setIcon(qtlib.geticon('hg-transplant'))
- self.showGraftSourceBtn.setCheckable(True)
- self.showGraftSourceBtn.setChecked(True)
- self.showGraftSourceBtn.setToolTip(_('Toggle graft relations visibility'))
- self.showGraftSourceBtn.clicked.connect(self.showGraftSourceChanged)
- self.addWidget(self.showGraftSourceBtn)
- self.addSeparator()
-
- self._initBranchFilter()
self.setFocusProxy(self.revsetcombo)
- self.refresh()
-
- @property
- def _repo(self):
- return self._repoagent.rawRepo()

def onClearButtonClicked(self):
if self.revsetcombo.currentText():
@@ -310,10 +214,13 @@
self.revsetcombo.setEditText(query)
self.runQuery()

+ def _querytype(self, query):
+ return 'keyword'
+
def _prepareQuery(self):
# type: () -> Text
query = pycompat.unicode(self.revsetcombo.currentText()).strip()
- if _querytype(self._repo, query) == 'keyword':
+ if self._querytype(query) == 'keyword':
return hglib.formatrevspec('keyword(%s)', query)
else:
return query
@@ -325,7 +232,7 @@
@pyqtSlot()
def _updateQueryType(self):
query = pycompat.unicode(self.revsetcombo.currentText()).strip()
- qtype = _querytype(self._repo, query)
+ qtype = self._querytype(query)
if not qtype:
self._revsettypelabel.hide()
self._updateQueryTypeGeometry()
@@ -386,18 +293,194 @@
self.revsetcombo.addItems(full)
self.revsetcombo.setCurrentIndex(self.revsetcombo.findText(query))

- def loadSettings(self, s):
- # type: (QSettings) -> None
- repoid = hglib.shortrepoid(self._repo)
+ def _loadSettings(self, s, repoid):
+ # type: (QSettings, Text) -> None
s.beginGroup('revset/' + repoid)
self.entrydlg.restoreGeometry(qtlib.readByteArray(s, 'geom'))
self.revsethist = list(qtlib.readStringList(s, 'queries'))
- self.filtercb.setChecked(qtlib.readBool(s, 'filter', True))
full = self.revsethist + self._permanent_queries
self.revsetcombo.clear()
self.revsetcombo.addItems(full)
self.revsetcombo.setCurrentIndex(-1)
self.setVisible(qtlib.readBool(s, 'showrepofilterbar'))
+ s.endGroup()
+
+ def _saveSettings(self, s, repoid):
+ # type: (QSettings, Text) -> None
+ s.beginGroup('revset/' + repoid)
+ s.setValue('geom', self.entrydlg.saveGeometry())
+ s.setValue('queries', self.revsethist)
+ s.setValue('showrepofilterbar', not self.isHidden())
+ s.endGroup()
+
+
+class RepoRegistryFilterBar(RepoFilterBarBase):
+ """Toolbar for RepoRegistry to filter repositories"""
+
+ def __init__(self, parent=None):
+ # type: (Optional[QWidget]) -> None
+ super(RepoRegistryFilterBar, self).__init__(None, parent)
+
+ def _querytype(self, query):
+ # type: (Text) -> Optional[Text]
+ r"""
+ >>> # TODO: maybe replace with real repo
+ >>> origisrevsymbol = scmutil.isrevsymbol
+ >>> scmutil.isrevsymbol = lambda repo, changeid: changeid in repo
+ >>> repo = set(b'0 1 2 3 . stable'.split())
+ >>> _querytype(repo, u'') is None
+ True
+ >>> _querytype(repo, u'quick fox')
+ 'keyword'
+ >>> _querytype(repo, u'0')
+ 'revset'
+ >>> _querytype(repo, u'stable')
+ 'revset'
+ >>> _querytype(repo, u'0::2') # symbol
+ 'revset'
+ >>> _querytype(repo, u'::"stable"') # string
+ 'revset'
+ >>> _querytype(repo, u'"') # unterminated string
+ 'keyword'
+ >>> _querytype(repo, u'tagged()')
+ 'revset'
+ >>> _querytype(repo, u'\u3000') # UnicodeEncodeError
+ 'revset'
+ >>> scmutil.isrevsymbol = origisrevsymbol
+ """
+ if not query:
+ return
+ if '(' in query:
+ return 'revset'
+ try:
+ changeid = _firstword(query)
+ except UnicodeEncodeError:
+ return 'revset' # avoid further error on formatspec()
+ if not changeid:
+ return 'keyword'
+ return 'keyword'
+
+ def loadSettings(self, s):
+ # type: (QSettings) -> None
+ super(RepoRegistryFilterBar, self)._loadSettings(s, "__RepoRegistry")
+
+ def saveSettings(self, s):
+ # type: (QSettings) -> None
+ super(RepoRegistryFilterBar, self)._saveSettings(s, "__RepoRegistry")
+
+
+class RepoFilterBar(RepoFilterBarBase):
+ """Toolbar for RepoWidget to filter changesets"""
+
+ branchChanged = pyqtSignal(str, bool)
+ """Emitted (branch, allparents) when branch selection changed"""
+
+ filterToggled = pyqtSignal(bool)
+ showHiddenChanged = pyqtSignal(bool)
+ showGraftSourceChanged = pyqtSignal(bool)
+
+ _allBranchesLabel = u'\u2605 ' + _('Show all') + u' \u2605'
+
+ def __init__(self, repoagent, parent=None):
+ # type: (thgrepo.RepoAgent, Optional[QWidget]) -> None
+ super(RepoFilterBar, self).__init__(repoagent, parent)
+
+ self._repoagent = repoagent
+ self._permanent_queries = list(_permanent_queries)
+ repo = repoagent.rawRepo()
+ username = hglib.configuredusername(repo.ui)
+ if username:
+ self._permanent_queries.insert(0,
+ hglib.formatrevspec(
+ 'author(%s)',
+ hglib.tounicode(os.path.expandvars(username))
+ )
+ )
+ self.filterEnabled = True
+
+ #Check if the font contains the glyph needed by the branch combo
+ if not QFontMetrics(self.font()).inFont(u'\u2605'):
+ self._allBranchesLabel = u'*** %s ***' % _('Show all')
+
+ self.addSeparator()
+
+ self.filtercb = f = QCheckBox(_('filter'))
+ f.clicked.connect(self.filterToggled)
+ f.setToolTip(_('Toggle filtering of non-matched changesets'))
+ self.addWidget(f)
+
+ self.addSeparator()
+
+ self.showHiddenBtn = QToolButton()
+ self.showHiddenBtn.setIcon(qtlib.geticon('view-hidden'))
+ self.showHiddenBtn.setCheckable(True)
+ self.showHiddenBtn.setToolTip(_('Show/Hide hidden changesets'))
+ self.showHiddenBtn.clicked.connect(self.showHiddenChanged)
+ self.addWidget(self.showHiddenBtn)
+
+ self.showGraftSourceBtn = QToolButton()
+ self.showGraftSourceBtn.setIcon(qtlib.geticon('hg-transplant'))
+ self.showGraftSourceBtn.setCheckable(True)
+ self.showGraftSourceBtn.setChecked(True)
+ self.showGraftSourceBtn.setToolTip(_('Toggle graft relations visibility'))
+ self.showGraftSourceBtn.clicked.connect(self.showGraftSourceChanged)
+ self.addWidget(self.showGraftSourceBtn)
+ self.addSeparator()
+
+ self._initBranchFilter()
+ self.refresh()
+
+ def _querytype(self, query):
+ # type: (Text) -> Optional[Text]
+ r"""
+ >>> # TODO: maybe replace with real repo
+ >>> origisrevsymbol = scmutil.isrevsymbol
+ >>> scmutil.isrevsymbol = lambda repo, changeid: changeid in repo
+ >>> repo = set(b'0 1 2 3 . stable'.split())
+ >>> _querytype(repo, u'') is None
+ True
+ >>> _querytype(repo, u'quick fox')
+ 'keyword'
+ >>> _querytype(repo, u'0')
+ 'revset'
+ >>> _querytype(repo, u'stable')
+ 'revset'
+ >>> _querytype(repo, u'0::2') # symbol
+ 'revset'
+ >>> _querytype(repo, u'::"stable"') # string
+ 'revset'
+ >>> _querytype(repo, u'"') # unterminated string
+ 'keyword'
+ >>> _querytype(repo, u'tagged()')
+ 'revset'
+ >>> _querytype(repo, u'\u3000') # UnicodeEncodeError
+ 'revset'
+ >>> scmutil.isrevsymbol = origisrevsymbol
+ """
+ if not query:
+ return
+ if '(' in query:
+ return 'revset'
+ try:
+ changeid = _firstword(query)
+ except UnicodeEncodeError:
+ return 'revset' # avoid further error on formatspec()
+ if not changeid:
+ return 'keyword'
+ try:
+ if scmutil.isrevsymbol(self._repo, changeid):
+ return 'revset'
+ except error.LookupError: # ambiguous changeid
+ pass
+ return 'keyword'
+
+ def loadSettings(self, s):
+ # type: (QSettings) -> None
+ repoid = hglib.shortrepoid(self._repo)
+ super(RepoFilterBar, self)._loadSettings(s, repoid)
+
+ s.beginGroup('revset/' + repoid)
+ self.filtercb.setChecked(qtlib.readBool(s, 'filter', True))
self.showHiddenBtn.setChecked(qtlib.readBool(s, 'showhidden'))
self.showGraftSourceBtn.setChecked(
qtlib.readBool(s, 'showgraftsource', True))
@@ -410,16 +493,20 @@
repoid = hglib.shortrepoid(self._repo)
except EnvironmentError:
return
+
+ super(RepoFilterBar, self)._saveSettings(s, repoid)
+
s.beginGroup('revset/' + repoid)
- s.setValue('geom', self.entrydlg.saveGeometry())
- s.setValue('queries', self.revsethist)
s.setValue('filter', self.filtercb.isChecked())
- s.setValue('showrepofilterbar', not self.isHidden())
self._saveBranchFilterSettings(s)
s.setValue('showhidden', self.showHiddenBtn.isChecked())
s.setValue('showgraftsource', self.showGraftSourceBtn.isChecked())
s.endGroup()

+ @property
+ def _repo(self):
+ return self._repoagent.rawRepo()
+
def _initBranchFilter(self):
self._branchLabel = QToolButton(
text=_('Branch'), popupMode=QToolButton.InstantPopup,

mvdw...@gmail.com

unread,
Jul 24, 2021, 4:01:18 AM7/24/21
to thg...@googlegroups.com
# HG changeset patch
# User KPOP
# Date 1627110977 -7200
# Sat Jul 24 09:16:17 2021 +0200
# Node ID 5b4ca7040a361f5d20f3c5389fdeff38bed6c147
# Parent 14546c73a780bf78bb284352c87729c75b132ef0
Add the RepoRegistryFilterbar to the registry and fade non-matching repositories

diff -r 14546c73a780 -r 5b4ca7040a36 tortoisehg/hgqt/reporegistry.py
--- a/tortoisehg/hgqt/reporegistry.py Sat Jul 24 09:14:47 2021 +0200
+++ b/tortoisehg/hgqt/reporegistry.py Sat Jul 24 09:16:17 2021 +0200
@@ -30,6 +30,7 @@
QFrame,
QMenu,
QMessageBox,
+ QSplitter,
QTreeView,
QVBoxLayout,
)
@@ -51,6 +52,7 @@
repotreemodel,
settings,
)
+from .repofilter import RepoRegistryFilterBar

def settingsfilename():
"""Return path to thg-reporegistry.xml as unicode"""
@@ -243,8 +245,14 @@
mainframe.setLayout(QVBoxLayout())
self.setWidget(mainframe)
mainframe.layout().setContentsMargins(0, 0, 0, 0)
+ mainframe.layout().setSpacing(0)

self.contextmenu = QMenu(self)
+
+ self.filterbar = RepoRegistryFilterBar(self)
+ mainframe.layout().addWidget(self.filterbar)
+ self._updateShowSearch()
+
self.tview = tv = RepoTreeView(self)
mainframe.layout().addWidget(tv)

@@ -266,6 +274,7 @@
sfile = settingsfilename()
model = repotreemodel.RepoTreeModel(QFile(sfile), repomanager, self,
showShortPaths=self._isSettingEnabled('showShortPaths'))
+ self.filterbar.setRevisionSet.connect(model.setRevisionSet)
tv.setModel(model)

# Setup a file system watcher to update the reporegistry
@@ -295,13 +304,15 @@

def _loadSettings(self):
defaultmap = {'showPaths': False, 'showSubrepos': False,
- 'showNetworkSubrepos': False, 'showShortPaths': True}
+ 'showNetworkSubrepos': False, 'showShortPaths': True, 'showSearch': False}
s = QSettings()
s.beginGroup('Workbench') # for compatibility with old release
for key, action in self._settingactions.items():
action.setChecked(qtlib.readBool(s, key, defaultmap[key]))
s.endGroup()

+ self.filterbar.loadSettings(s)
+
def _saveSettings(self):
s = QSettings()
s.beginGroup('Workbench') # for compatibility with old release
@@ -312,6 +323,8 @@
self._writeExpandedState(s)
s.endGroup()

+ self.filterbar.saveSettings(s)
+
def _loadExpandedState(self):
s = QSettings()
s.beginGroup('reporegistry')
@@ -324,6 +337,7 @@
('showShortPaths', _('Show S&hort Paths'), self._updateCommonPath),
('showSubrepos', _('&Scan Repositories at Startup'), None),
('showNetworkSubrepos', _('Scan &Remote Repositories'), None),
+ ('showSearch', _('Show Search'), self._updateShowSearch),
]
self._settingactions = {}
for i, (key, text, slot) in enumerate(settingtable):
@@ -450,6 +464,14 @@
self.tview.resizeColumnToContents(0)
self.tview.resizeColumnToContents(1)

+ @pyqtSlot()
+ def _updateShowSearch(self):
+ show = self._isSettingEnabled('showSearch')
+ self.filterbar.setVisible(show)
+
+ def setRevisionSet(self, query):
+ self.model.setRevisionSet(query)
+
def close(self):
# We must stop monitoring the settings file and then we can save it
sfile = settingsfilename()
diff -r 14546c73a780 -r 5b4ca7040a36 tortoisehg/hgqt/repotreemodel.py
--- a/tortoisehg/hgqt/repotreemodel.py Sat Jul 24 09:14:47 2021 +0200
+++ b/tortoisehg/hgqt/repotreemodel.py Sat Jul 24 09:16:17 2021 +0200
@@ -23,6 +23,7 @@
pyqtSlot,
)
from .qtgui import (
+ QColor,
QFont,
)

@@ -88,6 +89,7 @@
return [e for e in repotreeitem.flatten(root, stopfunc=stopfunc)
if isinstance(e, repotreeitem.RepoItem)]

+HIDDENREPO_COLOR = QColor('#999999')

class RepoTreeModel(QAbstractItemModel):
def __init__(self, f, repomanager, parent=None,
@@ -167,9 +169,17 @@
if not index.isValid():
return None
if role not in (Qt.DisplayRole, Qt.EditRole, Qt.DecorationRole,
- Qt.FontRole):
+ Qt.FontRole, Qt.ForegroundRole):
return None
item = index.internalPointer()
+ if role == Qt.ForegroundRole:
+ color = None
+ if item.faded() and item is not self._activeRepoItem:
+ if color is None:
+ color = HIDDENREPO_COLOR
+ else:
+ color = color.lighter()
+ return color
if role == Qt.FontRole and item is self._activeRepoItem:
font = QFont()
font.setBold(True)

mvdw...@gmail.com

unread,
Jul 24, 2021, 4:01:19 AM7/24/21
to thg...@googlegroups.com
# HG changeset patch
# User KPOP
# Date 1617870065 -7200
# Thu Apr 08 10:21:05 2021 +0200
# Node ID e3d2e989cb22dbe76918f6c7a1168c1c0d22e2af
# Parent 5b4ca7040a361f5d20f3c5389fdeff38bed6c147
Extend open all to all decendents, including subrepositories and their children and implement the analogue for closing

diff -r 5b4ca7040a36 -r e3d2e989cb22 tortoisehg/hgqt/reporegistry.py
--- a/tortoisehg/hgqt/reporegistry.py Sat Jul 24 09:16:17 2021 +0200
+++ b/tortoisehg/hgqt/reporegistry.py Thu Apr 08 10:21:05 2021 +0200
@@ -224,6 +224,7 @@

showMessage = pyqtSignal(str)
openRepo = pyqtSignal(str, bool)
+ closeRepo = pyqtSignal(str)
removeRepo = pyqtSignal(str)
cloneRepoRequested = pyqtSignal(str)
progressReceived = pyqtSignal(str, object, str, str, object)
@@ -793,10 +794,23 @@
sd.finished.connect(sd.deleteLater)
sd.exec_()

+ def _openAll(self, index, notOnlyMatching):
+ for childRepoItem in index.internalPointer().allRepoItems():
+ if notOnlyMatching or not childRepoItem.faded():
+ self.openRepo.emit(childRepoItem.rootpath(), False)
def openAll(self):
- index = self.tview.currentIndex()
- for root in index.internalPointer().childRoots():
- self.openRepo.emit(root, False)
+ self._openAll(self.tview.currentIndex(), True)
+ def openAllMatching(self):
+ self._openAll(self.tview.currentIndex(), False)
+
+ def _closeAll(self, index, notOnlyNonMatching=False):
+ for childRepoItem in index.internalPointer().allRepoItems():
+ if notOnlyNonMatching or childRepoItem.faded():
+ self.closeRepo.emit(childRepoItem.rootpath())
+ def closeAll(self):
+ self._closeAll(self.tview.currentIndex(), True)
+ def closeAllNonMatching(self):
+ self._closeAll(self.tview.currentIndex(), False)

def open(self, root=None):
'open context menu action, open repowidget unconditionally'
diff -r 5b4ca7040a36 -r e3d2e989cb22 tortoisehg/hgqt/repotreeitem.py
--- a/tortoisehg/hgqt/repotreeitem.py Sat Jul 24 09:16:17 2021 +0200
+++ b/tortoisehg/hgqt/repotreeitem.py Thu Apr 08 10:21:05 2021 +0200
@@ -198,6 +198,14 @@
def childCount(self):
return len(self.childs)

+ def allRepoItems(self):
+ repoItems = []
+ if isinstance(self, RepoItem):
+ repoItems.extend([self])
+ for c in self.childs:
+ repoItems.extend(c.allRepoItems())
+ return repoItems
+
def columnCount(self):
return 2

@@ -647,9 +655,6 @@
return (Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDropEnabled
| Qt.ItemIsDragEnabled | Qt.ItemIsEditable)

- def childRoots(self):
- return [c._root for c in self.childs if isinstance(c, RepoItem)]
-
def dump(self, xw):
xw.writeAttribute('name', self.name)
_dumpChild(xw, parent=self)
diff -r 5b4ca7040a36 -r e3d2e989cb22 tortoisehg/hgqt/workbench.py
--- a/tortoisehg/hgqt/workbench.py Sat Jul 24 09:16:17 2021 +0200
+++ b/tortoisehg/hgqt/workbench.py Thu Apr 08 10:21:05 2021 +0200
@@ -76,6 +76,7 @@
rr.setObjectName('RepoRegistryView')
rr.showMessage.connect(self.statusbar.showMessage)
rr.openRepo.connect(self.openRepo)
+ rr.closeRepo.connect(self.repoTabsWidget.closeRepo)
rr.removeRepo.connect(self.repoTabsWidget.closeRepo)
rr.cloneRepoRequested.connect(self.cloneRepository)
rr.progressReceived.connect(self.statusbar.progress)

mvdw...@gmail.com

unread,
Jul 24, 2021, 4:01:19 AM7/24/21
to thg...@googlegroups.com
# HG changeset patch
# User KPOP
# Date 1617870074 -7200
# Thu Apr 08 10:21:14 2021 +0200
# Node ID 6a3a5ae0236eec3f48db01c8348e1f1a4cdc854f
# Parent e3d2e989cb22dbe76918f6c7a1168c1c0d22e2af
Add context menu items to open/close all repositories or those (not) matching the current revset filter

diff -r e3d2e989cb22 -r 6a3a5ae0236e tortoisehg/hgqt/reporegistry.py
--- a/tortoisehg/hgqt/reporegistry.py Thu Apr 08 10:21:05 2021 +0200
+++ b/tortoisehg/hgqt/reporegistry.py Thu Apr 08 10:21:14 2021 +0200
@@ -489,6 +489,14 @@
_("Open the repository in a new tab"), self.open),
("openAll", _("&Open All"), 'thg-repository-open',
_("Open all repositories in new tabs"), self.openAll),
+ ("openAllMatching", _("Open All &Matching"), 'thg-repository-open',
+ _("Open repositories matching the current filter in new tabs"),
+ self.openAllMatching),
+ ("closeAll", _("&Close All"), None,
+ _("Close all tabs from this group"), self.closeAll),
+ ("closeAllNonMatching", _("Close All &Non-Matching"), None,
+ _("Close tabs that do not match the current filter"),
+ self.closeAllNonMatching),
("newGroup", _("New &Group"), 'new-group',
_("Create a new group"), self.newGroup),
("rename", _("Re&name"), None,
diff -r e3d2e989cb22 -r 6a3a5ae0236e tortoisehg/hgqt/repotreeitem.py
--- a/tortoisehg/hgqt/repotreeitem.py Thu Apr 08 10:21:05 2021 +0200
+++ b/tortoisehg/hgqt/repotreeitem.py Thu Apr 08 10:21:14 2021 +0200
@@ -373,6 +373,7 @@
acts = ['open', 'clone', 'addsubrepo', None, 'explore',
'terminal', 'copypath', None, 'rename', 'remove']
if self.childCount() > 0:
+ acts.extend([None, 'openAll', 'closeAll', None, 'openAllMatching', 'closeAllNonMatching' ])
acts.extend([None, (_('&Sort'), ['sortbyname', 'sortbyhgsub'])])
acts.extend([None, 'settings'])
return acts
@@ -647,7 +648,8 @@
return self.name

def menulist(self):
- return ['openAll', 'add', None, 'newGroup', None, 'rename', 'remove',
+ return ['openAll', 'closeAll', None, 'openAllMatching', 'closeAllNonMatching',
+ None, 'add', None, 'newGroup', None, 'rename', 'remove',
None, (_('&Sort'), ['sortbyname', 'sortbypath']), None,
'reloadRegistry']

@@ -707,7 +709,8 @@
RepoGroupItem.__init__(self, name or _('default'), parent=parent)

def menulist(self):
- return ['openAll', 'add', None, 'newGroup', None, 'rename',
+ return ['openAll', 'closeAll', None, 'openAllMatching', 'closeAllNonMatching',
+ None, 'add', None, 'newGroup', None, 'rename',
None, (_('&Sort'), ['sortbyname', 'sortbypath']), None,
'reloadRegistry']

mvdw...@gmail.com

unread,
Jul 24, 2021, 4:01:20 AM7/24/21
to thg...@googlegroups.com
# HG changeset patch
# User KPOP
# Date 1617960297 -7200
# Fri Apr 09 11:24:57 2021 +0200
# Node ID 6d6ff1d8811c61568247312093687189a1ba606e
# Parent 6a3a5ae0236eec3f48db01c8348e1f1a4cdc854f
Add filtering based on revset queries

diff -r 6a3a5ae0236e -r 6d6ff1d8811c tests/qt_repotreemodel_test.py
--- a/tests/qt_repotreemodel_test.py Thu Apr 08 10:21:14 2021 +0200
+++ b/tests/qt_repotreemodel_test.py Fri Apr 09 11:24:57 2021 +0200
@@ -18,6 +18,8 @@
repotreeitem,
)

+import helpers
+
def prettyxml(s):
dom = minidom.parseString(s)
return dom.toprettyxml(indent=' ').splitlines()
@@ -285,3 +287,71 @@
assert not isFaded(subroot2Index)
assert not isFaded(svnsub2Index)
assert not isFaded(sub2Index)
+
+def test_repotreemodel_filter_branch():
+ """Test filtering based on the repo's branches"""
+
+ # Prepare repo
+ repopath = helpers.mktmpdir(__name__)
+ hg = helpers.HgClient(repopath)
+ hg.init()
+ hg.branch(b'default')
+ hg.ftouch(b'data')
+ hg.add(b'data')
+ hg.commit(b'-m', b'Initial commit')
+ for branch in [ b"somebranch", b"someotherbranch"]:
+ hg.branch(branch)
+ hg.commit(b'-m', b'new branch %s' % branch)
+
+ # Prepare model
+ data = br'''<?xml version="1.0" encoding="UTF-8"?>
+ <reporegistry>
+ <treeitem>
+ <allgroup name="default">
+ <repo root="%s" shortname="repo"/>
+ <repo root="nonExistingRepo"/>
+ </allgroup>
+ </treeitem>
+ </reporegistry>
+ ''' % repopath
+ ba = QByteArray(data) # keep reference to avoid GC
+ f = QBuffer(ba)
+ f.open(QIODevice.ReadOnly)
+ repomanager = DummyRepoManager()
+ model = repotreemodel.RepoTreeModel(f, repomanager)
+
+ rootIndex = QModelIndex()
+ assert model.rowCount(rootIndex) is 1
+ allGroupIndex = model.index(0, 0, rootIndex)
+ assert model.rowCount(allGroupIndex) is 2
+ repoIndex = model.index(0, 0, allGroupIndex)
+ assert model.data(repoIndex) == 'repo'
+ nonExistingRepoIndex = model.index(1, 0, allGroupIndex)
+ assert model.data(nonExistingRepoIndex) == 'nonExistingRepo'
+
+ def isFaded(modelIndex):
+ return modelIndex.internalPointer().faded()
+
+ model.setRevisionSet("")
+ assert not isFaded(repoIndex)
+ assert not isFaded(nonExistingRepoIndex)
+
+ model.setRevisionSet("branch(default)")
+ assert not isFaded(repoIndex)
+ assert isFaded(nonExistingRepoIndex)
+
+ model.setRevisionSet("branch('nonexistingRepo')")
+ assert isFaded(repoIndex)
+ assert isFaded(nonExistingRepoIndex)
+
+ model.setRevisionSet("branch('re:some.*')")
+ assert not isFaded(repoIndex)
+ assert isFaded(nonExistingRepoIndex)
+
+ model.setRevisionSet("branch('re:SOME.*')")
+ assert isFaded(repoIndex) # case sensitive
+ assert isFaded(nonExistingRepoIndex)
+
+ model.setRevisionSet("")
+ assert not isFaded(repoIndex)
+ assert not isFaded(nonExistingRepoIndex)
diff -r 6a3a5ae0236e -r 6d6ff1d8811c tortoisehg/hgqt/repotreeitem.py
--- a/tortoisehg/hgqt/repotreeitem.py Thu Apr 08 10:21:14 2021 +0200
+++ b/tortoisehg/hgqt/repotreeitem.py Fri Apr 09 11:24:57 2021 +0200
@@ -20,6 +20,7 @@
)

from mercurial import (
+ commands,
error,
hg,
node,
@@ -502,6 +503,20 @@
keywordMatch = self._testRevisionSetKeyword(revisionSet, self.shortname())
if keywordMatch is not None:
return keywordMatch
+
+ try:
+ ui = hglib.loadui()
+ repo = hg.repository(ui, hglib.fromunicode(self._root))
+ ui.pushbuffer()
+ commands.log(ui, repo, limit=1, rev=[hglib.fromunicode(revisionSet)])
+ output = ui.popbuffer()
+ print(output)
+ return len(output) > 0
+ except error.RepoLookupError:
+ return False # Does not match
+ except error.RepoError:
+ return False # Repo does not work

mvdw...@gmail.com

unread,
Jul 24, 2021, 4:01:21 AM7/24/21
to thg...@googlegroups.com
# HG changeset patch
# User KPOP
# Date 1627112326 -7200
# Sat Jul 24 09:38:46 2021 +0200
# Node ID e6db34ca4b02d3ac140cd4b978ae626f87f1ec87
# Parent 6d6ff1d8811c61568247312093687189a1ba606e
Create a new tab only if it's not open already

diff -r 6d6ff1d8811c -r e6db34ca4b02 tortoisehg/hgqt/repotab.py
--- a/tortoisehg/hgqt/repotab.py Fri Apr 09 11:24:57 2021 +0200
+++ b/tortoisehg/hgqt/repotab.py Sat Jul 24 09:38:46 2021 +0200
@@ -124,6 +124,10 @@

def openRepo(self, root, bundle=None):
"""Open the specified repository in new tab"""
+ for i in pycompat.xrange(self.count()):
+ if self.repoRootPath(i) == root:
+ return # already open
+
rw = self._createRepoWidget(root, bundle)
if not rw:
return False

Yuya Nishihara

unread,
Jul 26, 2021, 8:01:31 AM7/26/21
to thg...@googlegroups.com, mvdw...@gmail.com
On Sat, 24 Jul 2021 10:01:16 +0200, mvdw...@gmail.com wrote:
> # HG changeset patch
> # User KPOP
> # Date 1627110887 -7200
> # Sat Jul 24 09:14:47 2021 +0200
> # Node ID 14546c73a780bf78bb284352c87729c75b132ef0
> # Parent 17848c398d3818a208bd517c2c665f18e1716a3d
> Extract RepoFilterBarBase from RepoFilterBar and derive RepoRegistryFilterBar for use in the RepoRegistry

It's probably better to extract a core component that depends on
repo/repoAgent. Widget inheritance is likely to get mess.

class RepoFilterBarLogic(object): # TODO: naming
def queryType(self, query): # for example
return ...
...

def createRepoFilterBar(repoAgent, parent):
c = RepoFilterBarLogic(repoAgent) # TODO: naming
return RepoFilterBar(c, parent)

def createRepoRegistryFilterBar(parent):
c = RepoRegistryFilterBarLogic() # TODO: naming
return RepoFilterBar(c, parent)

Yuya Nishihara

unread,
Jul 26, 2021, 8:01:34 AM7/26/21
to thg...@googlegroups.com, mvdw...@gmail.com
Maybe we can ditch the repoAgent argument at all, and pass hgsubversion
flag instead?

w = RevisionSetQuery(..., extensions={'hgsubversion'})
w.setWindowTitle(...)

Yuya Nishihara

unread,
Jul 26, 2021, 8:01:38 AM7/26/21
to thg...@googlegroups.com, mvdw...@gmail.com
I don't remember the details, but it might be intended behavior that
RepoRegistry can open duplicated repo tabs.

Anyway, this is similar to the reuse flag of Workbench.openRepo(), so it
should be handled at the same layer, not in RepoTab.

Yuya Nishihara

unread,
Jul 26, 2021, 8:01:52 AM7/26/21
to thg...@googlegroups.com, mvdw...@gmail.com
On Sat, 24 Jul 2021 10:01:20 +0200, mvdw...@gmail.com wrote:
> # HG changeset patch
> # User KPOP
> # Date 1617960297 -7200
> # Fri Apr 09 11:24:57 2021 +0200
> # Node ID 6d6ff1d8811c61568247312093687189a1ba606e
> # Parent 6a3a5ae0236eec3f48db01c8348e1f1a4cdc854f
> Add filtering based on revset queries

> --- a/tortoisehg/hgqt/repotreeitem.py Thu Apr 08 10:21:14 2021 +0200
> +++ b/tortoisehg/hgqt/repotreeitem.py Fri Apr 09 11:24:57 2021 +0200
> @@ -20,6 +20,7 @@
> )
>
> from mercurial import (
> + commands,
> error,
> hg,
> node,
> @@ -502,6 +503,20 @@
> keywordMatch = self._testRevisionSetKeyword(revisionSet, self.shortname())
> if keywordMatch is not None:
> return keywordMatch
> +
> + try:
> + ui = hglib.loadui()
> + repo = hg.repository(ui, hglib.fromunicode(self._root))
> + ui.pushbuffer()
> + commands.log(ui, repo, limit=1, rev=[hglib.fromunicode(revisionSet)])

Instantiating repo for all repo-tree items would be too slow to run on GUI
process, and revset query could take a few seconds for each repo.
Maybe you can instead write a Mercurial command to run a revset query for
the specified repositories, and run it by CmdAgent.

$ hg debugbulkrevset -Tjson -rrevspec repo1 repo2 ...
^^^ implement this command, and run it by CmdAgent

See hgqt/hginit.py for CmdAgent, and util/hgcommands.py for extension command.

Yuya Nishihara

unread,
Jul 26, 2021, 8:01:56 AM7/26/21
to thg...@googlegroups.com, mvdw...@gmail.com
On Sat, 24 Jul 2021 10:01:14 +0200, mvdw...@gmail.com wrote:
> # HG changeset patch
> # User KPOP
> # Date 1627111490 -7200
> # Sat Jul 24 09:24:50 2021 +0200
> # Node ID cd0578829cffec43109c43712e936f9cf35d4c48
> # Parent 26d6c2d13e47479cec083154ca21572e876c46af
> Add case insensitive filtering based on repository name

> + def _testRevisionSetKeyword(self, revisionSet, keywordString):
> + """Helper method for keyword based searching"""
> + keywordm = _keywordrevisionsetre.search(revisionSet)
> + if keywordm:
> + return re.search(keywordm.group('keyword'), keywordString, re.IGNORECASE) is not None

This doesn't look correct since keyword(...) revset should search the change
log whereas keywordString is shortname or name.

> class RepoItem(RepoTreeItem):
> xmltagname = 'repo'
> @@ -460,6 +489,11 @@
> return True
> return False
>
> + def _testRevisionSet(self, revisionSet):
> + keywordMatch = self._testRevisionSetKeyword(revisionSet, self.shortname())
> + if keywordMatch is not None:
> + return keywordMatch
> + return False
>
> _subrepoType2IcoMap = {
> 'hg': 'hg',
> @@ -551,6 +585,12 @@
> def appendSubrepos(self, repo=None):
> raise Exception('unsupported by non-hg subrepo')
>
> + def _testRevisionSet(self, revisionSet):
> + keywordMatch = self._testRevisionSetKeyword(revisionSet, self._repotype)

Why testing repotype instead of shortname?

> + def _testRevisionSet(self, revisionSet):
> + keywordMatch = self._testRevisionSetKeyword(revisionSet, self.name)

This one looks good. self.name == self.shortname().

> @@ -434,3 +434,6 @@
> self.layoutAboutToBeChanged.emit()
> childs.sort(key=keyfunc)
> self.layoutChanged.emit()
> + def setRevisionSet(self, revisionSet):
> + self.rootItem.setRevisionSet(revisionSet,
> + lambda item : self._emitItemDataChanged(item))

Instead of passing around callback function, you can emit dataChanged signal
for all items including unmodified rows. This is simpler and better than
emitting lots of dataChanged signals repeatedly.

self.dataChanged.emit(self.index(0, 0),
self.index(self.rowCount() - 1, self.columnCount() - 1))

It'll be a bit tedious for treed model, though:

def _emitDataChangedRecursively(self, parent):
count = self.rowCount(parent)
if count <= 0:
return
for i in range(count):
self._emitDataChangedRecursively(self.index(i, 0, parent))
self.dataChanged.emit(self.index(0, 0, parent),
self.index(count - 1, self.columnCount() - 1, parent))

Yuya Nishihara

unread,
Jul 27, 2021, 6:57:37 AM7/27/21
to thg...@googlegroups.com, mvdw...@gmail.com
On Sat, 24 Jul 2021 10:01:13 +0200, mvdw...@gmail.com wrote:
> # HG changeset patch
> # User KPOP
> # Date 1619459899 -7200
> # Mon Apr 26 19:58:19 2021 +0200
> # Node ID 26d6c2d13e47479cec083154ca21572e876c46af
> # Parent 5849ec046555ce24a28268c086ab171ff41ad268
> Add extra tests for registry

Queued this one, thanks.

> +@with_qbuffer(filter_data)
> +def test_repotreemodel(f):
> + """Test data used for the filtering tests"""
> + repomanager = DummyRepoManager()
> + model = repotreemodel.RepoTreeModel(f, repomanager)
> +
> + rootIndex = QModelIndex()
> + assert model.rowCount(rootIndex) is 2

s/is/==/ since "is" basically compares the address of the objects, not
the value.
Reply all
Reply to author
Forward
0 new messages