spacepaste

  1.  
  2. #!/usr/bin/env python
  3. #############################################################################
  4. ##
  5. ## Copyright (C) 2010 Riverbank Computing Limited.
  6. ## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
  7. ## All rights reserved.
  8. ##
  9. ## This file is part of the examples of PyQt.
  10. ##
  11. ## $QT_BEGIN_LICENSE:BSD$
  12. ## You may use this file under the terms of the BSD license as follows:
  13. ##
  14. ## "Redistribution and use in source and binary forms, with or without
  15. ## modification, are permitted provided that the following conditions are
  16. ## met:
  17. ## * Redistributions of source code must retain the above copyright
  18. ## notice, this list of conditions and the following disclaimer.
  19. ## * Redistributions in binary form must reproduce the above copyright
  20. ## notice, this list of conditions and the following disclaimer in
  21. ## the documentation and/or other materials provided with the
  22. ## distribution.
  23. ## * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
  24. ## the names of its contributors may be used to endorse or promote
  25. ## products derived from this software without specific prior written
  26. ## permission.
  27. ##
  28. ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  29. ## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  30. ## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  31. ## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  32. ## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  33. ## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  34. ## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  35. ## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  36. ## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  37. ## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  38. ## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  39. ## $QT_END_LICENSE$
  40. ##
  41. #############################################################################
  42. from PyQt4 import QtCore, QtGui
  43. class TreeItem(object):
  44. def __init__(self, data, parent=None):
  45. self.parentItem = parent
  46. self.checkable = data[0][0] == "x"
  47. self.itemData = data
  48. self.childItems = []
  49. self.checked = None
  50. if self.checkable:
  51. self.checked = QtCore.Qt.Checked
  52. def appendChild(self, item):
  53. self.childItems.append(item)
  54. def child(self, row):
  55. return self.childItems[row]
  56. def childCount(self):
  57. return len(self.childItems)
  58. def columnCount(self):
  59. return len(self.itemData)
  60. def data(self, column):
  61. try:
  62. return self.itemData[column]
  63. except IndexError:
  64. return None
  65. def parent(self):
  66. return self.parentItem
  67. def row(self):
  68. if self.parentItem:
  69. return self.parentItem.childItems.index(self)
  70. return 0
  71. class TreeModel(QtCore.QAbstractItemModel):
  72. def __init__(self, data, parent=None):
  73. super(TreeModel, self).__init__(parent)
  74. self.states = {}
  75. self.rootItem = TreeItem(("Title", "Summary"))
  76. self.setupModelData(data.split('\n'), self.rootItem)
  77. def columnCount(self, parent):
  78. if parent.isValid():
  79. return parent.internalPointer().columnCount()
  80. else:
  81. return self.rootItem.columnCount()
  82. def data(self, index, role):
  83. if not index.isValid():
  84. return None
  85. item = index.internalPointer()
  86. if role == QtCore.Qt.DisplayRole:
  87. return item.data(index.column())
  88. elif role == QtCore.Qt.CheckStateRole:
  89. if index.column() == 0:
  90. return item.checked
  91. return None
  92. def setData(self, index, value, role):
  93. status = False
  94. item = index.internalPointer()
  95. if role == QtCore.Qt.CheckStateRole:
  96. if index.column() == 0:
  97. if item.checked == QtCore.Qt.Checked:
  98. item.checked = QtCore.Qt.Unchecked
  99. else:
  100. item.checked = QtCore.Qt.Checked
  101. status = True
  102. self.emit(QtCore.SIGNAL('dataChanged(QModelIndex,QModelIndex)'), index, index)
  103. return status
  104. def flags(self, index):
  105. if not index.isValid():
  106. return QtCore.Qt.NoItemFlags
  107. flags = QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
  108. item = index.internalPointer()
  109. if item.checkable and index.column() == 0:
  110. flags = flags | QtCore.Qt.ItemIsUserCheckable
  111. return flags
  112. def headerData(self, section, orientation, role):
  113. if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
  114. return self.rootItem.data(section)
  115. return None
  116. def index(self, row, column, parent):
  117. if not self.hasIndex(row, column, parent):
  118. return QtCore.QModelIndex()
  119. if not parent.isValid():
  120. parentItem = self.rootItem
  121. else:
  122. parentItem = parent.internalPointer()
  123. childItem = parentItem.child(row)
  124. if childItem:
  125. return self.createIndex(row, column, childItem)
  126. else:
  127. return QtCore.QModelIndex()
  128. def parent(self, index):
  129. if not index.isValid():
  130. return QtCore.QModelIndex()
  131. childItem = index.internalPointer()
  132. parentItem = childItem.parent()
  133. if parentItem == self.rootItem:
  134. return QtCore.QModelIndex()
  135. return self.createIndex(parentItem.row(), 0, parentItem)
  136. def rowCount(self, parent):
  137. if parent.column() > 0:
  138. return 0
  139. if not parent.isValid():
  140. parentItem = self.rootItem
  141. else:
  142. parentItem = parent.internalPointer()
  143. return parentItem.childCount()
  144. def setupModelData(self, lines, parent):
  145. parents = [parent]
  146. indentations = [0]
  147. number = 0
  148. while number < len(lines):
  149. position = 0
  150. while position < len(lines[number]):
  151. if lines[number][position] != ' ':
  152. break
  153. position += 1
  154. lineData = lines[number][position:].trimmed()
  155. if lineData:
  156. # Read the column data from the rest of the line.
  157. columnData = [s for s in lineData.split('\t') if s]
  158. if position > indentations[-1]:
  159. # The last child of the current parent is now the new
  160. # parent unless the current parent has no children.
  161. if parents[-1].childCount() > 0:
  162. parents.append(parents[-1].child(parents[-1].childCount() - 1))
  163. indentations.append(position)
  164. else:
  165. while position < indentations[-1] and len(parents) > 0:
  166. parents.pop()
  167. indentations.pop()
  168. # Append a new item to the current parent's list of children.
  169. parents[-1].appendChild(TreeItem(columnData, parents[-1]))
  170. number += 1
  171. if __name__ == '__main__':
  172. import sys
  173. app = QtGui.QApplication(sys.argv)
  174. f = QtCore.QFile('default.txt')
  175. f.open(QtCore.QIODevice.ReadOnly)
  176. model = TreeModel(f.readAll())
  177. f.close()
  178. view = QtGui.QTreeView()
  179. view.setModel(model)
  180. view.setWindowTitle("Simple Tree Model")
  181. view.show()
  182. sys.exit(app.exec_())
  183.