/tortoisehg/hgqt/repotreemodel.py

https://bitbucket.org/tortoisehg/hgtk/ · Python · 240 lines · 193 code · 38 blank · 9 comment · 41 complexity · a1c9e3c864056d801487918868640acc MD5 · raw file

  1. # repotreemodel.py - model for the reporegistry
  2. #
  3. # Copyright 2010 Adrian Buehlmann <adrian@cadifra.com>
  4. #
  5. # This software may be used and distributed according to the terms of the
  6. # GNU General Public License version 2 or any later version.
  7. from mercurial import error
  8. from tortoisehg.hgqt import thgrepo
  9. from tortoisehg.util import hglib
  10. from tortoisehg.hgqt.i18n import _
  11. from repotreeitem import undumpObject, AllRepoGroupItem, RepoGroupItem
  12. from repotreeitem import RepoItem, RepoTreeItem
  13. from PyQt4.QtCore import *
  14. from PyQt4.QtGui import *
  15. extractXmlElementName = 'reporegextract'
  16. reporegistryXmlElementName = 'reporegistry'
  17. repoRegMimeType = 'application/thg-reporegistry'
  18. def writeXml(target, item, rootElementName):
  19. xw = QXmlStreamWriter(target)
  20. xw.setAutoFormatting(True)
  21. xw.setAutoFormattingIndent(2)
  22. xw.writeStartDocument()
  23. xw.writeStartElement(rootElementName)
  24. item.dumpObject(xw)
  25. xw.writeEndElement()
  26. xw.writeEndDocument()
  27. def readXml(source, rootElementName, model):
  28. itemread = None
  29. xr = QXmlStreamReader(source)
  30. if xr.readNextStartElement():
  31. ele = str(xr.name().toString())
  32. if ele != rootElementName:
  33. print "unexpected xml element '%s' "\
  34. "(was looking for %s)" % (ele, rootElementName)
  35. return
  36. if xr.hasError():
  37. print str(xr.errorString())
  38. if xr.readNextStartElement():
  39. itemread = undumpObject(xr, model)
  40. xr.skipCurrentElement()
  41. if xr.hasError():
  42. print str(xr.errorString())
  43. return itemread
  44. class RepoTreeModel(QAbstractItemModel):
  45. def __init__(self, openrepofunc, filename=None, parent=None):
  46. QAbstractItemModel.__init__(self, parent)
  47. self.openrepofunc = openrepofunc
  48. root = None
  49. all = None
  50. if filename:
  51. f = QFile(filename)
  52. if f.open(QIODevice.ReadOnly):
  53. root = readXml(f, reporegistryXmlElementName, self)
  54. f.close()
  55. if root:
  56. for c in root.childs:
  57. if isinstance(c, AllRepoGroupItem):
  58. all = c
  59. break
  60. if not root:
  61. root = RepoTreeItem(self)
  62. all = AllRepoGroupItem(self)
  63. root.appendChild(all)
  64. self.rootItem = root
  65. self.allrepos = all
  66. # see http://doc.qt.nokia.com/4.6/model-view-model-subclassing.html
  67. # overrides from QAbstractItemModel
  68. def index(self, row, column, parent):
  69. if not self.hasIndex(row, column, parent):
  70. return QModelIndex()
  71. if (not parent.isValid()):
  72. parentItem = self.rootItem
  73. else:
  74. parentItem = parent.internalPointer()
  75. childItem = parentItem.child(row)
  76. if childItem:
  77. return self.createIndex(row, column, childItem)
  78. else:
  79. return QModelIndex()
  80. def parent(self, index):
  81. if not index.isValid():
  82. return QModelIndex()
  83. childItem = index.internalPointer()
  84. parentItem = childItem.parent()
  85. if parentItem is self.rootItem:
  86. return QModelIndex()
  87. return self.createIndex(parentItem.row(), 0, parentItem)
  88. def rowCount(self, parent):
  89. if parent.column() > 0:
  90. return 0
  91. if not parent.isValid():
  92. parentItem = self.rootItem;
  93. else:
  94. parentItem = parent.internalPointer()
  95. return parentItem.childCount()
  96. def columnCount(self, parent):
  97. if parent.isValid():
  98. return parent.internalPointer().columnCount()
  99. else:
  100. return self.rootItem.columnCount()
  101. def data(self, index, role):
  102. if not index.isValid():
  103. return QVariant()
  104. if role not in (Qt.DisplayRole, Qt.EditRole, Qt.DecorationRole):
  105. return QVariant()
  106. item = index.internalPointer()
  107. return item.data(index.column(), role)
  108. def headerData(self, section, orientation, role):
  109. if role == Qt.DisplayRole:
  110. if orientation == Qt.Horizontal:
  111. if section == 1:
  112. return QString(_('Path'))
  113. return QVariant()
  114. def flags(self, index):
  115. if not index.isValid():
  116. return Qt.NoItemFlags
  117. item = index.internalPointer()
  118. return item.flags()
  119. def supportedDropActions(self):
  120. return Qt.CopyAction | Qt.MoveAction | Qt.LinkAction
  121. def removeRows(self, row, count, parent):
  122. item = parent.internalPointer()
  123. if item is None:
  124. item = self.rootItem
  125. self.beginRemoveRows(parent, row, row+count-1)
  126. res = item.removeRows(row, count)
  127. self.endRemoveRows()
  128. return res
  129. def mimeTypes(self):
  130. return QStringList(repoRegMimeType)
  131. def mimeData(self, indexes):
  132. i = indexes[0]
  133. item = i.internalPointer()
  134. buf = QByteArray()
  135. writeXml(buf, item, extractXmlElementName)
  136. d = QMimeData()
  137. d.setData(repoRegMimeType, buf)
  138. d.setUrls([QUrl.fromLocalFile(hglib.tounicode(item.rootpath()))])
  139. return d
  140. def dropMimeData(self, data, action, row, column, parent):
  141. d = str(data.data(repoRegMimeType))
  142. itemread = readXml(d, extractXmlElementName, self)
  143. group = parent.internalPointer()
  144. if row < 0:
  145. row = 0
  146. self.beginInsertRows(parent, row, row)
  147. group.insertChild(row, itemread)
  148. self.endInsertRows()
  149. return True
  150. def setData(self, index, value, role):
  151. if not index.isValid() or role != Qt.EditRole:
  152. return False
  153. s = value.toString()
  154. if s.isEmpty():
  155. return False
  156. item = index.internalPointer()
  157. if item.setData(index.column(), value):
  158. self.emit(SIGNAL('dataChanged(index, index)'), index, index)
  159. return True
  160. return False
  161. # functions not defined in QAbstractItemModel
  162. def allreposIndex(self):
  163. return self.createIndex(0, 0, self.allrepos)
  164. def addRepo(self, group, reporoot):
  165. ar = reporoot
  166. if ar == '':
  167. caption = _('Select repository directory to add')
  168. FD = QFileDialog
  169. path = FD.getExistingDirectory(caption=caption,
  170. options=FD.ShowDirsOnly | FD.ReadOnly)
  171. if path:
  172. try:
  173. lpath = hglib.fromunicode(path)
  174. repo = thgrepo.repository(None, path=lpath)
  175. ar = repo.root
  176. except error.RepoError:
  177. QMessageBox.warning(self, _('Failed to add repository'),
  178. _('%s is not a valid repository') % path)
  179. return
  180. else:
  181. return
  182. grp = group
  183. if grp == None:
  184. grp = self.allreposIndex()
  185. rgi = grp.internalPointer()
  186. cc = rgi.childCount()
  187. self.beginInsertRows(grp, cc, cc + 1)
  188. rgi.appendChild(RepoItem(self, rootpath=ar))
  189. self.endInsertRows()
  190. def getRepoItem(self, reporoot):
  191. return self.rootItem.getRepoItem(reporoot)
  192. def addGroup(self, name):
  193. ri = self.rootItem
  194. cc = ri.childCount()
  195. self.beginInsertRows(QModelIndex(), cc, cc + 1)
  196. ri.appendChild(RepoGroupItem(self, name, ri))
  197. self.endInsertRows()
  198. def write(self, fn):
  199. f = QFile(fn)
  200. f.open(QIODevice.WriteOnly)
  201. writeXml(f, self.rootItem, reporegistryXmlElementName)
  202. f.close()