Package pyffi :: Package qskope :: Module detail_model
[hide private]
[frames] | no frames]

Source Code for Module pyffi.qskope.detail_model

  1  """The DetailModel module defines a model to display the details of 
  2  StructBase, Array, and BasicBase instances.""" 
  3   
  4  # ***** BEGIN LICENSE BLOCK ***** 
  5  # 
  6  # Copyright (c) 2007-2011, Python File Format Interface 
  7  # All rights reserved. 
  8  # 
  9  # Redistribution and use in source and binary forms, with or without 
 10  # modification, are permitted provided that the following conditions 
 11  # are met: 
 12  # 
 13  #    * Redistributions of source code must retain the above copyright 
 14  #      notice, this list of conditions and the following disclaimer. 
 15  # 
 16  #    * Redistributions in binary form must reproduce the above 
 17  #      copyright notice, this list of conditions and the following 
 18  #      disclaimer in the documentation and/or other materials provided 
 19  #      with the distribution. 
 20  # 
 21  #    * Neither the name of the Python File Format Interface 
 22  #      project nor the names of its contributors may be used to endorse 
 23  #      or promote products derived from this software without specific 
 24  #      prior written permission. 
 25  # 
 26  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 27  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 28  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 29  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 30  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 31  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 32  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 33  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 34  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 35  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 36  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 37  # POSSIBILITY OF SUCH DAMAGE. 
 38  # 
 39  # ***** END LICENSE BLOCK ***** 
 40   
 41  from PyQt4 import QtCore 
 42   
 43  from pyffi.utils.graph import EdgeFilter, GlobalNode 
 44  from pyffi.qskope.detail_tree import DetailTreeItem, DetailTreeItemData 
 45   
 46  # implementation references: 
 47  # http://doc.trolltech.com/4.3/model-view-programming.html 
 48  # http://doc.trolltech.com/4.3/model-view-model-subclassing.html 
