Mercurial and Git clients can push and pull from this alias URL to interact with this repository. You can change to which repository an alias points by going to the Aliases link on the project page.
# manifestmodel.py - Model for TortoiseHg manifest view## Copyright (C) 2009-2010 LOGILAB S.A. <http://www.logilab.fr/># Copyright (C) 2010 Yuya Nishihara <yuya@tcha.org>## This program is free software; you can redistribute it and/or modify it under# the terms of the GNU General Public License as published by the Free Software# Foundation; either version 2 of the License, or (at your option) any later# version.
import os, itertools
+import refrom PyQt4.QtCore import *
from PyQt4.QtGui import *
frommercurialimportutilfrommercurial.subrepoimporthgsubrepofromtortoisehg.utilimporthglibfromtortoisehg.hgqtimportqtlib,status,visdiffclassManifestModel(QAbstractItemModel):""" Qt model to display a hg manifest, ie. the tree of files at a given revision. To be used with a QTreeView. """StatusRole=Qt.UserRole+1"""Role for file change status"""def__init__(self,repo,rev=None,statusfilter='MASC',parent=None):QAbstractItemModel.__init__(self,parent)self._repo=repoself._rev=revself._subinfo={}assertutil.all(cin'MARSC'forcinstatusfilter)self._statusfilter=statusfilterdefdata(self,index,role=Qt.DisplayRole):ifnotindex.isValid():returnifrole==Qt.DecorationRole:returnself.fileIcon(index)ifrole==self.StatusRole:returnself.fileStatus(index)e=index.internalPointer()ifrolein(Qt.DisplayRole,Qt.EditRole):returne.namedeffilePath(self,index):"""Return path at the given index [unicode]"""ifnotindex.isValid():return''returnindex.internalPointer().pathdeffileSubrepoCtx(self,index):"""Return the subrepo context of the specified index"""path=self.filePath(index)returnself.fileSubrepoCtxFromPath(path)deffileSubrepoCtxFromPath(self,path):"""Return the subrepo context of the specified file"""ifnotpath:returnNone,pathforsubpathinsorted(self._subinfo.keys())[::-1]:ifpath.startswith(subpath+'/'):returnself._subinfo[subpath]['ctx'],path[len(subpath)+1:]returnNone,pathdefsubrepoType(self,index):"""Return the subrepo type the specified index"""path=self.filePath(index)returnself.subrepoTypeFromPath(path)defsubrepoTypeFromPath(self,path):"""Return the subrepo type of the specified subrepo"""ifnotpath:returnNonetry:substate=self._subinfo[path]returnsubstate['substate'][2]except:returnNonedeffileIcon(self,index):ic=QApplication.style().standardIcon(self.isDir(index)andQStyle.SP_DirIconorQStyle.SP_FileIcon)ifnotindex.isValid():returnice=index.internalPointer()ifnote.status:returnicst=status.statusTypes[e.status]ifst.icon:icOverlay=qtlib.geticon(st.icon[:-4])ife.status=='S':_subrepoType2IcoMap={'hg':'hg','git':'thg-git-subrepo','svn':'thg-svn-subrepo',}stype=self.subrepoType(index)ifstype:ic=qtlib.geticon(_subrepoType2IcoMap[stype])ic=qtlib.getoverlaidicon(ic,icOverlay)# XXXreturnicdeffileStatus(self,index):"""Return the change status of the specified file"""ifnotindex.isValid():returne=index.internalPointer()returne.statusdefisDir(self,index):ifnotindex.isValid():returnTrue# root entry must be a directorye=index.internalPointer()ife.status=='S':# Consider subrepos as dirs as wellreturnTrueelse:returnlen(e)!=0defmimeData(self,indexes):defpreparefiles():files=[self.filePath(i)foriinindexesifi.isValid()]ifself._revisnotNone:base,_fns=visdiff.snapshot(self._repo,files,self._repo[self._rev])else:# working copybase=self._repo.rootreturniter(os.path.join(base,e)foreinfiles)m=QMimeData()m.setUrls([QUrl.fromLocalFile(e)foreinpreparefiles()])returnmdefmimeTypes(self):return['text/uri-list']defflags(self,index):ifnotindex.isValid():returnQt.ItemIsEnabledf=Qt.ItemIsEnabled|Qt.ItemIsSelectableifnot(self.isDir(index)orself.fileStatus(index)=='R'):f|=Qt.ItemIsDragEnabledreturnfdefindex(self,row,column,parent=QModelIndex()):try:returnself.createIndex(row,column,self._parententry(parent).at(row))exceptIndexError:returnQModelIndex()defindexFromPath(self,path,column=0):"""Return index for the specified path if found [unicode] If not found, returns invalid index. """ifnotpath:returnQModelIndex()e=self._rootentrypaths=pathandunicode(path).split('/')or[]try:forpinpaths:e=e[p]exceptKeyError:returnQModelIndex()returnself.createIndex(e.parent.index(e.name),column,e)defparent(self,index):ifnotindex.isValid():returnQModelIndex()e=index.internalPointer()ife.path:returnself.indexFromPath(e.parent.path,index.column())else:returnQModelIndex()def_parententry(self,parent):ifparent.isValid():returnparent.internalPointer()else:returnself._rootentrydefrowCount(self,parent=QModelIndex()):returnlen(self._parententry(parent))defcolumnCount(self,parent=QModelIndex()):return1@pyqtSlot(str)defsetStatusFilter(self,status):"""Filter file tree by change status 'MARSC'"""status=str(status)assertutil.all(cin'MARSC'forcinstatus)ifself._statusfilter==status:return# for performance reasonself._statusfilter=statusself._buildrootentry()@propertydefstatusFilter(self):"""Return the current status filter"""returnself._statusfilter@propertydef_rootentry(self):try:returnself.__rootentryexcept(AttributeError,TypeError):self._buildrootentry()returnself.__rootentrydef_buildrootentry(self):"""Rebuild the tree of files and directories"""defpathinstatus(path,status,uncleanpaths):"""Test path is included by the status filter"""ifutil.any(cinself._statusfilterandpathineforc,einstatus.iteritems()):returnTrueif'C'inself._statusfilterandpathnotinuncleanpaths:returnTruereturnFalsedefgetctxtreeinfo(ctx,repo):""" Get the context information that is relevant to populating the tree """status=dict(zip(('M','A','R'),(set(a)forainself._repo.status(ctx.parents()[0],ctx)[:3])))uncleanpaths=status['M']|status['A']|status['R']files=itertools.chain(ctx.manifest(),status['R'])returnstatus,uncleanpaths,filesdefaddfilestotree(treeroot,files,status,uncleanpaths):"""Add files to the tree according to their state"""forpathinfiles: if not pathinstatus(path, status, uncleanpaths):
continue
+ path = re.sub(r'^\.kbf/', '', path)+ e = treeroot
for p in hglib.tounicode(path).split('/'):
if not p in e:
e.addchild(p)e=e[p]forst,filesofstinstatus.iteritems():ifpathinfilesofst:e.setstatus(st)breakelse:e.setstatus('C')# Add subrepos to the treedefaddrepocontentstotree(roote,ctx,toproot=''):subpaths=ctx.substate.keys()forpathinsubpaths:ifnot'S'inself._statusfilter:breake=rootepathelements=hglib.tounicode(path).split('/')forpinpathelements[:-1]:ifnotpine:e.addchild(p)e=e[p]p=pathelements[-1]ifnotpine:e.addchild(p)e=e[p]e.setstatus('S')# If the subrepo exists in the working directory# and it is a mercurial subrepo,# add the files that it contains to the tree as well, according# to the status filterabspath=os.path.join(ctx._repo.root,path)ifos.path.isdir(abspath):# Add subrepo files to the treesubstate=ctx.substate[path]# Add the subrepo info to the _subinfo dictionary:# The value is the subrepo context, while the key is# the path of the subrepo relative to the topmost repoiftoproot:# Note that we cannot use os.path.join() because we# need path items to be separated by "/"toprelpath='/'.join([toproot,path])else:toprelpath=pathtoprelpath=util.pconvert(toprelpath)self._subinfo[toprelpath]= \
{'substate':substate,'ctx':None}srev=substate[1]sub=ctx.sub(path)ifsrevandisinstance(sub,hgsubrepo):srepo=sub._repoifsrevinsrepo:sctx=srepo[srev]self._subinfo[toprelpath]['ctx']=sctx# Add the subrepo contents to the treee=addrepocontentstotree(e,sctx,toprelpath)# Add regular files to the treestatus,uncleanpaths,files=getctxtreeinfo(ctx,self._repo)addfilestotree(roote,files,status,uncleanpaths)returnroote# Clear the _subinfoself._subinfo={}roote=_Entry()ctx=self._repo[self._rev]addrepocontentstotree(roote,ctx)roote.sort()self.beginResetModel()self.__rootentry=rooteself.endResetModel()class_Entry(object):"""Each file or directory"""def__init__(self,name='',parent=None):self._name=nameself._parent=parentself._status=Noneself._child={}self._nameindex=[]@propertydefparent(self):returnself._parent@propertydefpath(self):ifself.parentisNoneornotself.parent.name:returnself.nameelse:returnself.parent.path+'/'+self.name@propertydefname(self):returnself._name@propertydefstatus(self):"""Return file change status"""returnself._statusdefsetstatus(self,status):assertstatusin'MARSC'self._status=statusdef__len__(self):returnlen(self._child)def__getitem__(self,name):returnself._child[name]defaddchild(self,name):ifnamenotinself._child:self._nameindex.append(name)self._child[name]=self.__class__(name,parent=self)def__contains__(self,item):returniteminself._childdefat(self,index):returnself._child[self._nameindex[index]]defindex(self,name):returnself._nameindex.index(name)defsort(self,reverse=False):"""Sort the entries recursively; directories first"""foreinself._child.itervalues():e.sort(reverse=reverse)self._nameindex.sort(key=lambdas:'%s%s'%(self[s]and'D'or'F',s),reverse=reverse)classManifestCompleter(QCompleter):"""QCompleter for ManifestModel"""defsplitPath(self,path):""" >>> c = ManifestCompleter() >>> c.splitPath(QString('foo/bar')) [u'foo', u'bar'] trailing slash appends extra '', so that QCompleter can descend to next level: >>> c.splitPath(QString('foo/')) [u'foo', u''] """returnunicode(path).split('/')defpathFromIndex(self,index):ifnotindex.isValid():return''m=self.model()ifnotm:return''returnm.filePath(index)
Attach a Trello Card
Add a tag
Your session has expired
You are no longer logged in. Please log in and try your request again.
Filter RSS Feed
This RSS feed URL allows you to see the contents of your current filter using any feed reader.
This link includes a special authentication token. If you share the URL with anyone else, they can see this RSS feed's activity. You can disable these tokens when needed.
Your current filter is unsaved; changing it won't affect this RSS feed.