Features:
- When opening thg, thg will scan all repos in the repo registry and show their
subrepositories (as they are in their working directory)
- When opening a new repository, its subrepos will also be shown on the repo registry.
- Subrepos are not saved to the repo registry.
- It is possible to copy subrepos into the registry by dragging them.
Limitations:
- Subrepos are not updated (yet) when the selected parent repository revision changes.
- Subrepos are shown as regular repos. It might be best to shown them with a "subrepo
icon" and they could even have their own context menu. This could be done by subclassing.
the RepoItem class.
- There are no checks for non mercurial subrepos, which may cause problems.
diff --git a/tortoisehg/hgqt/repotreeitem.py b/tortoisehg/hgqt/repotreeitem.py
--- a/tortoisehg/hgqt/repotreeitem.py
+++ b/tortoisehg/hgqt/repotreeitem.py
@@ -8,10 +8,12 @@
import sys, os
from mercurial import node
+from mercurial import ui
from tortoisehg.util import hglib
from tortoisehg.hgqt.i18n import _
from tortoisehg.hgqt import qtlib
+from tortoisehg.hgqt import thgrepo
from PyQt4.QtCore import *
from PyQt4.QtGui import *
@@ -189,7 +191,6 @@
xw.writeAttribute('root', hglib.tounicode(self._root))
xw.writeAttribute('shortname', self.shortname())
xw.writeAttribute('basenode', node.hex(self.basenode()))
- RepoTreeItem.dump(self, xw)
def undump(self, xr):
a = xr.attributes()
@@ -198,6 +199,17 @@
self._basenode = node.bin(str(a.value('', 'basenode').toString()))
RepoTreeItem.undump(self, xr)
+ def addSubrepos(ri):
+ repo = thgrepo.repository(ui.ui(), ri.rootpath())
+ for subpath in repo['.'].substate:
+ sctx = repo['.'].sub(subpath)
+ thgsrepo = thgrepo.repository(sctx._repo.ui, sctx._repo.root)
+ ri.appendChild(RepoItem(self.model, sctx._repo.root))
+ if ri.childCount():
+ addSubrepos(ri.child(ri.childCount()-1))
+
+ addSubrepos(self)
+
def details(self):
return _('Local Repository %s') % hglib.tounicode(self._root)
diff --git a/tortoisehg/hgqt/repotreemodel.py b/tortoisehg/hgqt/repotreemodel.py
--- a/tortoisehg/hgqt/repotreemodel.py
+++ b/tortoisehg/hgqt/repotreemodel.py
@@ -7,6 +7,7 @@
from tortoisehg.util import hglib
from tortoisehg.hgqt.i18n import _
+from tortoisehg.hgqt import thgrepo
from repotreeitem import undumpObject, AllRepoGroupItem, RepoGroupItem
from repotreeitem import RepoItem, RepoTreeItem
@@ -222,6 +223,16 @@
row = rgi.childCount()
self.beginInsertRows(grp, row, row)
rgi.insertChild(row, RepoItem(self, root))
+ def addSubrepos(ri, repo):
+ for subpath in repo['.'].substate:
+ sctx = repo['.'].sub(subpath)
+ thgsrepo = thgrepo.repository(sctx._repo.ui, sctx._repo.root)
+ ri.insertChild(row,
+ RepoItem(self, sctx._repo.root))
+ addSubrepos(ri.child(ri.childCount()-1), thgsrepo)
+ from mercurial import ui
+ repo = thgrepo.repository(ui.ui(), root)
+ addSubrepos(rgi.child(rgi.childCount()-1), repo)
self.endInsertRows()
def getRepoItem(self, reporoot):
These look good except for the use of thgrepo.repository(). We want
to avoid all that overhead for every Mercurial repository on the local
drive.
You should be able to use the same 'isinstance' check that filedata
uses to determine whether a subrepo is a mercurial subrepo, and then
directory use it's _repo.
--
Steve Borho
diff --git a/tortoisehg/hgqt/repotreeitem.py b/tortoisehg/hgqt/repotreeitem.py
--- a/tortoisehg/hgqt/repotreeitem.py
+++ b/tortoisehg/hgqt/repotreeitem.py
@@ -8,10 +8,12 @@
import sys, os
from mercurial import node
+from mercurial import ui, hg
from tortoisehg.util import hglib
from tortoisehg.hgqt.i18n import _
from tortoisehg.hgqt import qtlib
+from tortoisehg.hgqt import thgrepo
from PyQt4.QtCore import *
from PyQt4.QtGui import *
@@ -189,7 +191,6 @@
xw.writeAttribute('root', hglib.tounicode(self._root))
xw.writeAttribute('shortname', self.shortname())
xw.writeAttribute('basenode', node.hex(self.basenode()))
- RepoTreeItem.dump(self, xw)
def undump(self, xr):
a = xr.attributes()
@@ -198,6 +199,18 @@
self._basenode = node.bin(str(a.value('', 'basenode').toString()))
RepoTreeItem.undump(self, xr)
+ def addSubrepos(ri):
+ repo = hg.repository(ui.ui(), ri.rootpath())
+ for subpath in repo['.'].substate:
+ # For now we only support showing mercurial subrepos
+ if repo['.'].substate[subpath][2] == 'hg':
+ sctx = repo['.'].sub(subpath)
diff --git a/tortoisehg/hgqt/repotreemodel.py b/tortoisehg/hgqt/repotreemodel.py
--- a/tortoisehg/hgqt/repotreemodel.py
+++ b/tortoisehg/hgqt/repotreemodel.py
@@ -7,6 +7,7 @@
from tortoisehg.util import hglib
from tortoisehg.hgqt.i18n import _
+from tortoisehg.hgqt import thgrepo
from repotreeitem import undumpObject, AllRepoGroupItem, RepoGroupItem
from repotreeitem import RepoItem, RepoTreeItem
@@ -222,6 +223,17 @@
row = rgi.childCount()
self.beginInsertRows(grp, row, row)
rgi.insertChild(row, RepoItem(self, root))
+ def addSubrepos(ri, repo):
+ for subpath in repo['.'].substate:
+ # For now we only support showing mercurial subrepos
+ if repo['.'].substate[subpath][2] == 'hg':
+ sctx = repo['.'].sub(subpath)
+ ri.insertChild(row,
+ RepoItem(self, sctx._repo.root))
+ addSubrepos(ri.child(ri.childCount()-1), sctx._repo)
+ from mercurial import ui, hg
+ repo = hg.repository(ui.ui(), root)
You are right, some where not even being used! They were there because
I needed them on a first version of the patch that I did not send.
I've just resent the patch series fixing this (and other problems).
However, I still needed to create some repo objects. In those (few)
cases I don't need a thgrepo, so I will use hg.repository() instead.
> You should be able to use the same 'isinstance' check that filedata
> uses to determine whether a subrepo is a mercurial subrepo, and then
> directory use it's _repo.
In the new version of these patches, rather than checking the instance
type I checked for:
repo['.'].substate[subpath][2] == 'hg'
By doing that I avoid calling repo['.'].sub(), which seems more
expensive. Do you think that is ok?
Angel
It's probably no more expensive than calling repo['.'] twice. However
that is diving a layer lower than we probably should into Mercurial's
API, meaning that they are more likely to break us in the future. I
lean towards using wctx.sub().
Also be aware that calling hg.repository() and then repo['.'] on
random repositories is going to throw exceptions every once in a while
and we need to catch them gracefully.
I'm also a bit worried about scanning every repo in the registry for
subrepos at startup. Consider what this user is doing:
https://bitbucket.org/tortoisehg/thg/issue/537/synchronize-tab-timeout
--
Steve Borho
OK, I will start by caching the call to repo['.'] for now (as you
suggested on another thread).
I agree that this may be diving a bit too low into mercurial's API
although we do access repo.substate in quite a few places in the code
already so if they change it we are already screwed :-P
Due to the way I've implemented non mercurial subrepo support (in the
patch that followed this one) makes it much more convenient (right
now) to use the subrepo type as recorded on the repo.substate
property. So if you do not mind I'd rather keep things as they are for
now and if you want me to use the alternative approach instead (i.e.
using "isinstance") I'd rather do it on a subsequent patch series on
top of this one. Would that be ok?
> Also be aware that calling hg.repository() and then repo['.'] on
> random repositories is going to throw exceptions every once in a while
> and we need to catch them gracefully.
True, I will do so. I did not realize that when I improved the subrepo
support on the manifest those exception were already being catches for
me. I see that in filedata they catch EnvironmentError,
error.RepoError and util.Abort. Should I catch those 3 as well here?
What do you think that should be done when such an error happens? I
could silently catch the error and simply not show the corresponding
subrepo or show an error message. What would you prefer?
> I'm also a bit worried about scanning every repo in the registry for
> subrepos at startup. Consider what this user is doing:
> https://bitbucket.org/tortoisehg/thg/issue/537/synchronize-tab-timeout
I think the solution for that could be to make showing subrepos a
configuration option or perhaps a checkbox on the View menu (like
"Show paths"). Again, this could be done on a separate patch.
Also, we could avoid looking for subrepos for "remote" (i.e. UNC)
repositories. Is there an easy way (e.g. an existing function) that
would tell whether a repository is "remote"? Or should I simply check
whether their path begins with "\\"? That seems too windows specific,
but I don't know how would you check that a certain repo is mounted on
a remote machine in Linux, for example.
Angel
One problem that I've found is that I am not able to force qt to put a carriage return on the qtlib.WarningMsgBox, making the error messages uglier than they should. Any ideas?
diff --git a/tortoisehg/hgqt/repotreeitem.py b/tortoisehg/hgqt/repotreeitem.py
--- a/tortoisehg/hgqt/repotreeitem.py
+++ b/tortoisehg/hgqt/repotreeitem.py
@@ -8,10 +8,12 @@
import sys, os
from mercurial import node
+from mercurial import ui, hg
from tortoisehg.util import hglib
from tortoisehg.hgqt.i18n import _
from tortoisehg.hgqt import qtlib
+from tortoisehg.hgqt import thgrepo
from PyQt4.QtCore import *
from PyQt4.QtGui import *
@@ -189,7 +191,6 @@
xw.writeAttribute('root', hglib.tounicode(self._root))
xw.writeAttribute('shortname', self.shortname())
xw.writeAttribute('basenode', node.hex(self.basenode()))
- RepoTreeItem.dump(self, xw)
def undump(self, xr):
a = xr.attributes()
@@ -198,6 +199,18 @@
self._basenode = node.bin(str(a.value('', 'basenode').toString()))
RepoTreeItem.undump(self, xr)
+ def addSubrepos(ri):
+ repo = hg.repository(ui.ui(), ri.rootpath())
+ for subpath in repo['.'].substate:
+ # For now we only support showing mercurial subrepos
+ if repo['.'].substate[subpath][2] == 'hg':
+ sctx = repo['.'].sub(subpath)
diff --git a/tortoisehg/hgqt/repotreeitem.py b/tortoisehg/hgqt/repotreeitem.py
--- a/tortoisehg/hgqt/repotreeitem.py
+++ b/tortoisehg/hgqt/repotreeitem.py
@@ -205,19 +205,43 @@
RepoTreeItem.undump(self, xr)
def addSubrepos(ri, repo):
- wctx = repo['.']
- for subpath in wctx.substate:
- # For now we only support showing mercurial subrepos
- subtype = wctx.substate[subpath][2]
- sctx = wctx.sub(subpath)
- ri.appendChild(
- SubrepoItem(self.model, sctx._repo.root, subtype=subtype))
- if subtype == 'hg':
- # Only recurse into mercurial subrepos
- if ri.childCount():
- addSubrepos(ri.child(ri.childCount()-1), sctx._repo)
+ invalidRepoList = []
+ try:
+ wctx = repo['.']
+ for subpath in wctx.substate:
+ # For now we only support showing mercurial subrepos
+ subtype = wctx.substate[subpath][2]
+ sctx = wctx.sub(subpath)
+ ri.appendChild(
+ SubrepoItem(self.model, sctx._repo.root, subtype=subtype))
+ if subtype == 'hg':
+ # Only recurse into mercurial subrepos
+ if ri.childCount():
+ invalidRepoList += \
+ addSubrepos(
+ ri.child(ri.childCount()-1), sctx._repo)
+ except (EnvironmentError, error.RepoError, util.Abort), e:
+ # Add the repo to the list of repos/subrepos
+ # that could not be open
+ invalidRepoList.append(repo.root)
+
+ return invalidRepoList
- addSubrepos(self, hg.repository(ui.ui(), self.rootpath()))
+ root = self.rootpath()
+ invalidRepoList = \
+ addSubrepos(self, hg.repository(ui.ui(), root))
+
+ if invalidRepoList:
+ if invalidRepoList[0] == root:
+ qtlib.WarningMsgBox(_('Could not get subrepository list'),
+ _('It was not possible to get the subrepository list for '
+ 'the repository in %s') % root)
+ else:
+ qtlib.WarningMsgBox(_('Could not open some subrepositories'),
+ _('It was not possible to fully load the subrepository list '
+ 'for the repository in %s.\n\n'
+ 'The following subrepositories could not be accessed:\n\n%s') %
+ (root, "\n".join(invalidRepoList)))
def details(self):
return _('Local Repository %s') % hglib.tounicode(self._root)
diff --git a/tortoisehg/hgqt/repotreemodel.py b/tortoisehg/hgqt/repotreemodel.py
--- a/tortoisehg/hgqt/repotreemodel.py
+++ b/tortoisehg/hgqt/repotreemodel.py
@@ -5,8 +5,11 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from mercurial import ui, hg, util, error
+
from tortoisehg.util import hglib
from tortoisehg.hgqt.i18n import _
+from tortoisehg.hgqt import qtlib
from tortoisehg.hgqt import thgrepo
from repotreeitem import undumpObject, AllRepoGroupItem, RepoGroupItem
@@ -226,22 +229,43 @@
self.beginInsertRows(grp, row, row)
rgi.insertChild(row, RepoItem(self, root))
def addSubrepos(ri, repo):
- wctx = repo['.']
- for subpath in wctx.substate:
- # For now we only support showing mercurial subrepos
- subtype = wctx.substate[subpath][2]
- sctx = wctx.sub(subpath)
- ri.insertChild(row,
- SubrepoItem(self, sctx._repo.root, subtype=subtype))
- if subtype == 'hg':
- # Only recurse into mercurial subrepos
- if ri.childCount():
- addSubrepos(ri.child(ri.childCount()-1), sctx._repo)
+ invalidRepoList = []
+ try:
+ wctx = repo['.']
+ for subpath in wctx.substate:
+ # For now we only support showing mercurial subrepos
+ subtype = wctx.substate[subpath][2]
+ sctx = wctx.sub(subpath)
+ ri.insertChild(row,
+ SubrepoItem(self, sctx._repo.root, subtype=subtype))
+ if subtype == 'hg':
+ # Only recurse into mercurial subrepos
+ if ri.childCount():
+ invalidRepoList += \
+ addSubrepos(
+ ri.child(ri.childCount()-1), sctx._repo)
+ except (EnvironmentError, error.RepoError, util.Abort), e:
+ # Add the repo to the list of repos/subrepos
+ # that could not be open
+ invalidRepoList.append(repo.root)
- from mercurial import ui, hg
+ return invalidRepoList
+
repo = hg.repository(ui.ui(), root)
- addSubrepos(rgi.child(rgi.childCount()-1), repo)
+ invalidRepoList = \
+ addSubrepos(rgi.child(rgi.childCount()-1), repo)
self.endInsertRows()
+
+ if invalidRepoList:
+ if invalidRepoList[0] == root:
+ qtlib.WarningMsgBox(_('Could not get subrepository list'),
+ _('It was not possible to get the subrepository list for '
+ 'the repository in %s') % root)
+ else:
+ qtlib.WarningMsgBox(_('Could not open some subrepositories'),
+ _('It was not possible to fully load the subrepository list '
+ 'for the repository in %s.\nThe following subrepositories:\n\n\n\n%s') %
+ (root, "\n".join(invalidRepoList)))
def getRepoItem(self, reporoot):
return self.rootItem.getRepoItem(reporoot)
This patch fixes most of the limitations with the way subrepos are shown on the
repo registry.
- It shows each subrepo type (hg, git, svn) with its own icon (git and svn icons
are based on icons found on the wikimedia site which have a Creative Commons
license)
- It overlays a "subrepo" icon on top of the subrepo icon type
This could have done by embedding the "subrepo" icon on top of each of the
subrepo icon types, but this solution seems more flexible and makes it easier
to change the subrepo marker icon in the future.
For non mercurial subrepos:
- It disables drag and drop
- It disables double clicking to open
- It hides those context menu actions that do not make sense for non mercurial
subrepos
diff --git a/icons/scalable/status/thg-git-subrepo.svg b/icons/scalable/status/thg-git-subrepo.svg
new file mode 100644
--- /dev/null
+++ b/icons/scalable/status/thg-git-subrepo.svg
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="256"
+ id="svg2"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:version="0.48.0 r9654"
+ sodipodi:docname="thg-git-subrepo.svg"
+ sodipodi:version="0.32"
+ version="1.0"
+ width="256">
+ <metadata
+ id="metadata3">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:title></dc:title>
+ <dc:description />
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>unsorted</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:publisher>
+ <cc:Agent
+ rdf:about="http://www.openclipart.org/">
+ <dc:title>Open Clip Art Library, Source: Wiki Commons, Source: Wikimedia Commons</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:rights>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:rights>
+ <dc:date />
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <cc:license
+ rdf:resource="GPL" />
+ <dc:language>en</dc:language>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs22">
+ <inkscape:perspective
+ id="perspective26"
+ inkscape:persp3d-origin="35.5 : 8.6666667 : 1"
+ inkscape:vp_x="0 : 13 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="71 : 13 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ </defs>
+ <sodipodi:namedview
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10.0"
+ guidetolerance="10.0"
+ id="base"
+ inkscape:current-layer="svg2"
+ inkscape:cx="89.736991"
+ inkscape:cy="131.8906"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:window-height="738"
+ inkscape:window-width="1280"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:zoom="1.9683098"
+ objecttolerance="10.0"
+ pagecolor="#ffffff"
+ showgrid="false"
+ inkscape:window-maximized="1" />
+ <rect
+ y="0.79069471"
+ x="0.69856781"
+ width="247.80269"
+ style="fill:#ffffff"
+ ry="24.249325"
+ id="background"
+ height="242.49326" />
+ <g
+ id="g3786"
+ transform="translate(1.8429833,2.6771937)">
+ <rect
+ height="19.39946"
+ id="minus"
+ style="fill:#c00000"
+ width="57.91848"
+ x="21.129864"
+ y="72.660362" />
+ <use
+ height="26"
+ id="use8"
+ transform="translate(77.224633,-7.7244905e-7)"
+ width="71"
+ x="0"
+ xlink:href="#minus"
+ y="0" />
+ <use
+ height="26"
+ id="use10"
+ transform="translate(154.44928,-7.7244905e-7)"
+ width="71"
+ x="0"
+ xlink:href="#minus"
+ y="0" />
+ <path
+ d="m 40.436017,121.15902 0,19.39946 -19.30616,0 0,19.39946 19.30616,0 0,19.39946 19.30617,0 0,-19.39946 19.30616,0 0,-19.39946 -19.30616,0 0,-19.39946 -19.30617,0 z"
+ id="plus"
+ style="fill:#008000"
+ inkscape:connector-curvature="0" />
+ <use
+ height="26"
+ id="use13"
+ transform="translate(77.224633,-7.7244905e-7)"
+ width="71"
+ x="0"
+ xlink:href="#plus"
+ y="0" />
+ <use
+ height="26"
+ id="use15"
+ transform="translate(154.44928,-7.7244905e-7)"
+ width="71"
+ x="0"
+ xlink:href="#plus"
+ y="0" />
+ </g>
+ <path
+ style="fill:#60605d"
+ d="m 29.516103,7.4516989 c -13.434128,0 -24.2500023,10.8158741 -24.2500023,24.2500001 l 0,193.968751 c 0,13.43413 10.8158743,24.25 24.2500023,24.25 l 199.281247,0 c 13.43413,0 24.25,-10.81587 24.25,-24.25 l 0,-193.968751 c 0,-13.434126 -10.81587,-24.2500001 -24.25,-24.2500001 l -199.281247,0 z m 1.6875,1.21875 193.968747,0 c 13.93155,0 25.15625,11.2247041 25.15625,25.1562501 l 0,181.750001 c 0,13.93155 -11.2247,25.15625 -25.15625,25.15625 l -193.968747,0 c -13.931548,0 -25.1562523,-11.2247 -25.1562523,-25.15625 l 0,-181.750001 c 0,-13.931546 11.2247043,-25.1562501 25.1562523,-25.1562501 z"
+ id="shadow"
+ inkscape:connector-curvature="0" />
+</svg>
diff --git a/icons/scalable/status/thg-subrepo.svg b/icons/scalable/status/thg-subrepo.svg
new file mode 100644
--- /dev/null
+++ b/icons/scalable/status/thg-subrepo.svg
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="256"
+ id="svg2"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:version="0.48.0 r9654"
+ sodipodi:docname="thg-subrepo.svg"
+ sodipodi:version="0.32"
+ version="1.0"
+ width="256">
+ <metadata
+ id="metadata3">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:title></dc:title>
+ <dc:description />
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>unsorted</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:publisher>
+ <cc:Agent
+ rdf:about="http://www.openclipart.org/">
+ <dc:title>Open Clip Art Library, Source: Wiki Commons, Source: Wikimedia Commons</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:rights>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:rights>
+ <dc:date />
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <cc:license
+ rdf:resource="GPL" />
+ <dc:language>en</dc:language>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs22">
+ <inkscape:perspective
+ id="perspective26"
+ inkscape:persp3d-origin="35.5 : 8.6666667 : 1"
+ inkscape:vp_x="0 : 13 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="71 : 13 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6551"
+ id="linearGradient6557"
+ x1="55.080357"
+ y1="110.15236"
+ x2="73.14286"
+ y2="110.15236"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.00344154,1.2102096,-1.6263159,0.18275943,243.22716,8.6686994)" />
+ <linearGradient
+ id="linearGradient6551">
+ <stop
+ style="stop-color:#f2f53a;stop-opacity:1;"
+ offset="0"
+ id="stop6553" />
+ <stop
+ style="stop-color:#fdff8e;stop-opacity:0;"
+ offset="1"
+ id="stop6555" />
+ </linearGradient>
+ <linearGradient
+ y2="110.15236"
+ x2="73.14286"
+ y1="110.15236"
+ x1="55.080357"
+ gradientTransform="matrix(0.00344154,1.2102096,-1.6263159,0.18275943,309.0051,57.366183)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3022"
+ xlink:href="#linearGradient6551"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6551"
+ id="linearGradient3848"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.00344154,1.2102096,-1.6263159,0.18275943,309.0051,57.366183)"
+ x1="55.080357"
+ y1="110.15236"
+ x2="73.14286"
+ y2="110.15236" />
+ </defs>
+ <sodipodi:namedview
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10.0"
+ guidetolerance="10.0"
+ id="base"
+ inkscape:current-layer="svg2"
+ inkscape:cx="89.736991"
+ inkscape:cy="122.43398"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:window-height="738"
+ inkscape:window-width="1280"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:zoom="1.9683098"
+ objecttolerance="10.0"
+ pagecolor="#ffffff"
+ showgrid="false"
+ inkscape:window-maximized="1" />
+ <path
+ style="color:#000000;fill:#fff08b;fill-opacity:1;fill-rule:nonzero;stroke:#c4a000;stroke-width:6.1813693;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 125.93864,98.872518 c -0.009,-0.685743 -0.68406,-1.277866 -1.42388,-1.248212 l -15.76003,0.630734 -56.285668,2.25282 -45.5914241,1.82489 c -1.0459723,0.0424 -1.9589962,0.93548 -1.9465597,1.90518 l 1.7798561,138.8014 c 0.012437,0.96977 0.947448,1.78948 1.9934245,1.74752 L 110.58138,240.70913 c 1.046,-0.0402 1.95917,-0.93553 1.94667,-1.90515 l -0.98024,-76.44525 13.78995,-0.55375 c 0.74031,-0.0302 1.39924,-0.67454 1.39041,-1.3607 l -0.78971,-61.573643 z"
+ id="rect2995"
+ inkscape:connector-curvature="0" />
+ <path
+ style="color:#000000;fill:#fff08b;fill-opacity:1;fill-rule:nonzero;stroke:#c4a000;stroke-width:6.90631437;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 126.53106,174.8151 c -0.002,-0.73164 -0.68305,-1.31092 -1.58265,-1.35089 l -18.6286,-0.81954 -0.18942,-62.78471 c -0.002,-0.674 -0.75201,-1.31432 -1.58251,-1.35078 L 7.3000652,104.2305 c -0.8291401,-0.0366 -1.5767724,0.53831 -1.5747635,1.21186 l 0.4190185,138.89489 c 0.00201,0.67395 0.7526549,1.31425 1.5825125,1.35078 l 70.7257353,3.11177 c 0.209509,0.54277 0.538841,1.0484 1.265881,1.08068 l 45.466451,2.00049 c 0.89981,0.0402 1.57713,-0.48056 1.5749,-1.21195 l -0.22887,-75.85389 z"
+ id="rect3043"
+ inkscape:connector-curvature="0" />
+ <text
+ xml:space="preserve"
+ style="font-size:142.12782288px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000080;fill-opacity:1;stroke:none;font-family:Arial;-inkscape-font-specification:Arial Bold"
+ x="12.382761"
+ y="221.77342"
+ id="text3821"
+ sodipodi:linespacing="125%"
+ transform="scale(0.9640397,1.0373017)"><tspan
+ sodipodi:role="line"
+ id="tspan3823"
+ x="12.382761"
+ y="221.77342">S</tspan></text>
+</svg>
diff --git a/icons/scalable/status/thg-svn-subrepo.svg b/icons/scalable/status/thg-svn-subrepo.svg
new file mode 100644
--- /dev/null
+++ b/icons/scalable/status/thg-svn-subrepo.svg
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="256"
+ id="svg2"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:version="0.48.0 r9654"
+ sodipodi:docname="thg-svn-subrepo.svg"
+ sodipodi:version="0.32"
+ version="1.0"
+ width="256">
+ <metadata
+ id="metadata3">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:title></dc:title>
+ <dc:description />
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>unsorted</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ <dc:publisher>
+ <cc:Agent
+ rdf:about="http://www.openclipart.org/">
+ <dc:title>Open Clip Art Library, Source: Wiki Commons, Source: Wikimedia Commons</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:creator>
+ <dc:rights>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:rights>
+ <dc:date />
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <cc:license
+ rdf:resource="GPL" />
+ <dc:language>en</dc:language>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs22">
+ <inkscape:perspective
+ id="perspective26"
+ inkscape:persp3d-origin="35.5 : 8.6666667 : 1"
+ inkscape:vp_x="0 : 13 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="71 : 13 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6551"
+ id="linearGradient6557"
+ x1="55.080357"
+ y1="110.15236"
+ x2="73.14286"
+ y2="110.15236"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.00344154,1.2102096,-1.6263159,0.18275943,243.22716,8.6686994)" />
+ <linearGradient
+ id="linearGradient6551">
+ <stop
+ style="stop-color:#f2f53a;stop-opacity:1;"
+ offset="0"
+ id="stop6553" />
+ <stop
+ style="stop-color:#fdff8e;stop-opacity:0;"
+ offset="1"
+ id="stop6555" />
+ </linearGradient>
+ <linearGradient
+ y2="110.15236"
+ x2="73.14286"
+ y1="110.15236"
+ x1="55.080357"
+ gradientTransform="matrix(0.00344154,1.2102096,-1.6263159,0.18275943,309.0051,57.366183)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3022"
+ xlink:href="#linearGradient6551"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient6551"
+ id="linearGradient3848"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.00344154,1.2102096,-1.6263159,0.18275943,309.0051,57.366183)"
+ x1="55.080357"
+ y1="110.15236"
+ x2="73.14286"
+ y2="110.15236" />
+ </defs>
+ <sodipodi:namedview
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10.0"
+ guidetolerance="10.0"
+ id="base"
+ inkscape:current-layer="svg2"
+ inkscape:cx="51.56764"
+ inkscape:cy="94.638993"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:window-height="738"
+ inkscape:window-width="1280"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:zoom="1.9683098"
+ objecttolerance="10.0"
+ pagecolor="#ffffff"
+ showgrid="false"
+ inkscape:window-maximized="1" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 0.32992046,0.20734072 0,92.68331928 C 34.848621,73.004547 80.970856,53.019612 139.01298,32.852882 176.20444,19.950325 212.14896,9.1011362 246.86753,0.20734072 l -246.53760954,0 z M 255.72733,19.969777 C 222.06985,26.89033 191.88559,35.034216 165.32117,44.235044 134.90992,54.803095 110.42768,65.487058 91.911358,76.380272 73.371352,87.078403 64.758735,95.730648 65.964787,102.39664 c 1.087803,5.88563 8.852263,8.55783 23.324794,8.00504 7.449121,-0.19508 19.510179,-1.32856 36.252869,-3.37713 16.74277,-2.04857 38.35919,-5.01103 64.82123,-8.880584 26.22939,-3.746717 47.95432,-6.280751 65.36365,-7.754879 l 0,-70.41931 z m -74.7659,117.573983 c -7.44906,0.13009 -17.70389,0.91822 -30.82849,2.25141 -13.17188,1.36574 -29.467,3.33242 -49.00015,6.12886 -30.316639,4.48734 -55.549738,7.98026 -75.579547,10.25645 -9.608021,1.12175 -17.9552499,1.81915 -25.22332254,2.3765 l 0,75.17229 C 40.111127,225.68406 76.097953,216.09183 108.18447,204.96118 c 31.52268,-10.92571 55.75044,-21.58714 72.77696,-31.89507 17.05017,-10.30789 25.01072,-19.05271 23.68642,-26.14145 -1.11149,-6.11321 -9.09564,-9.21832 -23.68642,-9.3809 z m 74.7659,26.39161 C 220.77006,182.88145 177.38199,201.46286 125.54245,219.4703 77.278383,236.21287 35.587684,248.19222 0.32992046,255.61804 l 0,0.62541 255.39740954,0 0,-92.30808 z M 10.997854,179.69528 c 0.130246,-0.0264 0.229985,-0.002 0.361618,0 0.660236,0.0308 1.364189,0.31696 1.808131,1.00063 0.678024,0.96569 0.854069,2.51386 0.452029,3.75236 -0.43723,1.42533 -1.597602,2.28493 -2.712189,2.00126 -1.2303394,-0.24712 -2.1842943,-1.92033 -2.0793372,-3.62728 0.035631,-1.60701 1.0215998,-2.92796 2.1697482,-3.12697 z m 9.040613,0 c 0.57655,0.032 1.112825,0.19372 1.536897,0.75047 0.801103,0.9107 1.116882,2.54845 0.723249,3.87744 -0.36853,1.36558 -1.378333,2.38006 -2.440955,2.25141 -0.912693,-0.0517 -1.810533,-0.83856 -2.169749,-2.00124 -0.496734,-1.51128 -0.09208,-3.55529 0.99447,-4.37776 0.405095,-0.34314 0.879931,-0.50696 1.356088,-0.50032 z m -8.678995,22.13892 c 1.077061,-0.0478 2.039357,1.00128 2.350558,2.3765 0.329631,1.52957 -0.194781,3.45414 -1.265677,4.1276 -1.075686,0.74675 -2.4885027,0.27342 -3.1642179,-1.12571 -0.687779,-1.36614 -0.5927238,-3.42703 0.361618,-4.50283 0.4677099,-0.57764 1.0894719,-0.89387 1.7177189,-0.87556 z m 8.678995,0 c 0.856618,-0.0648 1.61794,0.68525 2.079337,1.62604 0.664733,1.43462 0.386626,3.50364 -0.632838,4.50283 -1.022614,1.07599 -2.621151,0.89559 -3.435439,-0.50031 -0.841778,-1.38689 -0.786224,-3.74845 0.27122,-4.87808 0.458862,-0.52449 1.118697,-0.77677 1.71772,-0.75048 z"
+ id="polygon3517"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;letter-spacing:normal;word-spacing:normal;text-anchor:start;fill:#809cc8;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+</svg>
diff --git a/tortoisehg/hgqt/reporegistry.py b/tortoisehg/hgqt/reporegistry.py
--- a/tortoisehg/hgqt/reporegistry.py
+++ b/tortoisehg/hgqt/reporegistry.py
@@ -16,6 +16,9 @@
from PyQt4.QtCore import *
from PyQt4.QtGui import *
+import qtlib
+
+
def settingsfilename():
"""Return path to thg-reporegistry.xml as unicode"""
s = QSettings()
@@ -140,7 +143,15 @@
def mouseDoubleClickEvent(self, event):
if self.selitem and self.selitem.internalPointer().isRepo():
- self.showFirstTabOrOpen()
+ # We can only open mercurial repositories and subrepositories
+ repotype = self.selitem.internalPointer().repotype()
+ if repotype == 'hg':
+ self.showFirstTabOrOpen()
+ else:
+ qtlib.WarningMsgBox(
+ _('Unsupported repository type (%s)') % repotype,
+ _('Cannot open non mercurial repositories or subrepositories'),
+ parent=self)
else:
# a double-click on non-repo rows opens an editor
super(RepoTreeView, self).mouseDoubleClickEvent(event)
@@ -324,7 +335,14 @@
def open(self):
'open context menu action, open repowidget unconditionally'
root = self.selitem.internalPointer().rootpath()
- self.openRepo.emit(hglib.tounicode(root), False)
+ repotype = self.selitem.internalPointer().repotype()
+ if repotype == 'hg':
+ self.openRepo.emit(hglib.tounicode(root), False)
+ else:
+ qtlib.WarningMsgBox(
+ _('Unsupported repository type (%s)') % repotype,
+ _('Cannot open non mercurial repositories or subrepositories'),
+ parent=self)
def startRename(self):
self.tview.edit(self.selitem)
diff --git a/tortoisehg/hgqt/repotreeitem.py b/tortoisehg/hgqt/repotreeitem.py
--- a/tortoisehg/hgqt/repotreeitem.py
+++ b/tortoisehg/hgqt/repotreeitem.py
@@ -8,7 +8,7 @@
import sys, os
from mercurial import node
-from mercurial import ui, hg
+from mercurial import ui, hg, util, error
from tortoisehg.util import hglib
from tortoisehg.hgqt.i18n import _
@@ -23,6 +23,7 @@
'allgroup': 'AllRepoGroupItem',
'group': 'RepoGroupItem',
'repo': 'RepoItem',
+ 'subrepo': 'SubrepoItem',
'treeitem': 'RepoTreeItem',
}
@@ -142,6 +143,7 @@
self._root = root or ''
self._shortname = u''
self._basenode = node.nullid
+ self._repotype = 'hg'
def isRepo(self):
return True
@@ -155,6 +157,9 @@
else:
return hglib.tounicode(os.path.basename(self._root))
+ def repotype(self):
+ return self._repotype
+
def basenode(self):
"""Return node id of revision 0"""
return self._basenode
@@ -199,17 +204,20 @@
self._basenode = node.bin(str(a.value('', 'basenode').toString()))
RepoTreeItem.undump(self, xr)
- def addSubrepos(ri):
- repo = hg.repository(ui.ui(), ri.rootpath())
- for subpath in repo['.'].substate:
+ def addSubrepos(ri, repo):
+ wctx = repo['.']
+ for subpath in wctx.substate:
# For now we only support showing mercurial subrepos
- if repo['.'].substate[subpath][2] == 'hg':
- sctx = repo['.'].sub(subpath)
- ri.appendChild(RepoItem(self.model, sctx._repo.root))
+ subtype = wctx.substate[subpath][2]
+ sctx = wctx.sub(subpath)
+ ri.appendChild(
+ SubrepoItem(self.model, sctx._repo.root, subtype=subtype))
+ if subtype == 'hg':
+ # Only recurse into mercurial subrepos
if ri.childCount():
- addSubrepos(ri.child(ri.childCount()-1))
+ addSubrepos(ri.child(ri.childCount()-1), sctx._repo)
- addSubrepos(self)
+ addSubrepos(self, hg.repository(ui.ui(), self.rootpath()))
def details(self):
return _('Local Repository %s') % hglib.tounicode(self._root)
@@ -220,6 +228,61 @@
return None
+def _overlaidicon(base, overlay):
+ """Generate overlaid icon"""
+ # TODO: This was copied from manifestmodel.py
+ # TODO: generalize this function as a utility
+ pixmap = base.pixmap(16, 16)
+ painter = QPainter(pixmap)
+ painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
+ painter.drawPixmap(0, 0, overlay.pixmap(16, 16))
+ del painter
+ return QIcon(pixmap)
+
+
+class SubrepoItem(RepoItem):
+ _subrepoType2IcoMap = {
+ 'hg': 'hg',
+ 'git': 'thg-git-subrepo',
+ 'svn': 'thg-svn-subrepo',
+ }
+
+ def __init__(self, model, repo=None, parent=None, parentrepo=None,
+ subtype='hg'):
+ RepoItem.__init__(self, model, repo, parent)
+ self._parentrepo = parentrepo
+ self._repotype = subtype
+ if self._repotype != 'hg':
+ # Make sure that we cannot drag non hg subrepos
+ # To do so we disable the dumpObject method for non hg subrepos
+ def doNothing(dummy):
+ pass
+ self.dumpObject = doNothing
+
+ # Limit the context menu to those actions that are valid for non
+ # mercurial subrepos
+ def nonHgMenulist():
+ return ['remove', None, 'explore', 'terminal']
+ self.menulist = nonHgMenulist
+
+ def data(self, column, role):
+ if role == Qt.DecorationRole:
+ if column == 0:
+ subiconame = SubrepoItem._subrepoType2IcoMap.get(self._repotype, None)
+ if subiconame is None:
+ # Unknown (or generic) subrepo type
+ ico = qtlib.geticon('thg-subrepo')
+ else:
+ # Overlay the "subrepo icon" on top of the selected subrepo
+ # type icon
+ ico = qtlib.geticon(subiconame)
+ ico = _overlaidicon(ico, qtlib.geticon('thg-subrepo'))
+ return QVariant(ico)
+ return QVariant()
+ else:
+ return super(SubrepoItem, self).data(column, role)
+
+
class RepoGroupItem(RepoTreeItem):
def __init__(self, model, name=None, parent=None):
RepoTreeItem.__init__(self, model, parent)
diff --git a/tortoisehg/hgqt/repotreemodel.py b/tortoisehg/hgqt/repotreemodel.py
--- a/tortoisehg/hgqt/repotreemodel.py
+++ b/tortoisehg/hgqt/repotreemodel.py
@@ -10,7 +10,7 @@
from tortoisehg.hgqt import thgrepo
from repotreeitem import undumpObject, AllRepoGroupItem, RepoGroupItem
-from repotreeitem import RepoItem, RepoTreeItem
+from repotreeitem import RepoItem, SubrepoItem, RepoTreeItem
from PyQt4.QtCore import *
from PyQt4.QtGui import *
@@ -188,6 +188,8 @@
parent = QModelIndex()
d = str(data.data(repoRegGroupMimeType))
itemread = readXml(d, extractXmlElementName, self)
+ if itemread is None:
+ return False
if group is None:
return False
if row < 0:
@@ -224,13 +226,18 @@
self.beginInsertRows(grp, row, row)
rgi.insertChild(row, RepoItem(self, root))
def addSubrepos(ri, repo):
- for subpath in repo['.'].substate:
+ wctx = repo['.']
+ for subpath in wctx.substate:
# For now we only support showing mercurial subrepos
- if repo['.'].substate[subpath][2] == 'hg':
- sctx = repo['.'].sub(subpath)
- ri.insertChild(row,
- RepoItem(self, sctx._repo.root))
- addSubrepos(ri.child(ri.childCount()-1), sctx._repo)
+ subtype = wctx.substate[subpath][2]
+ sctx = wctx.sub(subpath)
+ ri.insertChild(row,
+ SubrepoItem(self, sctx._repo.root, subtype=subtype))
+ if subtype == 'hg':
+ # Only recurse into mercurial subrepos
+ if ri.childCount():
+ addSubrepos(ri.child(ri.childCount()-1), sctx._repo)
+
from mercurial import ui, hg
repo = hg.repository(ui.ui(), root)
addSubrepos(rgi.child(rgi.childCount()-1), repo)
diff --git a/tortoisehg/hgqt/repotreemodel.py b/tortoisehg/hgqt/repotreemodel.py
--- a/tortoisehg/hgqt/repotreemodel.py
+++ b/tortoisehg/hgqt/repotreemodel.py
@@ -7,6 +7,7 @@
from tortoisehg.util import hglib
from tortoisehg.hgqt.i18n import _
+from tortoisehg.hgqt import thgrepo
from repotreeitem import undumpObject, AllRepoGroupItem, RepoGroupItem
from repotreeitem import RepoItem, RepoTreeItem
@@ -222,6 +223,17 @@
row = rgi.childCount()
self.beginInsertRows(grp, row, row)
rgi.insertChild(row, RepoItem(self, root))
+ def addSubrepos(ri, repo):
+ for subpath in repo['.'].substate:
+ # For now we only support showing mercurial subrepos
+ if repo['.'].substate[subpath][2] == 'hg':
+ sctx = repo['.'].sub(subpath)
+ ri.insertChild(row,
+ RepoItem(self, sctx._repo.root))
+ addSubrepos(ri.child(ri.childCount()-1), sctx._repo)
+ from mercurial import ui, hg
+ repo = hg.repository(ui.ui(), root)
It's a restricted HTML subset. Try <br>
--
Steve Borho
Thank you. That makes sense. I'll resend the series with that issue
fixed, assuming that you have no other suggestions for improvement.
Angel
diff --git a/tortoisehg/hgqt/repotreeitem.py b/tortoisehg/hgqt/repotreeitem.py
--- a/tortoisehg/hgqt/repotreeitem.py
+++ b/tortoisehg/hgqt/repotreeitem.py
@@ -8,10 +8,12 @@
import sys, os
from mercurial import node
+from mercurial import ui, hg
from tortoisehg.util import hglib
from tortoisehg.hgqt.i18n import _
from tortoisehg.hgqt import qtlib
+from tortoisehg.hgqt import thgrepo
from PyQt4.QtCore import *
from PyQt4.QtGui import *
@@ -189,7 +191,6 @@
xw.writeAttribute('root', hglib.tounicode(self._root))
xw.writeAttribute('shortname', self.shortname())
xw.writeAttribute('basenode', node.hex(self.basenode()))
- RepoTreeItem.dump(self, xw)
def undump(self, xr):
a = xr.attributes()
@@ -198,6 +199,18 @@
self._basenode = node.bin(str(a.value('', 'basenode').toString()))
RepoTreeItem.undump(self, xr)
+ def addSubrepos(ri):
+ repo = hg.repository(ui.ui(), ri.rootpath())
+ for subpath in repo['.'].substate:
+ # For now we only support showing mercurial subrepos
+ if repo['.'].substate[subpath][2] == 'hg':
+ sctx = repo['.'].sub(subpath)
+ ri.appendChild(RepoItem(self.model, sctx._repo.root))
+ if ri.childCount():
+ addSubrepos(ri.child(ri.childCount()-1))
+
+ addSubrepos(self)
+
diff --git a/tortoisehg/hgqt/repotreemodel.py b/tortoisehg/hgqt/repotreemodel.py
--- a/tortoisehg/hgqt/repotreemodel.py
+++ b/tortoisehg/hgqt/repotreemodel.py
@@ -7,6 +7,7 @@
from tortoisehg.util import hglib
from tortoisehg.hgqt.i18n import _
+from tortoisehg.hgqt import thgrepo
from repotreeitem import undumpObject, AllRepoGroupItem, RepoGroupItem
from repotreeitem import RepoItem, RepoTreeItem
@@ -222,6 +223,17 @@
row = rgi.childCount()
self.beginInsertRows(grp, row, row)
rgi.insertChild(row, RepoItem(self, root))
+ def addSubrepos(ri, repo):
+ for subpath in repo['.'].substate:
+ # For now we only support showing mercurial subrepos
+ if repo['.'].substate[subpath][2] == 'hg':
+ sctx = repo['.'].sub(subpath)
from PyQt4.QtCore import *
from PyQt4.QtGui import *
diff --git a/tortoisehg/hgqt/repotreeitem.py b/tortoisehg/hgqt/repotreeitem.py
--- a/tortoisehg/hgqt/repotreeitem.py
+++ b/tortoisehg/hgqt/repotreeitem.py
@@ -8,7 +8,7 @@
import sys, os
from mercurial import node
-from mercurial import ui, hg
+from mercurial import ui, hg, util, error
from tortoisehg.util import hglib
from tortoisehg.hgqt.i18n import _
@@ -23,6 +23,7 @@
'allgroup': 'AllRepoGroupItem',
'group': 'RepoGroupItem',
'repo': 'RepoItem',
+ 'subrepo': 'SubrepoItem',
'treeitem': 'RepoTreeItem',
}
@@ -142,6 +143,7 @@
self._root = root or ''
self._shortname = u''
self._basenode = node.nullid
+ self._repotype = 'hg'
def isRepo(self):
return True
@@ -155,6 +157,9 @@
else:
return hglib.tounicode(os.path.basename(self._root))
+ def repotype(self):
+ return self._repotype
+
def basenode(self):
"""Return node id of revision 0"""
return self._basenode
@@ -199,17 +204,20 @@
self._basenode = node.bin(str(a.value('', 'basenode').toString()))
RepoTreeItem.undump(self, xr)
- def addSubrepos(ri):
- repo = hg.repository(ui.ui(), ri.rootpath())
- for subpath in repo['.'].substate:
+ def addSubrepos(ri, repo):
+ wctx = repo['.']
+ for subpath in wctx.substate:
# For now we only support showing mercurial subrepos
- if repo['.'].substate[subpath][2] == 'hg':
- sctx = repo['.'].sub(subpath)
- ri.appendChild(RepoItem(self.model, sctx._repo.root))
+ subtype = wctx.substate[subpath][2]
+ sctx = wctx.sub(subpath)
+ ri.appendChild(
+ SubrepoItem(self.model, sctx._repo.root, subtype=subtype))
+ if subtype == 'hg':
+ # Only recurse into mercurial subrepos
if ri.childCount():
- addSubrepos(ri.child(ri.childCount()-1))
+ addSubrepos(ri.child(ri.childCount()-1), sctx._repo)
- addSubrepos(self)
+ addSubrepos(self, hg.repository(ui.ui(), self.rootpath()))
def details(self):
return _('Local Repository %s') % hglib.tounicode(self._root)
diff --git a/tortoisehg/hgqt/repotreemodel.py b/tortoisehg/hgqt/repotreemodel.py
--- a/tortoisehg/hgqt/repotreemodel.py
+++ b/tortoisehg/hgqt/repotreemodel.py
@@ -10,7 +10,7 @@
from tortoisehg.hgqt import thgrepo
from repotreeitem import undumpObject, AllRepoGroupItem, RepoGroupItem
-from repotreeitem import RepoItem, RepoTreeItem
+from repotreeitem import RepoItem, SubrepoItem, RepoTreeItem
from PyQt4.QtCore import *
from PyQt4.QtGui import *
@@ -188,6 +188,8 @@
parent = QModelIndex()
d = str(data.data(repoRegGroupMimeType))
itemread = readXml(d, extractXmlElementName, self)
+ if itemread is None:
+ return False
if group is None:
return False
if row < 0:
@@ -224,13 +226,18 @@
self.beginInsertRows(grp, row, row)
rgi.insertChild(row, RepoItem(self, root))
def addSubrepos(ri, repo):
- for subpath in repo['.'].substate:
+ wctx = repo['.']
+ for subpath in wctx.substate:
# For now we only support showing mercurial subrepos
- if repo['.'].substate[subpath][2] == 'hg':
- sctx = repo['.'].sub(subpath)
- ri.insertChild(row,
- RepoItem(self, sctx._repo.root))
- addSubrepos(ri.child(ri.childCount()-1), sctx._repo)
+ subtype = wctx.substate[subpath][2]
+ sctx = wctx.sub(subpath)
+ ri.insertChild(row,
+ SubrepoItem(self, sctx._repo.root, subtype=subtype))
+ if subtype == 'hg':
+ # Only recurse into mercurial subrepos
+ if ri.childCount():
+ addSubrepos(ri.child(ri.childCount()-1), sctx._repo)
+
from mercurial import ui, hg
diff --git a/tortoisehg/hgqt/repotreeitem.py b/tortoisehg/hgqt/repotreeitem.py
--- a/tortoisehg/hgqt/repotreeitem.py
+++ b/tortoisehg/hgqt/repotreeitem.py
@@ -205,19 +205,44 @@
RepoTreeItem.undump(self, xr)
def addSubrepos(ri, repo):
- wctx = repo['.']
- for subpath in wctx.substate:
- # For now we only support showing mercurial subrepos
- subtype = wctx.substate[subpath][2]
- sctx = wctx.sub(subpath)
- ri.appendChild(
- SubrepoItem(self.model, sctx._repo.root, subtype=subtype))
- if subtype == 'hg':
- # Only recurse into mercurial subrepos
- if ri.childCount():
- addSubrepos(ri.child(ri.childCount()-1), sctx._repo)
+ invalidRepoList = []
+ try:
+ wctx = repo['.']
+ for subpath in wctx.substate:
+ # For now we only support showing mercurial subrepos
+ subtype = wctx.substate[subpath][2]
+ sctx = wctx.sub(subpath)
+ ri.appendChild(
+ SubrepoItem(self.model, sctx._repo.root, subtype=subtype))
+ if subtype == 'hg':
+ # Only recurse into mercurial subrepos
+ if ri.childCount():
+ invalidRepoList += \
+ addSubrepos(
+ ri.child(ri.childCount()-1), sctx._repo)
+ except (EnvironmentError, error.RepoError, util.Abort), e:
+ # Add the repo to the list of repos/subrepos
+ # that could not be open
+ invalidRepoList.append(repo.root)
+
+ return invalidRepoList
- addSubrepos(self, hg.repository(ui.ui(), self.rootpath()))
+ root = self.rootpath()
+ invalidRepoList = \
+ addSubrepos(self, hg.repository(ui.ui(), root))
+
+ if invalidRepoList:
+ if invalidRepoList[0] == root:
+ qtlib.WarningMsgBox(_('Could not get subrepository list'),
+ _('It was not possible to get the subrepository list for '
+ 'the repository in:<br><br><i>%s</i>') % root)
+ else:
+ qtlib.WarningMsgBox(_('Could not open some subrepositories'),
+ _('It was not possible to fully load the subrepository list '
+ 'for the repository in:<br><br><i>%s</i><br><br>'
+ 'The following subrepositories could not be accessed:'
+ '<br><br><i>%s</i>') %
+ (root, "<br>".join(invalidRepoList)))
def details(self):
return _('Local Repository %s') % hglib.tounicode(self._root)
diff --git a/tortoisehg/hgqt/repotreemodel.py b/tortoisehg/hgqt/repotreemodel.py
--- a/tortoisehg/hgqt/repotreemodel.py
+++ b/tortoisehg/hgqt/repotreemodel.py
@@ -5,8 +5,11 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+from mercurial import ui, hg, util, error
+
from tortoisehg.util import hglib
from tortoisehg.hgqt.i18n import _
+from tortoisehg.hgqt import qtlib
from tortoisehg.hgqt import thgrepo
from repotreeitem import undumpObject, AllRepoGroupItem, RepoGroupItem
@@ -226,22 +229,45 @@
self.beginInsertRows(grp, row, row)
rgi.insertChild(row, RepoItem(self, root))
def addSubrepos(ri, repo):
- wctx = repo['.']
- for subpath in wctx.substate:
- # For now we only support showing mercurial subrepos
- subtype = wctx.substate[subpath][2]
- sctx = wctx.sub(subpath)
- ri.insertChild(row,
- SubrepoItem(self, sctx._repo.root, subtype=subtype))
- if subtype == 'hg':
- # Only recurse into mercurial subrepos
- if ri.childCount():
- addSubrepos(ri.child(ri.childCount()-1), sctx._repo)
+ invalidRepoList = []
+ try:
+ wctx = repo['.']
+ for subpath in wctx.substate:
+ # For now we only support showing mercurial subrepos
+ subtype = wctx.substate[subpath][2]
+ sctx = wctx.sub(subpath)
+ ri.insertChild(row,
+ SubrepoItem(self, sctx._repo.root, subtype=subtype))
+ if subtype == 'hg':
+ # Only recurse into mercurial subrepos
+ if ri.childCount():
+ invalidRepoList += \
+ addSubrepos(
+ ri.child(ri.childCount()-1), sctx._repo)
+ except (EnvironmentError, error.RepoError, util.Abort), e:
+ # Add the repo to the list of repos/subrepos
+ # that could not be open
+ invalidRepoList.append(repo.root)
- from mercurial import ui, hg
+ return invalidRepoList
+
repo = hg.repository(ui.ui(), root)
- addSubrepos(rgi.child(rgi.childCount()-1), repo)
+ invalidRepoList = \
+ addSubrepos(rgi.child(rgi.childCount()-1), repo)
self.endInsertRows()
+
+ if invalidRepoList:
+ if invalidRepoList[0] == root:
+ qtlib.WarningMsgBox(_('Could not get subrepository list'),
+ _('It was not possible to get the subrepository list for '
+ 'the repository in:<br><br><i>%s</i>') % root)
+ else:
+ qtlib.WarningMsgBox(_('Could not open some subrepositories'),
+ _('It was not possible to fully load the subrepository list '
+ 'for the repository in:<br><br><i>%s</i><br><br>'
+ 'The following subrepositories could not be accessed:'
+ '<br><br><i>%s</i>') %
+ (root, "<br>".join(invalidRepoList)))
I'm ready to apply these, but I don't seem to be getting patch 1 of 4
in the series. It would likely be easier if you attached these as a
single bundle, or pushed them to a repo I can pull from.
--
Steve Borho
I updated to tip, and got this traceback on non-existing repos in the
reporegistry when restarting the workbench afterwards. Problem is not so
much the repo not existing, but me not being able anymore to load the
workbench. Maybe we should simply exclude that non-existing repo from
the reporegistry from now on, or mark it in some way visually, and/or
internally (so the error has to be reported only once) ?
{{{
#!python
** Mercurial version (1.8+2-da192c62f89e). TortoiseHg version
(2.0.4+13-92356e6a4b12)
** Command: workbench
** CWD: M:\DEV\thg-qt
** Extensions loaded: patchbomb, graphlog, mq, pbranch, rebase
** Python version: 2.6.5 (r265:79096, Mar 19 2010, 21:48:26) [MSC v.1500
32 bit (Intel)]
** Windows version: (6, 1, 7601, 2, 'Service Pack 1')
** Processor architecture: x86
** Qt-4.6.2 PyQt-4.7.3
Traceback (most recent call last):
File "M:\DEV\thg-qt\tortoisehg\hgqt\run.py", line 485, in __call__
dlg = dlgfunc(ui, *args, **opts)
File "M:\DEV\thg-qt\tortoisehg\hgqt\workbench.py", line 828, in run
w = Workbench()
File "M:\DEV\thg-qt\tortoisehg\hgqt\workbench.py", line 46, in __init__
self.reporegistry = rr = RepoRegistryView(self)
File "M:\DEV\thg-qt\tortoisehg\hgqt\reporegistry.py", line 198, in
__init__
tv.setModel(repotreemodel.RepoTreeModel(settingsfilename(), self))
File "M:\DEV\thg-qt\tortoisehg\hgqt\repotreemodel.py", line 76, in
__init__
root = readXml(f, reporegistryXmlElementName, self)
File "M:\DEV\thg-qt\tortoisehg\hgqt\repotreemodel.py", line 52, in readXml
itemread = undumpObject(xr, model)
File "M:\DEV\thg-qt\tortoisehg\hgqt\repotreeitem.py", line 45, in
undumpObject
obj.undump(xr)
File "M:\DEV\thg-qt\tortoisehg\hgqt\repotreeitem.py", line 113, in undump
item = undumpObject(xr, self.model)
File "M:\DEV\thg-qt\tortoisehg\hgqt\repotreeitem.py", line 45, in
undumpObject
obj.undump(xr)
File "M:\DEV\thg-qt\tortoisehg\hgqt\repotreeitem.py", line 372, in undump
RepoTreeItem.undump(self, xr)
File "M:\DEV\thg-qt\tortoisehg\hgqt\repotreeitem.py", line 113, in undump
item = undumpObject(xr, self.model)
File "M:\DEV\thg-qt\tortoisehg\hgqt\repotreeitem.py", line 45, in
undumpObject
obj.undump(xr)
File "M:\DEV\thg-qt\tortoisehg\hgqt\repotreeitem.py", line 232, in undump
addSubrepos(self, hg.repository(ui.ui(), root))
File "M:\DEV\hg-default\mercurial\hg.py", line 93, in repository
repo = _lookup(path).instance(ui, path, create)
File "M:\DEV\hg-default\mercurial\localrepo.py", line 1950, in instance
return localrepository(ui, util.localpath(path), create)
File "M:\DEV\hg-default\mercurial\localrepo.py", line 66, in __init__
raise error.RepoError(_("repository %s not found") % path)
RepoError: repository C:\DEV\TEST\ren-clone3 not found
}}}
--
Johan
Johan,
The problem happens because I am blindly trying to create a repo
object outside of the try/catch that is supposed to protect against
the corresponding errors. I will fix this problem ASAP and send the
fix to the list.
Angel