49 -class DetailModel(QtCore.QAbstractItemModel):
50 """General purpose model for QModelIndexed access to pyffi data structures 51 such as StructBase, Array, and BasicBase instances.""" 52 # column definitions 53 NUM_COLUMNS = 3 54 COL_NAME = 0 55 COL_TYPE = 1 56 COL_VALUE = 2 57 58 # def __init__(self, parent = None, block = None, refnumber_dict = None): 59 # """Initialize the model to display the given block. The refnumber_dict 60 # dictionary is used to handle references in the block.""" 61 # QtCore.QAbstractItemModel.__init__(self, parent) 62 # # this list stores the blocks in the view 63 # # is a list of NiObjects for the nif format, and a list of Chunks for 64 # # the cgf format 65 # self.block = block 66 # self.refNumber = refnumber_dict if not refnumber_dict is None else {} 67
68 - def __init__(self, parent=None, globalnode=None, globalmodel=None, 69 edge_filter=EdgeFilter()):
70 """Initialize the model to display the given global node in the 71 detail tree. We also need a reference to the global model to 72 resolve node references. 73 """ 74 QtCore.QAbstractItemModel.__init__(self, parent) 75 self.root_item = DetailTreeItem( 76 data=DetailTreeItemData(node=globalnode), 77 edge_filter=EdgeFilter()) 78 self.globalmodel = globalmodel
79
80 - def flags(self, index):
81 """Return flags for the given index: all indices are enabled and 82 selectable.""" 83 if not index.isValid(): 84 return QtCore.Qt.ItemFlags() 85 # all items are enabled and selectable 86 flags = QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable 87 # determine whether item value can be set 88 if index.column() == self.COL_VALUE: 89 try: 90 index.internalPointer().data.node.get_value() 91 # TODO: find more clever system 92 except AttributeError: 93 pass 94 except NotImplementedError: 95 pass 96 else: 97 flags |= QtCore.Qt.ItemIsEditable 98 return QtCore.Qt.ItemFlags(flags)
99
100 - def data(self, index, role):
101 """Return the data of model index in a particular role. Only 102 QtCore.Qt.DisplayRole is implemented. 103 """ 104 # check if the index is valid 105 # check if the role is supported 106 if not index.isValid() or role != QtCore.Qt.DisplayRole: 107 return QtCore.QVariant() 108 # get the data for display 109 item = index.internalPointer() 110 111 # the name column 112 if index.column() == self.COL_NAME: 113 return QtCore.QVariant(item.data.name) 114 115 # the type column 116 elif index.column() == self.COL_TYPE: 117 return QtCore.QVariant(item.data.typename) 118 119 # the value column 120 elif index.column() == self.COL_VALUE: 121 # get display element 122 display = item.data.display 123 if isinstance(display, GlobalNode): 124 # reference 125 blocknum = self.globalmodel.index_dict[display] 126 if (not hasattr(display, "name") or not display.name): 127 return QtCore.QVariant( 128 "%i [%s]" % (blocknum, display.__class__.__name__)) 129 else: 130 return QtCore.QVariant( 131 "%i (%s)" % (blocknum, display.name)) 132 elif isinstance(display, basestring): 133 # regular string 134 if len(display) > 32: 135 display = display[:32] + "..." 136 return QtCore.QVariant( 137 display.replace("\n", " ").replace("\r", " ")) 138 else: 139 raise TypeError("%s: do not know how to display %s" 140 % (item.data.name, display.__class__.__name__)) 141 142 # other colums: invalid 143 else: 144 return QtCore.QVariant()
145
146 - def headerData(self, section, orientation, role):
147 """Return header data.""" 148 if (orientation == QtCore.Qt.Horizontal 149 and role == QtCore.Qt.DisplayRole): 150 if section == self.COL_TYPE: 151 return QtCore.QVariant("Type") 152 elif section == self.COL_NAME: 153 return QtCore.QVariant("Name") 154 elif section == self.COL_VALUE: 155 return QtCore.QVariant("Value") 156 return QtCore.QVariant()
157
158 - def rowCount(self, parent=QtCore.QModelIndex()):
159 """Calculate a row count for the given parent index.""" 160 if not parent.isValid(): 161 # top level: one row for each attribute 162 return len(self.root_item.children) 163 else: 164 # get the parent child count 165 return len(parent.internalPointer().children)
166
167 - def columnCount(self, parent=QtCore.QModelIndex()):
168 """Return column count.""" 169 # column count is constant everywhere 170 return self.NUM_COLUMNS
171
172 - def index(self, row, column, parent):
173 """Create an index to item (row, column) of object parent.""" 174 # check if the parent is valid 175 if not parent.isValid(): 176 # parent is not valid, so we need a top-level object 177 # return the row'th attribute 178 item = self.root_item.children[row] 179 else: 180 # parent is valid, so we need to go get the row'th attribute 181 # get the parent pointer 182 item = parent.internalPointer().children[row] 183 return self.createIndex(row, column, item)
184
185 - def parent(self, index):
186 """Calculate parent of a given index.""" 187 # get parent structure 188 parent_item = index.internalPointer().parent 189 # if parent's parent is None, then index must be a top 190 # level object, so return invalid index 191 if parent_item.parent is None: 192 return QtCore.QModelIndex() 193 # if parent's parent is not None, then it must be member of 194 # some deeper nested structure, so calculate the row as usual 195 else: 196 return self.createIndex(parent_item.row, 0, parent_item)
197
198 - def setData(self, index, value, role):
199 """Set data of a given index from given QVariant value. Only 200 QtCore.Qt.EditRole is implemented. 201 """ 202 if role == QtCore.Qt.EditRole: 203 # fetch the current data, as a regular Python type 204 node = index.internalPointer().data.node 205 currentvalue = node.get_value() 206 # transform the QVariant value into the right class 207 if isinstance(currentvalue, (int, long)): 208 # use long type to work around QVariant(0xffffffff).toInt() bug 209 pyvalue, ok = value.toLongLong() 210 elif isinstance(currentvalue, float): 211 pyvalue, ok = value.toDouble() 212 elif isinstance(currentvalue, basestring): 213 pyvalue = str(value.toString()) 214 ok = True 215 elif isinstance(currentvalue, bool): 216 pyvalue, ok = value.toBool() 217 else: 218 # type not supported 219 return False 220 # check if conversion worked 221 if not ok: 222 return False 223 # set the value (EditRole, so use set_editor_value, not set_value) 224 node.set_editor_value(pyvalue) 225 # tell everyone that the data has changed 226 self.emit(QtCore.SIGNAL('dataChanged(QModelIndex, QModelIndex)'), 227 index, index) 228 return True 229 # all other cases: failed 230 return False
231