|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2006 - 2009 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the browser model. |
|
8 """ |
|
9 |
|
10 import sys |
|
11 import os |
|
12 import re |
|
13 |
|
14 from PyQt4.QtCore import * |
|
15 from PyQt4.QtGui import * |
|
16 |
|
17 from UI.BrowserModel import * |
|
18 |
|
19 import UI.PixmapCache |
|
20 import Preferences |
|
21 import Utilities |
|
22 |
|
23 import Utilities.ModuleParser |
|
24 |
|
25 ProjectBrowserItemSimpleDirectory = 100 |
|
26 ProjectBrowserItemDirectory = 101 |
|
27 ProjectBrowserItemFile = 102 |
|
28 |
|
29 ProjectBrowserNoType = 0 |
|
30 ProjectBrowserSourceType = 1 |
|
31 ProjectBrowserFormType = 2 |
|
32 ProjectBrowserInterfaceType = 3 |
|
33 ProjectBrowserTranslationType = 4 |
|
34 ProjectBrowserOthersType = 5 |
|
35 ProjectBrowserResourceType = 6 |
|
36 |
|
37 class ProjectBrowserItemMixin(object): |
|
38 """ |
|
39 Class implementing common methods of project browser items. |
|
40 |
|
41 It is meant to be used as a mixin class. |
|
42 """ |
|
43 def __init__(self, type_, bold = False): |
|
44 """ |
|
45 Constructor |
|
46 |
|
47 @param type_ type of file/directory in the project |
|
48 @param bold flag indicating a highlighted font |
|
49 """ |
|
50 self._projectTypes = [type_] |
|
51 self.bold = bold |
|
52 self.vcsState = " " |
|
53 |
|
54 def getTextColor(self): |
|
55 """ |
|
56 Public method to get the items text color. |
|
57 |
|
58 @return text color (QVariant(QColor)) |
|
59 """ |
|
60 if self.bold: |
|
61 return QVariant(Preferences.getProjectBrowserColour("Highlighted")) |
|
62 else: |
|
63 return QVariant() |
|
64 |
|
65 def setVcsState(self, state): |
|
66 """ |
|
67 Public method to set the items VCS state. |
|
68 |
|
69 @param state VCS state (one of A, C, M, U or " ") (string) |
|
70 """ |
|
71 self.vcsState = state |
|
72 |
|
73 def addVcsStatus(self, vcsStatus): |
|
74 """ |
|
75 Public method to add the VCS status. |
|
76 |
|
77 @param vcsStatus VCS status text (string) |
|
78 """ |
|
79 self.itemData.append(vcsStatus) |
|
80 |
|
81 def setVcsStatus(self, vcsStatus): |
|
82 """ |
|
83 Public method to set the VCS status. |
|
84 |
|
85 @param vcsStatus VCS status text (string) |
|
86 """ |
|
87 self.itemData[1] = vcsStatus |
|
88 |
|
89 def getProjectTypes(self): |
|
90 """ |
|
91 Public method to get the project type. |
|
92 |
|
93 @return project type |
|
94 """ |
|
95 return self._projectTypes[:] |
|
96 |
|
97 def addProjectType(self, type_): |
|
98 """ |
|
99 Public method to add a type to the list. |
|
100 |
|
101 @param type_ type to add to the list |
|
102 """ |
|
103 self._projectTypes.append(type_) |
|
104 |
|
105 class ProjectBrowserSimpleDirectoryItem(BrowserItem, ProjectBrowserItemMixin): |
|
106 """ |
|
107 Class implementing the data structure for project browser simple directory items. |
|
108 """ |
|
109 def __init__(self, parent, projectType, text, path = ""): |
|
110 """ |
|
111 Constructor |
|
112 |
|
113 @param parent parent item |
|
114 @param projectType type of file/directory in the project |
|
115 @param text text to be displayed (string) |
|
116 @param path path of the directory (string) |
|
117 """ |
|
118 BrowserItem.__init__(self, parent, text) |
|
119 ProjectBrowserItemMixin.__init__(self, projectType) |
|
120 |
|
121 self._dirName = path |
|
122 if not os.path.isdir(self._dirName): |
|
123 self._dirName = os.path.dirname(self._dirName) |
|
124 |
|
125 self.type_ = ProjectBrowserItemSimpleDirectory |
|
126 self.icon = UI.PixmapCache.getIcon("dirClosed.png") |
|
127 |
|
128 def dirName(self): |
|
129 """ |
|
130 Public method returning the directory name. |
|
131 |
|
132 @return directory name (string) |
|
133 """ |
|
134 return self._dirName |
|
135 |
|
136 def lessThan(self, other, column, order): |
|
137 """ |
|
138 Public method to check, if the item is less than the other one. |
|
139 |
|
140 @param other reference to item to compare against (BrowserItem) |
|
141 @param column column number to use for the comparison (integer) |
|
142 @param order sort order (Qt.SortOrder) (for special sorting) |
|
143 @return true, if this item is less than other (boolean) |
|
144 """ |
|
145 if issubclass(other.__class__, BrowserFileItem): |
|
146 if Preferences.getUI("BrowsersListFoldersFirst"): |
|
147 return order == Qt.AscendingOrder |
|
148 |
|
149 return BrowserItem.lessThan(self, other, column, order) |
|
150 |
|
151 class ProjectBrowserDirectoryItem(BrowserDirectoryItem, ProjectBrowserItemMixin): |
|
152 """ |
|
153 Class implementing the data structure for project browser directory items. |
|
154 """ |
|
155 def __init__(self, parent, dinfo, projectType, full = True, bold = False): |
|
156 """ |
|
157 Constructor |
|
158 |
|
159 @param parent parent item |
|
160 @param dinfo dinfo is the string for the directory (string) |
|
161 @param projectType type of file/directory in the project |
|
162 @param full flag indicating full pathname should be displayed (boolean) |
|
163 @param bold flag indicating a highlighted font (boolean) |
|
164 """ |
|
165 BrowserDirectoryItem.__init__(self, parent, dinfo, full) |
|
166 ProjectBrowserItemMixin.__init__(self, projectType, bold) |
|
167 |
|
168 self.type_ = ProjectBrowserItemDirectory |
|
169 |
|
170 class ProjectBrowserFileItem(BrowserFileItem, ProjectBrowserItemMixin): |
|
171 """ |
|
172 Class implementing the data structure for project browser file items. |
|
173 """ |
|
174 def __init__(self, parent, finfo, projectType, full = True, bold = False, |
|
175 sourceLanguage = ""): |
|
176 """ |
|
177 Constructor |
|
178 |
|
179 @param parent parent item |
|
180 @param finfo the string for the file (string) |
|
181 @param projectType type of file/directory in the project |
|
182 @param full flag indicating full pathname should be displayed (boolean) |
|
183 @param bold flag indicating a highlighted font (boolean) |
|
184 @param sourceLanguage source code language of the project (string) |
|
185 """ |
|
186 BrowserFileItem.__init__(self, parent, finfo, full, sourceLanguage) |
|
187 ProjectBrowserItemMixin.__init__(self, projectType, bold) |
|
188 |
|
189 self.type_ = ProjectBrowserItemFile |
|
190 |
|
191 class ProjectBrowserModel(BrowserModel): |
|
192 """ |
|
193 Class implementing the project browser model. |
|
194 |
|
195 @signal vcsStateChanged(QString) emitted after the VCS state has changed |
|
196 """ |
|
197 def __init__(self, parent): |
|
198 """ |
|
199 Constructor |
|
200 |
|
201 @param parent reference to parent object (Project.Project) |
|
202 """ |
|
203 QAbstractItemModel.__init__(self, parent) |
|
204 |
|
205 rootData = QVariant(self.trUtf8("Name")) |
|
206 self.rootItem = BrowserItem(None, rootData) |
|
207 self.rootItem.itemData.append(QVariant(self.trUtf8("VCS Status"))) |
|
208 |
|
209 self.progDir = None |
|
210 self.project = parent |
|
211 |
|
212 self.inRefresh = False |
|
213 |
|
214 self.projectBrowserTypes = { |
|
215 "SOURCES" : ProjectBrowserSourceType, |
|
216 "FORMS" : ProjectBrowserFormType, |
|
217 "RESOURCES" : ProjectBrowserResourceType, |
|
218 "INTERFACES" : ProjectBrowserInterfaceType, |
|
219 "TRANSLATIONS" : ProjectBrowserTranslationType, |
|
220 "OTHERS" : ProjectBrowserOthersType, |
|
221 } |
|
222 |
|
223 self.colorNames = { |
|
224 "A" : "VcsAdded", |
|
225 "M" : "VcsModified", |
|
226 "R" : "VcsReplaced", |
|
227 "U" : "VcsUpdate", |
|
228 "Z" : "VcsConflict", |
|
229 } |
|
230 self.itemBackgroundColors = { |
|
231 " " : QColor(), |
|
232 "A" : Preferences.getProjectBrowserColour(self.colorNames["A"]), |
|
233 "M" : Preferences.getProjectBrowserColour(self.colorNames["M"]), |
|
234 "R" : Preferences.getProjectBrowserColour(self.colorNames["R"]), |
|
235 "U" : Preferences.getProjectBrowserColour(self.colorNames["U"]), |
|
236 "Z" : Preferences.getProjectBrowserColour(self.colorNames["Z"]), |
|
237 } |
|
238 |
|
239 self.highLightColor = Preferences.getProjectBrowserColour("Highlighted") |
|
240 # needed by preferencesChanged() |
|
241 |
|
242 self.vcsStatusReport = {} |
|
243 |
|
244 def data(self, index, role): |
|
245 """ |
|
246 Public method to get data of an item. |
|
247 |
|
248 @param index index of the data to retrieve (QModelIndex) |
|
249 @param role role of data (Qt.ItemDataRole) |
|
250 @return requested data (QVariant) |
|
251 """ |
|
252 if not index.isValid(): |
|
253 return QVariant() |
|
254 |
|
255 if role == Qt.TextColorRole: |
|
256 if index.column() == 0: |
|
257 try: |
|
258 return index.internalPointer().getTextColor() |
|
259 except AttributeError: |
|
260 return QVariant() |
|
261 elif role == Qt.BackgroundColorRole: |
|
262 try: |
|
263 col = self.itemBackgroundColors[index.internalPointer().vcsState] |
|
264 if col.isValid(): |
|
265 return QVariant(col) |
|
266 else: |
|
267 return QVariant() |
|
268 except AttributeError: |
|
269 return QVariant() |
|
270 except KeyError: |
|
271 return QVariant() |
|
272 |
|
273 return BrowserModel.data(self, index, role) |
|
274 |
|
275 def populateItem(self, parentItem, repopulate = False): |
|
276 """ |
|
277 Public method to populate an item's subtree. |
|
278 |
|
279 @param parentItem reference to the item to be populated |
|
280 @param repopulate flag indicating a repopulation (boolean) |
|
281 """ |
|
282 if parentItem.type() == ProjectBrowserItemSimpleDirectory: |
|
283 return # nothing to do |
|
284 elif parentItem.type() == ProjectBrowserItemDirectory: |
|
285 self.populateProjectDirectoryItem(parentItem, repopulate) |
|
286 elif parentItem.type() == ProjectBrowserItemFile: |
|
287 self.populateFileItem(parentItem, repopulate) |
|
288 else: |
|
289 BrowserModel.populateItem(self, parentItem, repopulate) |
|
290 |
|
291 def populateProjectDirectoryItem(self, parentItem, repopulate = False): |
|
292 """ |
|
293 Public method to populate a directory item's subtree. |
|
294 |
|
295 @param parentItem reference to the directory item to be populated |
|
296 @param repopulate flag indicating a repopulation (boolean) |
|
297 """ |
|
298 qdir = QDir(parentItem.dirName()) |
|
299 |
|
300 entryInfoList = \ |
|
301 qdir.entryInfoList(QDir.Filters(QDir.AllEntries | QDir.NoDotAndDotDot)) |
|
302 |
|
303 if len(entryInfoList) > 0: |
|
304 if repopulate: |
|
305 self.beginInsertRows(self.createIndex(parentItem.row(), 0, parentItem), |
|
306 0, len(entryInfoList) - 1) |
|
307 states = {} |
|
308 if self.project.vcs is not None: |
|
309 for f in entryInfoList: |
|
310 fname = f.absoluteFilePath() |
|
311 states[os.path.normcase(fname)] = 0 |
|
312 dname = parentItem.dirName() |
|
313 self.project.vcs.clearStatusCache() |
|
314 states = self.project.vcs.vcsAllRegisteredStates(states, dname) |
|
315 |
|
316 for f in entryInfoList: |
|
317 if f.isDir(): |
|
318 node = ProjectBrowserDirectoryItem(parentItem, |
|
319 Utilities.toNativeSeparators(f.absoluteFilePath()), |
|
320 parentItem.getProjectTypes()[0], False) |
|
321 else: |
|
322 node = ProjectBrowserFileItem(parentItem, |
|
323 Utilities.toNativeSeparators(f.absoluteFilePath()), |
|
324 parentItem.getProjectTypes()[0]) |
|
325 if self.project.vcs is not None: |
|
326 fname = f.absoluteFilePath() |
|
327 if states[os.path.normcase(fname)] == self.project.vcs.canBeCommitted: |
|
328 node.addVcsStatus(self.project.vcs.vcsName()) |
|
329 self.project.clearStatusMonitorCachedState(f.absoluteFilePath()) |
|
330 else: |
|
331 node.addVcsStatus(self.trUtf8("local")) |
|
332 self._addItem(node, parentItem) |
|
333 if repopulate: |
|
334 self.endInsertRows() |
|
335 |
|
336 def projectClosed(self): |
|
337 """ |
|
338 Public method called after a project has been closed. |
|
339 """ |
|
340 self.__vcsStatus = {} |
|
341 |
|
342 self.rootItem.removeChildren() |
|
343 self.reset() |
|
344 |
|
345 # reset the module parser cache |
|
346 Utilities.ModuleParser.resetParsedModules() |
|
347 |
|
348 def projectOpened(self): |
|
349 """ |
|
350 Public method used to populate the model after a project has been opened. |
|
351 """ |
|
352 self.__vcsStatus = {} |
|
353 states = {} |
|
354 keys = self.projectBrowserTypes.keys()[:] |
|
355 |
|
356 if self.project.vcs is not None: |
|
357 for key in keys: |
|
358 for fn in self.project.pdata[key]: |
|
359 states[os.path.normcase(os.path.join(self.project.ppath, fn))] = 0 |
|
360 |
|
361 self.project.vcs.clearStatusCache() |
|
362 for dir in self.project.subdirs: |
|
363 states = self.project.vcs.vcsAllRegisteredStates(states, |
|
364 os.path.join(self.project.ppath, dir)) |
|
365 |
|
366 for dir in self.project.otherssubdirs: |
|
367 if not os.path.isabs(dir): |
|
368 dir = os.path.join(self.project.ppath, dir) |
|
369 states = self.project.vcs.vcsAllRegisteredStates(states, dir) |
|
370 |
|
371 if self.project.pdata["TRANSLATIONPATTERN"]: |
|
372 dir = os.path.join(self.project.ppath, |
|
373 self.project.pdata["TRANSLATIONPATTERN"][0])\ |
|
374 .split("%language%")[0] |
|
375 if not os.path.isdir(dir): |
|
376 dir = os.path.dirname(dir) |
|
377 states = self.project.vcs.vcsAllRegisteredStates(states, dir) |
|
378 |
|
379 self.inRefresh = True |
|
380 for key in keys: |
|
381 # Show the entry in bold in the others browser to make it more distinguishable |
|
382 if key == "OTHERS": |
|
383 bold = True |
|
384 else: |
|
385 bold = False |
|
386 |
|
387 if key == "SOURCES": |
|
388 sourceLanguage = self.project.pdata["PROGLANGUAGE"][0] |
|
389 else: |
|
390 sourceLanguage = "" |
|
391 |
|
392 for fn in self.project.pdata[key]: |
|
393 fname = os.path.join(self.project.ppath, fn) |
|
394 parentItem, dt = \ |
|
395 self.findParentItemByName(self.projectBrowserTypes[key], fn) |
|
396 if os.path.isdir(fname): |
|
397 itm = ProjectBrowserDirectoryItem(parentItem, fname, |
|
398 self.projectBrowserTypes[key], False, bold) |
|
399 else: |
|
400 itm = ProjectBrowserFileItem(parentItem, fname, |
|
401 self.projectBrowserTypes[key], False, bold, |
|
402 sourceLanguage = sourceLanguage) |
|
403 self._addItem(itm, parentItem) |
|
404 if self.project.vcs is not None: |
|
405 if states[os.path.normcase(fname)] == self.project.vcs.canBeCommitted: |
|
406 itm.addVcsStatus(self.project.vcs.vcsName()) |
|
407 else: |
|
408 itm.addVcsStatus(self.trUtf8("local")) |
|
409 else: |
|
410 itm.addVcsStatus("") |
|
411 self.inRefresh = False |
|
412 self.reset() |
|
413 |
|
414 def findParentItemByName(self, type_, name, dontSplit = False): |
|
415 """ |
|
416 Public method to find an item given it's name. |
|
417 |
|
418 <b>Note</b>: This method creates all necessary parent items, if they |
|
419 don't exist. |
|
420 |
|
421 @param type_ type of the item |
|
422 @param name name of the item (string) |
|
423 @param dontSplit flag indicating the name should not be split (boolean) |
|
424 @return reference to the item found and the new display name (string) |
|
425 """ |
|
426 if dontSplit: |
|
427 pathlist = [] |
|
428 pathlist.append(name) |
|
429 pathlist.append("ignore_me") |
|
430 else: |
|
431 pathlist = re.split(r'/|\\', name) |
|
432 |
|
433 if len(pathlist) > 1: |
|
434 olditem = self.rootItem |
|
435 path = self.project.ppath |
|
436 for p in pathlist[:-1]: |
|
437 itm = self.findChildItem(p, 0, olditem) |
|
438 path = os.path.join(path, p) |
|
439 if itm is None: |
|
440 itm = ProjectBrowserSimpleDirectoryItem(olditem, type_, p, path) |
|
441 self.__addVCSStatus(itm, path) |
|
442 if self.inRefresh: |
|
443 self._addItem(itm, olditem) |
|
444 else: |
|
445 if olditem == self.rootItem: |
|
446 oldindex = QModelIndex() |
|
447 else: |
|
448 oldindex = self.createIndex(olditem.row(), 0, olditem) |
|
449 self.addItem(itm, oldindex) |
|
450 else: |
|
451 if type_ and type_ not in itm.getProjectTypes(): |
|
452 itm.addProjectType(type_) |
|
453 index = self.createIndex(itm.row(), 0, itm) |
|
454 self.emit(SIGNAL(\ |
|
455 "dataChanged(const QModelIndex &, const QModelIndex &)"), |
|
456 index, index) |
|
457 olditem = itm |
|
458 return (itm, pathlist[-1]) |
|
459 else: |
|
460 return (self.rootItem, name) |
|
461 |
|
462 def findChildItem(self, text, column, parentItem = None): |
|
463 """ |
|
464 Public method to find a child item given some text. |
|
465 |
|
466 @param text text to search for (string) |
|
467 @param column column to search in (integer) |
|
468 @param parentItem reference to parent item |
|
469 @return reference to the item found |
|
470 """ |
|
471 if parentItem is None: |
|
472 parentItem = self.rootItem |
|
473 |
|
474 for itm in parentItem.children(): |
|
475 if itm.data(column) == text: |
|
476 return itm |
|
477 |
|
478 return None |
|
479 |
|
480 def addNewItem(self, typeString, name, additionalTypeStrings = []): |
|
481 """ |
|
482 Public method to add a new item to the model. |
|
483 |
|
484 @param typeString string denoting the type of the new item (string) |
|
485 @param name name of the new item (string) |
|
486 @param additionalTypeStrings names of additional types (list of string) |
|
487 """ |
|
488 # Show the entry in bold in the others browser to make it more distinguishable |
|
489 if typeString == "OTHERS": |
|
490 bold = True |
|
491 else: |
|
492 bold = False |
|
493 |
|
494 fname = os.path.join(self.project.ppath, name) |
|
495 parentItem, dt = \ |
|
496 self.findParentItemByName(self.projectBrowserTypes[typeString], name) |
|
497 if parentItem == self.rootItem: |
|
498 parentIndex = QModelIndex() |
|
499 else: |
|
500 parentIndex = self.createIndex(parentItem.row(), 0, parentItem) |
|
501 if os.path.isdir(fname): |
|
502 itm = ProjectBrowserDirectoryItem(parentItem, fname, |
|
503 self.projectBrowserTypes[typeString], False, bold) |
|
504 else: |
|
505 if typeString == "SOURCES": |
|
506 sourceLanguage = self.project.pdata["PROGLANGUAGE"][0] |
|
507 else: |
|
508 sourceLanguage = "" |
|
509 itm = ProjectBrowserFileItem(parentItem, fname, |
|
510 self.projectBrowserTypes[typeString], False, bold, |
|
511 sourceLanguage = sourceLanguage) |
|
512 self.__addVCSStatus(itm, fname) |
|
513 if additionalTypeStrings: |
|
514 for additionalTypeString in additionalTypeStrings: |
|
515 type_ = self.projectBrowserTypes[additionalTypeString] |
|
516 itm.addProjectType(type_) |
|
517 self.addItem(itm, parentIndex) |
|
518 |
|
519 def renameItem(self, name, newFilename): |
|
520 """ |
|
521 Public method to rename an item. |
|
522 |
|
523 @param name the old display name (string) |
|
524 @param newFilename new filename of the item (string) |
|
525 """ |
|
526 itm = self.findItem(name) |
|
527 if itm is None: |
|
528 return |
|
529 |
|
530 index = self.createIndex(itm.row(), 0, itm) |
|
531 itm.setName(newFilename) |
|
532 self.emit(SIGNAL("dataChanged(const QModelIndex &, const QModelIndex &)"), |
|
533 index, index) |
|
534 self.repopulateItem(newFilename) |
|
535 |
|
536 def findItem(self, name): |
|
537 """ |
|
538 Public method to find an item given it's name. |
|
539 |
|
540 @param name name of the item (string) |
|
541 @return reference to the item found |
|
542 """ |
|
543 if QDir.isAbsolutePath(name): |
|
544 name.replace(self.project.ppath + os.sep, "") |
|
545 pathlist = re.split(r'/|\\', name) |
|
546 if len(pathlist) > 0: |
|
547 olditem = self.rootItem |
|
548 for p in pathlist: |
|
549 itm = self.findChildItem(p, 0, olditem) |
|
550 if itm is None: |
|
551 return None |
|
552 olditem = itm |
|
553 return itm |
|
554 else: |
|
555 return None |
|
556 |
|
557 def itemIndexByName(self, name): |
|
558 """ |
|
559 Public method to find an item's index given it's name. |
|
560 |
|
561 @param name name of the item (string) |
|
562 @return index of the item found (QModelIndex) |
|
563 """ |
|
564 itm = self.findItem(name) |
|
565 if itm is None: |
|
566 index = QModelIndex() |
|
567 else: |
|
568 index = self.createIndex(itm.row(), 0, itm) |
|
569 return index |
|
570 |
|
571 def __addVCSStatus(self, item, name): |
|
572 """ |
|
573 Private method used to set the vcs status of a node. |
|
574 |
|
575 @param item item to work on |
|
576 @param name filename belonging to this item (string) |
|
577 """ |
|
578 if self.project.vcs is not None: |
|
579 state = self.project.vcs.vcsRegisteredState(name) |
|
580 if state == self.project.vcs.canBeCommitted: |
|
581 item.addVcsStatus(self.project.vcs.vcsName()) |
|
582 else: |
|
583 item.addVcsStatus(self.trUtf8("local")) |
|
584 else: |
|
585 item.addVcsStatus("") |
|
586 |
|
587 def __updateVCSStatus(self, item, name, recursive = True): |
|
588 """ |
|
589 Private method used to update the vcs status of a node. |
|
590 |
|
591 @param item item to work on |
|
592 @param name filename belonging to this item (string) |
|
593 @param recursive flag indicating a recursive update (boolean) |
|
594 """ |
|
595 if self.project.vcs is not None: |
|
596 self.project.vcs.clearStatusCache() |
|
597 state = self.project.vcs.vcsRegisteredState(name) |
|
598 if state == self.project.vcs.canBeCommitted: |
|
599 item.setVcsStatus(self.project.vcs.vcsName()) |
|
600 else: |
|
601 item.setVcsStatus(self.trUtf8("local")) |
|
602 if recursive: |
|
603 name = os.path.dirname(name) |
|
604 parentItem = item.parent() |
|
605 if name and parentItem is not self.rootItem: |
|
606 self.__updateVCSStatus(parentItem, name, recursive) |
|
607 else: |
|
608 item.setVcsStatus("") |
|
609 |
|
610 index = self.createIndex(item.row(), 0, item) |
|
611 self.emit(SIGNAL("dataChanged(const QModelIndex &, const QModelIndex &)"), |
|
612 index, index) |
|
613 |
|
614 def updateVCSStatus(self, name, recursive = True): |
|
615 """ |
|
616 Public method used to update the vcs status of a node. |
|
617 |
|
618 @param name filename belonging to this item (string) |
|
619 @param recursive flag indicating a recursive update (boolean) |
|
620 """ |
|
621 item = self.findItem(name) |
|
622 if item: |
|
623 self.__updateVCSStatus(item, name, recursive) |
|
624 |
|
625 def removeItem(self, name): |
|
626 """ |
|
627 Public method to remove a named item. |
|
628 |
|
629 @param name file or directory name of the item (string). |
|
630 """ |
|
631 fname = os.path.basename(name) |
|
632 parentItem = self.findParentItemByName(0, name)[0] |
|
633 if parentItem == self.rootItem: |
|
634 parentIndex = QModelIndex() |
|
635 else: |
|
636 parentIndex = self.createIndex(parentItem.row(), 0, parentItem) |
|
637 childItem = self.findChildItem(fname, 0, parentItem) |
|
638 if childItem is not None: |
|
639 self.beginRemoveRows(parentIndex, childItem.row(), childItem.row()) |
|
640 parentItem.removeChild(childItem) |
|
641 self.endRemoveRows() |
|
642 |
|
643 def repopulateItem(self, name): |
|
644 """ |
|
645 Public method to repopulate an item. |
|
646 |
|
647 @param name name of the file relative to the project root (string) |
|
648 """ |
|
649 itm = self.findItem(name) |
|
650 if itm is None: |
|
651 return |
|
652 |
|
653 if itm.isLazyPopulated() and not itm.isPopulated(): |
|
654 # item is not populated yet, nothing to do |
|
655 return |
|
656 |
|
657 if itm.childCount(): |
|
658 index = self.createIndex(itm.row(), 0, itm) |
|
659 self.beginRemoveRows(index, 0, itm.childCount() - 1) |
|
660 itm.removeChildren() |
|
661 self.endRemoveRows() |
|
662 Utilities.ModuleParser.resetParsedModule(\ |
|
663 os.path.join(self.project.ppath, name)) |
|
664 |
|
665 self.populateItem(itm, True) |
|
666 |
|
667 def projectPropertiesChanged(self): |
|
668 """ |
|
669 Public method to react on a change of the project properties. |
|
670 """ |
|
671 # nothing to do for now |
|
672 return |
|
673 |
|
674 def changeVCSStates(self, statesList): |
|
675 """ |
|
676 Public slot to record the (non normal) VCS states. |
|
677 |
|
678 @param statesList list of VCS state entries (list of strings) giving the |
|
679 states in the first column and the path relative to the project |
|
680 directory starting with the third column. The allowed status flags |
|
681 are: |
|
682 <ul> |
|
683 <li>"A" path was added but not yet comitted</li> |
|
684 <li>"M" path has local changes</li> |
|
685 <li>"R" path was deleted and then re-added</li> |
|
686 <li>"U" path needs an update</li> |
|
687 <li>"Z" path contains a conflict</li> |
|
688 <li>" " path is back at normal</li> |
|
689 </ul> |
|
690 """ |
|
691 statesList.sort() |
|
692 lastHead = "" |
|
693 itemCache = {} |
|
694 if len(statesList) == 1 and statesList[0] == '--RESET--': |
|
695 statesList = [] |
|
696 for name in self.__vcsStatus.keys(): |
|
697 statesList.append(" %s" % name) |
|
698 |
|
699 for name in statesList: |
|
700 state = name[0] |
|
701 name = name[1:].strip() |
|
702 if state == ' ': |
|
703 if name in self.__vcsStatus: |
|
704 del self.__vcsStatus[name] |
|
705 else: |
|
706 self.__vcsStatus[name] = state |
|
707 |
|
708 try: |
|
709 itm = itemCache[name] |
|
710 except KeyError: |
|
711 itm = self.findItem(name) |
|
712 if itm: |
|
713 itemCache[name] = itm |
|
714 if itm: |
|
715 itm.setVcsState(state) |
|
716 index1 = self.createIndex(itm.row(), 0, itm) |
|
717 index2 = self.createIndex(itm.row(), |
|
718 self.rootItem.columnCount(), itm) |
|
719 self.emit(\ |
|
720 SIGNAL("dataChanged(const QModelIndex &, const QModelIndex &)"), |
|
721 index1, index2) |
|
722 |
|
723 head, tail = os.path.split(name) |
|
724 if head != lastHead: |
|
725 if lastHead: |
|
726 self.__changeParentsVCSState(lastHead, itemCache) |
|
727 lastHead = head |
|
728 if lastHead: |
|
729 self.__changeParentsVCSState(lastHead, itemCache) |
|
730 try: |
|
731 globalVcsStatus = sorted(self.__vcsStatus.values())[-1] |
|
732 except IndexError: |
|
733 globalVcsStatus = ' ' |
|
734 self.emit(SIGNAL("vcsStateChanged"), globalVcsStatus) |
|
735 |
|
736 def __changeParentsVCSState(self, path, itemCache): |
|
737 """ |
|
738 Private method to recursively change the parents VCS state. |
|
739 |
|
740 @param path pathname of parent item (string) |
|
741 @param itemCache reference to the item cache used to store |
|
742 references to named items |
|
743 """ |
|
744 while path: |
|
745 try: |
|
746 itm = itemCache[path] |
|
747 except KeyError: |
|
748 itm = self.findItem(path) |
|
749 if itm: |
|
750 itemCache[path] = itm |
|
751 if itm: |
|
752 state = " " |
|
753 for id_ in itm.children(): |
|
754 if state < id_.vcsState: |
|
755 state = id_.vcsState |
|
756 if state != itm.vcsState: |
|
757 itm.setVcsState(state) |
|
758 index1 = self.createIndex(itm.row(), 0, itm) |
|
759 index2 = self.createIndex(itm.row(), |
|
760 self.rootItem.columnCount(), itm) |
|
761 self.emit(\ |
|
762 SIGNAL("dataChanged(const QModelIndex &, const QModelIndex &)"), |
|
763 index1, index2) |
|
764 path, tail = os.path.split(path) |
|
765 |
|
766 def preferencesChanged(self): |
|
767 """ |
|
768 Public method used to handle a change in preferences. |
|
769 """ |
|
770 for code in self.colorNames.keys(): |
|
771 color = Preferences.getProjectBrowserColour(self.colorNames[code]) |
|
772 if color.name() == self.itemBackgroundColors[code].name(): |
|
773 continue |
|
774 |
|
775 self.itemBackgroundColors[code] = color |
|
776 |
|
777 color = Preferences.getProjectBrowserColour("Highlighted") |
|
778 if self.highLightColor.name() != color.name(): |
|
779 self.highLightColor = color |