1# -*- coding: utf-8 -*- 2 3# Copyright (c) 2006 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> 4# 5 6""" 7Module implementing the Watch expression model. 8""" 9 10import copy 11 12from PyQt5.QtCore import pyqtSignal, Qt, QAbstractItemModel, QModelIndex 13 14 15class WatchPointModel(QAbstractItemModel): 16 """ 17 Class implementing a custom model for watch expressions. 18 19 @signal dataAboutToBeChanged(QModelIndex, QModelIndex) emitted to indicate 20 a change of the data 21 """ 22 dataAboutToBeChanged = pyqtSignal(QModelIndex, QModelIndex) 23 24 def __init__(self, parent=None): 25 """ 26 Constructor 27 28 @param parent reference to the parent widget (QObject) 29 """ 30 super().__init__(parent) 31 32 self.watchpoints = [] 33 self.header = [ 34 self.tr("Condition"), 35 self.tr("Special"), 36 self.tr('Temporary'), 37 self.tr('Enabled'), 38 self.tr('Ignore Count'), 39 ] 40 self.alignments = [Qt.Alignment(Qt.AlignmentFlag.AlignLeft), 41 Qt.Alignment(Qt.AlignmentFlag.AlignLeft), 42 Qt.Alignment(Qt.AlignmentFlag.AlignHCenter), 43 Qt.Alignment(Qt.AlignmentFlag.AlignHCenter), 44 Qt.Alignment(Qt.AlignmentFlag.AlignRight), 45 ] 46 47 def columnCount(self, parent=None): 48 """ 49 Public method to get the current column count. 50 51 @param parent index of the parent item (QModelIndex) (Unused) 52 @return column count (integer) 53 """ 54 return len(self.header) 55 56 def rowCount(self, parent=None): 57 """ 58 Public method to get the current row count. 59 60 @param parent index of the parent item (QModelIndex) 61 @return row count (integer) 62 """ 63 # we do not have a tree, parent should always be invalid 64 if parent is None or not parent.isValid(): 65 return len(self.watchpoints) 66 else: 67 return 0 68 69 def data(self, index, role): 70 """ 71 Public method to get the requested data. 72 73 @param index index of the requested data (QModelIndex) 74 @param role role of the requested data (Qt.ItemDataRole) 75 @return the requested data 76 """ 77 if not index.isValid(): 78 return None 79 80 if ( 81 role == Qt.ItemDataRole.DisplayRole and 82 index.column() in [0, 1, 4] 83 ): 84 return self.watchpoints[index.row()][index.column()] 85 86 if ( 87 role == Qt.ItemDataRole.CheckStateRole and 88 index.column() in [2, 3] 89 ): 90 return self.watchpoints[index.row()][index.column()] 91 92 if ( 93 role == Qt.ItemDataRole.ToolTipRole and 94 index.column() in [0, 1] 95 ): 96 return self.watchpoints[index.row()][index.column()] 97 98 if ( 99 role == Qt.ItemDataRole.TextAlignmentRole and 100 index.column() < len(self.alignments) 101 ): 102 return self.alignments[index.column()] 103 104 return None 105 106 def flags(self, index): 107 """ 108 Public method to get item flags. 109 110 @param index index of the requested flags (QModelIndex) 111 @return item flags for the given index (Qt.ItemFlags) 112 """ 113 if not index.isValid(): 114 return Qt.ItemFlag.ItemIsEnabled 115 116 return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable 117 118 def headerData(self, section, orientation, 119 role=Qt.ItemDataRole.DisplayRole): 120 """ 121 Public method to get header data. 122 123 @param section section number of the requested header data (integer) 124 @param orientation orientation of the header (Qt.Orientation) 125 @param role role of the requested data (Qt.ItemDataRole) 126 @return header data 127 """ 128 if ( 129 orientation == Qt.Orientation.Horizontal and 130 role == Qt.ItemDataRole.DisplayRole 131 ): 132 if section >= len(self.header): 133 return "" 134 else: 135 return self.header[section] 136 137 return None 138 139 def index(self, row, column, parent=None): 140 """ 141 Public method to create an index. 142 143 @param row row number for the index (integer) 144 @param column column number for the index (integer) 145 @param parent index of the parent item (QModelIndex) 146 @return requested index (QModelIndex) 147 """ 148 if ( 149 (parent and parent.isValid()) or 150 row < 0 or 151 row >= len(self.watchpoints) or 152 column < 0 or 153 column >= len(self.header) 154 ): 155 return QModelIndex() 156 157 return self.createIndex(row, column, self.watchpoints[row]) 158 159 def parent(self, index): 160 """ 161 Public method to get the parent index. 162 163 @param index index of item to get parent (QModelIndex) 164 @return index of parent (QModelIndex) 165 """ 166 return QModelIndex() 167 168 def hasChildren(self, parent=None): 169 """ 170 Public method to check for the presence of child items. 171 172 @param parent index of parent item (QModelIndex) 173 @return flag indicating the presence of child items (boolean) 174 """ 175 if parent is None or not parent.isValid(): 176 return len(self.watchpoints) > 0 177 else: 178 return False 179 180 ########################################################################### 181 182 def addWatchPoint(self, cond, special, properties): 183 """ 184 Public method to add a new watch expression to the list. 185 186 @param cond expression of the watch expression 187 @type str 188 @param special special condition of the watch expression 189 @type str 190 @param properties properties of the watch expression 191 (tuple of temporary flag, enabled flag, ignore count) 192 @type tuple of (bool, bool, int) 193 """ 194 wp = [cond, special] + list(properties) 195 cnt = len(self.watchpoints) 196 self.beginInsertRows(QModelIndex(), cnt, cnt) 197 self.watchpoints.append(wp) 198 self.endInsertRows() 199 200 def addWatchPoints(self, watchpoints): 201 """ 202 Public method to add multiple watch expressions to the list. 203 204 @param watchpoints list of watch expressions with expression, special 205 condition, temporary flag, enabled flag and ignore count each 206 @type list of (str, str, bool, bool, int) 207 """ 208 cnt = len(self.watchpoints) 209 self.beginInsertRows(QModelIndex(), cnt, cnt + len(watchpoints) - 1) 210 self.watchpoints += watchpoints 211 self.endInsertRows() 212 213 def setWatchPointByIndex(self, index, cond, special, properties): 214 """ 215 Public method to set the values of a watch expression given by index. 216 217 @param index index of the watch expression (QModelIndex) 218 @param cond expression of the watch expression (string) 219 @param special special condition of the watch expression (string) 220 @param properties properties of the watch expression 221 (tuple of temporary flag (bool), enabled flag (bool), 222 ignore count (integer)) 223 """ 224 if index.isValid(): 225 row = index.row() 226 index1 = self.createIndex(row, 0, self.watchpoints[row]) 227 index2 = self.createIndex( 228 row, len(self.watchpoints[row]), self.watchpoints[row]) 229 self.dataAboutToBeChanged.emit(index1, index2) 230 self.watchpoints[row] = [cond, special] + list(properties) 231 self.dataChanged.emit(index1, index2) 232 233 def setWatchPointEnabledByIndex(self, index, enabled): 234 """ 235 Public method to set the enabled state of a watch expression given by 236 index. 237 238 @param index index of the watch expression (QModelIndex) 239 @param enabled flag giving the enabled state (boolean) 240 """ 241 if index.isValid(): 242 row = index.row() 243 col = 3 244 index1 = self.createIndex(row, col, self.watchpoints[row]) 245 self.dataAboutToBeChanged.emit(index1, index1) 246 self.watchpoints[row][col] = enabled 247 self.dataChanged.emit(index1, index1) 248 249 def deleteWatchPointByIndex(self, index): 250 """ 251 Public method to set the values of a watch expression given by index. 252 253 @param index index of the watch expression (QModelIndex) 254 """ 255 if index.isValid(): 256 row = index.row() 257 self.beginRemoveRows(QModelIndex(), row, row) 258 del self.watchpoints[row] 259 self.endRemoveRows() 260 261 def deleteWatchPoints(self, idxList): 262 """ 263 Public method to delete a list of watch expressions given by their 264 indexes. 265 266 @param idxList list of watch expression indexes (list of QModelIndex) 267 """ 268 rows = [] 269 for index in idxList: 270 if index.isValid(): 271 rows.append(index.row()) 272 rows.sort(reverse=True) 273 for row in rows: 274 if row < len(self.breakpoints): 275 self.beginRemoveRows(QModelIndex(), row, row) 276 del self.watchpoints[row] 277 self.endRemoveRows() 278 279 def deleteAll(self): 280 """ 281 Public method to delete all watch expressions. 282 """ 283 if self.watchpoints: 284 self.beginRemoveRows(QModelIndex(), 0, len(self.watchpoints) - 1) 285 self.watchpoints = [] 286 self.endRemoveRows() 287 288 def getWatchPointByIndex(self, index): 289 """ 290 Public method to get the values of a watch expression given by index. 291 292 @param index index of the watch expression (QModelIndex) 293 @return watch expression (list of six values (expression, 294 special condition, temporary flag, enabled flag, ignore count)) 295 @rtype tuple of (str, str, bool, bool, int) 296 """ 297 if index.isValid(): 298 return self.watchpoints[index.row()][:] # return a copy 299 else: 300 return [] 301 302 def getAllWatchpoints(self): 303 """ 304 Public method to get the list of watchpoints. 305 306 @return list of watchpoints 307 @rtype list of list of [str, str, bool, bool, int] 308 """ 309 return copy.deepcopy(self.watchpoints) 310 311 def getWatchPointIndex(self, cond, special=""): 312 """ 313 Public method to get the index of a watch expression given by 314 expression. 315 316 @param cond expression of the watch expression (string) 317 @param special special condition of the watch expression (string) 318 @return index (QModelIndex) 319 """ 320 for row in range(len(self.watchpoints)): 321 wp = self.watchpoints[row] 322 if wp[0] == cond: 323 if special and wp[1] != special: 324 continue 325 return self.createIndex(row, 0, self.watchpoints[row]) 326 327 return QModelIndex() 328