Mon, 26 Dec 2011 19:31:22 +0100
Updated copyright for 2012.
# -*- coding: utf-8 -*- # Copyright (c) 2006 - 2012 Detlev Offenbach <detlev@die-offenbachs.de> # """ Module implementing the browser model. """ import sys import os import fnmatch from PyQt4.QtCore import QDir, QModelIndex, QAbstractItemModel, QFileSystemWatcher, Qt from PyQt4.QtGui import QImageReader, QApplication, QFont import Utilities.ClassBrowsers import Utilities.ClassBrowsers.ClbrBaseClasses import UI.PixmapCache import Preferences import Utilities BrowserItemRoot = 0 BrowserItemDirectory = 1 BrowserItemSysPath = 2 BrowserItemFile = 3 BrowserItemClass = 4 BrowserItemMethod = 5 BrowserItemAttributes = 6 BrowserItemAttribute = 7 BrowserItemCoding = 8 class BrowserModel(QAbstractItemModel): """ Class implementing the browser model. """ def __init__(self, parent=None): """ Constructor @param parent reference to parent object (QObject) """ super().__init__(parent) rootData = QApplication.translate("BrowserModel", "Name") self.rootItem = BrowserItem(None, rootData) self.progDir = None self.watchedItems = {} self.watcher = QFileSystemWatcher(self) self.watcher.directoryChanged.connect(self.directoryChanged) self.__populateModel() def columnCount(self, parent=QModelIndex()): """ Public method to get the number of columns. @param parent index of parent item (QModelIndex) @return number of columns (integer) """ if parent.isValid(): item = parent.internalPointer() else: item = self.rootItem return item.columnCount() + 1 def data(self, index, role): """ Public method to get data of an item. @param index index of the data to retrieve (QModelIndex) @param role role of data (Qt.ItemDataRole) @return requested data """ if not index.isValid(): return None if role == Qt.DisplayRole: item = index.internalPointer() if index.column() < item.columnCount(): return item.data(index.column()) elif index.column() == item.columnCount() and \ index.column() < self.columnCount(self.parent(index)): # This is for the case where an item under a multi-column parent # doesn't have a value for all the columns return "" elif role == Qt.DecorationRole: if index.column() == 0: return index.internalPointer().getIcon() elif role == Qt.FontRole: item = index.internalPointer() if item.isSymlink(): font = QFont(QApplication.font("QTreeView")) font.setItalic(True) return font return None def flags(self, index): """ Public method to get the item flags. @param index index of the data to retrieve (QModelIndex) @return requested flags (Qt.ItemFlags) """ if not index.isValid(): return Qt.ItemIsEnabled return Qt.ItemIsEnabled | Qt.ItemIsSelectable def headerData(self, section, orientation, role=Qt.DisplayRole): """ Public method to get the header data. @param section number of section to get data for (integer) @param orientation header orientation (Qt.Orientation) @param role role of data (Qt.ItemDataRole) @return requested header data """ if orientation == Qt.Horizontal and role == Qt.DisplayRole: if section >= self.rootItem.columnCount(): return "" else: return self.rootItem.data(section) return None def index(self, row, column, parent=QModelIndex()): """ Public method to create an index. @param row row number of the new index (integer) @param column column number of the new index (integer) @param parent index of parent item (QModelIndex) @return index object (QModelIndex) """ # The model/view framework considers negative values out-of-bounds, # however in python they work when indexing into lists. So make sure # we return an invalid index for out-of-bounds row/col if row < 0 or column < 0 or \ row >= self.rowCount(parent) or column >= self.columnCount(parent): return QModelIndex() if not parent.isValid(): parentItem = self.rootItem else: parentItem = parent.internalPointer() try: if not parentItem.isPopulated(): self.populateItem(parentItem) childItem = parentItem.child(row) except IndexError: childItem = None if childItem: return self.createIndex(row, column, childItem) else: return QModelIndex() def parent(self, index): """ Public method to get the index of the parent object. @param index index of the item (QModelIndex) @return index of parent item (QModelIndex) """ if not index.isValid(): return QModelIndex() childItem = index.internalPointer() parentItem = childItem.parent() if parentItem == self.rootItem: return QModelIndex() return self.createIndex(parentItem.row(), 0, parentItem) def rowCount(self, parent=QModelIndex()): """ Public method to get the number of rows. @param parent index of parent item (QModelIndex) @return number of rows (integer) """ # Only the first column should have children if parent.column() > 0: return 0 if not parent.isValid(): parentItem = self.rootItem else: parentItem = parent.internalPointer() if not parentItem.isPopulated(): # lazy population self.populateItem(parentItem) return parentItem.childCount() def hasChildren(self, parent=QModelIndex()): """ Public method to check for the presence of child items. We always return True for normal items in order to do lazy population of the tree. @param parent index of parent item (QModelIndex) @return flag indicating the presence of child items (boolean) """ # Only the first column should have children if parent.column() > 0: return 0 if not parent.isValid(): return self.rootItem.childCount() > 0 if parent.internalPointer().isLazyPopulated(): return True else: return parent.internalPointer().childCount() > 0 def clear(self): """ Public method to clear the model. """ self.rootItem.removeChildren() self.reset() def item(self, index): """ Public method to get a reference to an item. @param index index of the data to retrieve (QModelIndex) @return requested item reference (BrowserItem) """ if not index.isValid(): return None return index.internalPointer() def _addWatchedItem(self, itm): """ Protected method to watch an item. @param itm item to be watched (BrowserDirectoryItem) """ if isinstance(itm, BrowserDirectoryItem): dirName = itm.dirName() if dirName != "" and \ not dirName.startswith("//") and \ not dirName.startswith("\\\\"): if dirName not in self.watcher.directories(): self.watcher.addPath(dirName) if dirName in self.watchedItems: if itm not in self.watchedItems[dirName]: self.watchedItems[dirName].append(itm) else: self.watchedItems[dirName] = [itm] def _removeWatchedItem(self, itm): """ Protected method to remove a watched item. @param itm item to be removed (BrowserDirectoryItem) """ if isinstance(itm, BrowserDirectoryItem): dirName = itm.dirName() if dirName in self.watchedItems: if itm in self.watchedItems[dirName]: self.watchedItems[dirName].remove(itm) if len(self.watchedItems[dirName]) == 0: del self.watchedItems[dirName] self.watcher.removePath(dirName) def directoryChanged(self, path): """ Public slot to handle the directoryChanged signal of the watcher. @param path path of the directory (string) """ if path not in self.watchedItems: # just ignore the situation we don't have a reference to the item return if Preferences.getUI("BrowsersListHiddenFiles"): filter = QDir.Filters(QDir.AllEntries | QDir.Hidden | QDir.NoDotAndDotDot) else: filter = QDir.Filters(QDir.AllEntries | QDir.NoDotAndDotDot) for itm in self.watchedItems[path]: oldCnt = itm.childCount() qdir = QDir(itm.dirName()) entryInfoList = qdir.entryInfoList(filter) # step 1: check for new entries children = itm.children() for f in entryInfoList: fpath = f.absoluteFilePath() childFound = False for child in children: if child.name() == fpath: childFound = True children.remove(child) break if childFound: continue cnt = itm.childCount() self.beginInsertRows(self.createIndex(itm.row(), 0, itm), cnt, cnt) if f.isDir(): node = BrowserDirectoryItem(itm, Utilities.toNativeSeparators(f.absoluteFilePath()), False) else: node = BrowserFileItem(itm, Utilities.toNativeSeparators(f.absoluteFilePath())) self._addItem(node, itm) self.endInsertRows() # step 2: check for removed entries if len(entryInfoList) != itm.childCount(): for row in range(oldCnt - 1, -1, -1): child = itm.child(row) entryFound = False for f in entryInfoList: if f.absoluteFilePath() == child.name(): entryFound = True entryInfoList.remove(f) break if entryFound: continue self._removeWatchedItem(child) self.beginRemoveRows(self.createIndex(itm.row(), 0, itm), row, row) itm.removeChild(child) self.endRemoveRows() def __populateModel(self): """ Private method to populate the browser model. """ self._addItem(BrowserSysPathItem(self.rootItem), self.rootItem) self.toplevelDirs = [] tdp = Preferences.Prefs.settings.value('BrowserModel/ToplevelDirs') if tdp: self.toplevelDirs = tdp else: self.toplevelDirs.append(Utilities.toNativeSeparators(QDir.homePath())) for d in QDir.drives(): self.toplevelDirs.append(Utilities.toNativeSeparators( d.absoluteFilePath())) for d in self.toplevelDirs: itm = BrowserDirectoryItem(self.rootItem, d) self._addItem(itm, self.rootItem) def programChange(self, dirname): """ Public method to change the entry for the directory of file being debugged. @param dirname name of the directory containing the file (string) """ if self.progDir: if dirname == self.progDir.dirName(): return # remove old entry self._removeWatchedItem(self.progDir) self.beginRemoveRows(QModelIndex(), self.progDir.row(), self.progDir.row()) self.rootItem.removeChild(self.progDir) self.endRemoveRows() self.progDir = None itm = BrowserDirectoryItem(self.rootItem, dirname) self.addItem(itm) self.progDir = itm def addTopLevelDir(self, dirname): """ Public method to add a new toplevel directory. @param dirname name of the new toplevel directory (string) """ if dirname not in self.toplevelDirs: itm = BrowserDirectoryItem(self.rootItem, dirname) self.addItem(itm) self.toplevelDirs.append(itm.dirName()) def removeToplevelDir(self, index): """ Public method to remove a toplevel directory. @param index index of the toplevel directory to be removed (QModelIndex) """ if not index.isValid(): return item = index.internalPointer() self.beginRemoveRows(index.parent(), index.row(), index.row()) self.rootItem.removeChild(item) self.endRemoveRows() self.toplevelDirs.remove(item.dirName()) self._removeWatchedItem(item) def saveToplevelDirs(self): """ Public slot to save the toplevel directories. """ Preferences.Prefs.settings.setValue('BrowserModel/ToplevelDirs', self.toplevelDirs) def _addItem(self, itm, parentItem): """ Protected slot to add an item. @param itm reference to item to add (BrowserItem) @param parentItem reference to item to add to (BrowserItem) """ parentItem.appendChild(itm) def addItem(self, itm, parent=QModelIndex()): """ Puplic slot to add an item. @param itm item to add (BrowserItem) @param parent index of parent item (QModelIndex) """ if not parent.isValid(): parentItem = self.rootItem else: parentItem = parent.internalPointer() cnt = parentItem.childCount() self.beginInsertRows(parent, cnt, cnt) self._addItem(itm, parentItem) self.endInsertRows() def populateItem(self, parentItem, repopulate=False): """ Public method to populate an item's subtree. @param parentItem reference to the item to be populated @param repopulate flag indicating a repopulation (boolean) """ if parentItem.type() == BrowserItemDirectory: self.populateDirectoryItem(parentItem, repopulate) elif parentItem.type() == BrowserItemSysPath: self.populateSysPathItem(parentItem, repopulate) elif parentItem.type() == BrowserItemFile: self.populateFileItem(parentItem, repopulate) elif parentItem.type() == BrowserItemClass: self.populateClassItem(parentItem, repopulate) elif parentItem.type() == BrowserItemMethod: self.populateMethodItem(parentItem, repopulate) elif parentItem.type() == BrowserItemAttributes: self.populateClassAttributesItem(parentItem, repopulate) def populateDirectoryItem(self, parentItem, repopulate=False): """ Public method to populate a directory item's subtree. @param parentItem reference to the directory item to be populated @param repopulate flag indicating a repopulation (boolean) """ self._addWatchedItem(parentItem) qdir = QDir(parentItem.dirName()) if Preferences.getUI("BrowsersListHiddenFiles"): filter = QDir.Filters(QDir.AllEntries | QDir.Hidden | QDir.NoDotAndDotDot) else: filter = QDir.Filters(QDir.AllEntries | QDir.NoDotAndDotDot) entryInfoList = qdir.entryInfoList(filter) if len(entryInfoList) > 0: if repopulate: self.beginInsertRows(self.createIndex(parentItem.row(), 0, parentItem), 0, len(entryInfoList) - 1) for f in entryInfoList: if f.isDir(): node = BrowserDirectoryItem(parentItem, Utilities.toNativeSeparators(f.absoluteFilePath()), False) else: fileFilters = Preferences.getUI("BrowsersFileFilters").split(";") if fileFilters: fn = f.fileName() if any([fnmatch.fnmatch(fn, ff.strip()) for ff in fileFilters]): continue node = BrowserFileItem(parentItem, Utilities.toNativeSeparators(f.absoluteFilePath())) self._addItem(node, parentItem) if repopulate: self.endInsertRows() def populateSysPathItem(self, parentItem, repopulate=False): """ Public method to populate a sys.path item's subtree. @param parentItem reference to the sys.path item to be populated @param repopulate flag indicating a repopulation (boolean) """ if len(sys.path) > 0: if repopulate: self.beginInsertRows(self.createIndex(parentItem.row(), 0, parentItem), 0, len(sys.path) - 1) for p in sys.path: if p == '': p = os.getcwd() node = BrowserDirectoryItem(parentItem, p) self._addItem(node, parentItem) if repopulate: self.endInsertRows() def populateFileItem(self, parentItem, repopulate=False): """ Public method to populate a file item's subtree. @param parentItem reference to the file item to be populated @param repopulate flag indicating a repopulation (boolean) """ moduleName = parentItem.moduleName() fileName = parentItem.fileName() try: dict = Utilities.ClassBrowsers.readmodule( moduleName, [parentItem.dirName()], parentItem.isPython2File() or parentItem.isPython3File()) except ImportError: return keys = list(dict.keys()) if len(keys) > 0: if repopulate: self.beginInsertRows(self.createIndex(parentItem.row(), 0, parentItem), 0, len(keys) - 1) for key in keys: if key.startswith("@@"): # special treatment done later continue cl = dict[key] try: if cl.module == moduleName: node = BrowserClassItem(parentItem, cl, fileName) self._addItem(node, parentItem) except AttributeError: pass if "@@Coding@@" in keys: node = BrowserCodingItem(parentItem, QApplication.translate("BrowserModel", "Coding: {0}")\ .format(dict["@@Coding@@"].coding)) self._addItem(node, parentItem) if "@@Globals@@" in keys: node = BrowserClassAttributesItem(parentItem, dict["@@Globals@@"].globals, QApplication.translate("BrowserModel", "Globals")) self._addItem(node, parentItem) if repopulate: self.endInsertRows() def populateClassItem(self, parentItem, repopulate=False): """ Public method to populate a class item's subtree. @param parentItem reference to the class item to be populated @param repopulate flag indicating a repopulation (boolean) """ cl = parentItem.classObject() file_ = parentItem.fileName() if cl is None: return # build sorted list of names keys = [] for name in list(cl.classes.keys()): keys.append((name, 'c')) for name in list(cl.methods.keys()): keys.append((name, 'm')) if len(keys) > 0: if repopulate: self.beginInsertRows(self.createIndex(parentItem.row(), 0, parentItem), 0, len(keys) - 1) for key, kind in keys: if kind == 'c': node = BrowserClassItem(parentItem, cl.classes[key], file_) elif kind == 'm': node = BrowserMethodItem(parentItem, cl.methods[key], file_) self._addItem(node, parentItem) if repopulate: self.endInsertRows() if len(cl.attributes): node = BrowserClassAttributesItem( parentItem, cl.attributes, QApplication.translate("BrowserModel", "Attributes")) if repopulate: self.addItem(node, self.createIndex(parentItem.row(), 0, parentItem)) else: self._addItem(node, parentItem) if len(cl.globals): node = BrowserClassAttributesItem( parentItem, cl.globals, QApplication.translate("BrowserModel", "Class Attributes"), True) if repopulate: self.addItem(node, self.createIndex(parentItem.row(), 0, parentItem)) else: self._addItem(node, parentItem) def populateMethodItem(self, parentItem, repopulate=False): """ Public method to populate a method item's subtree. @param parentItem reference to the method item to be populated @param repopulate flag indicating a repopulation (boolean) """ fn = parentItem.functionObject() file_ = parentItem.fileName() if fn is None: return # build sorted list of names keys = [] for name in list(fn.classes.keys()): keys.append((name, 'c')) for name in list(fn.methods.keys()): keys.append((name, 'm')) if len(keys) > 0: if repopulate: self.beginInsertRows(self.createIndex(parentItem.row(), 0, parentItem), 0, len(keys) - 1) for key, kind in keys: if kind == 'c': node = BrowserClassItem(parentItem, fn.classes[key], file_) elif kind == 'm': node = BrowserMethodItem(parentItem, fn.methods[key], file_) self._addItem(node, parentItem) if repopulate: self.endInsertRows() def populateClassAttributesItem(self, parentItem, repopulate=False): """ Public method to populate a class attributes item's subtree. @param parentItem reference to the class attributes item to be populated @param repopulate flag indicating a repopulation (boolean) """ classAttributes = parentItem.isClassAttributes() attributes = parentItem.attributes() if not attributes: return keys = list(attributes.keys()) if len(keys) > 0: if repopulate: self.beginInsertRows(self.createIndex(parentItem.row(), 0, parentItem), 0, len(keys) - 1) for key in keys: node = BrowserClassAttributeItem(parentItem, attributes[key], classAttributes) self._addItem(node, parentItem) if repopulate: self.endInsertRows() class BrowserItem(object): """ Class implementing the data structure for browser items. """ def __init__(self, parent, data): """ Constructor. @param parent reference to the parent item @param data single data of the item """ self.childItems = [] self.parentItem = parent self.itemData = [data] self.type_ = BrowserItemRoot self.icon = UI.PixmapCache.getIcon("empty.png") self._populated = True self._lazyPopulation = False self.symlink = False def appendChild(self, child): """ Public method to add a child to this item. @param child reference to the child item to add (BrowserItem) """ self.childItems.append(child) self._populated = True def removeChild(self, child): """ Public method to remove a child. @param child reference to the child to remove (BrowserItem) """ self.childItems.remove(child) def removeChildren(self): """ Public method to remove all children. """ self.childItems = [] def child(self, row): """ Public method to get a child id. @param row number of child to get the id of (integer) @param return reference to the child item (BrowserItem) """ return self.childItems[row] def children(self): """ Public method to get the ids of all child items. @return references to all child items (list of BrowserItem) """ return self.childItems[:] def childCount(self): """ Public method to get the number of available child items. @return number of child items (integer) """ return len(self.childItems) def columnCount(self): """ Public method to get the number of available data items. @return number of data items (integer) """ return len(self.itemData) def data(self, column): """ Public method to get a specific data item. @param column number of the requested data item (integer) @param return the stored data item """ try: return self.itemData[column] except IndexError: return "" def parent(self): """ Public method to get the reference to the parent item. @return reference to the parent item """ return self.parentItem def row(self): """ Public method to get the row number of this item. @return row number (integer) """ return self.parentItem.childItems.index(self) def type(self): """ Public method to get the item type. @return type of the item """ return self.type_ def isPublic(self): """ Public method returning the public visibility status. @return flag indicating public visibility (boolean) """ return True def getIcon(self): """ Public method to get the items icon. @return the icon (QIcon) """ return self.icon def isPopulated(self): """ Public method to chek, if this item is populated. @return population status (boolean) """ return self._populated def isLazyPopulated(self): """ Public method to check, if this item should be populated lazyly. @return lazy population flag (boolean) """ return self._lazyPopulation def lessThan(self, other, column, order): """ Public method to check, if the item is less than the other one. @param other reference to item to compare against (BrowserItem) @param column column number to use for the comparison (integer) @param order sort order (Qt.SortOrder) (for special sorting) @return true, if this item is less than other (boolean) """ try: return self.itemData[column] < other.itemData[column] except IndexError: return False def isSymlink(self): """ Public method to check, if the items is a symbolic link. @return flag indicating a symbolic link (boolean) """ return self.symlink class BrowserDirectoryItem(BrowserItem): """ Class implementing the data structure for browser directory items. """ def __init__(self, parent, dinfo, full=True): """ Constructor @param parent parent item @param dinfo dinfo is the string for the directory (string) @param full flag indicating full pathname should be displayed (boolean) """ self._dirName = os.path.abspath(dinfo) if full: dn = self._dirName else: dn = os.path.basename(self._dirName) BrowserItem.__init__(self, parent, dn) self.type_ = BrowserItemDirectory if os.path.lexists(self._dirName) and os.path.islink(self._dirName): self.symlink = True self.icon = UI.PixmapCache.getSymlinkIcon("dirClosed.png") else: self.icon = UI.PixmapCache.getIcon("dirClosed.png") self._populated = False self._lazyPopulation = True def setName(self, dinfo, full=True): """ Public method to set the directory name. @param dinfo dinfo is the string for the directory (string) @param full flag indicating full pathname should be displayed (boolean) """ self._dirName = os.path.abspath(dinfo) if full: dn = self._dirName else: dn = os.path.basename(self._dirName) self.itemData[0] = dn def dirName(self): """ Public method returning the directory name. @return directory name (string) """ return self._dirName def name(self): """ Public method to return the name of the item. @return name of the item (string) """ return self._dirName def lessThan(self, other, column, order): """ Public method to check, if the item is less than the other one. @param other reference to item to compare against (BrowserItem) @param column column number to use for the comparison (integer) @param order sort order (Qt.SortOrder) (for special sorting) @return true, if this item is less than other (boolean) """ if issubclass(other.__class__, BrowserFileItem): if Preferences.getUI("BrowsersListFoldersFirst"): return order == Qt.AscendingOrder return BrowserItem.lessThan(self, other, column, order) class BrowserSysPathItem(BrowserItem): """ Class implementing the data structure for browser sys.path items. """ def __init__(self, parent): """ Constructor @param parent parent item """ BrowserItem.__init__(self, parent, "sys.path") self.type_ = BrowserItemSysPath self.icon = UI.PixmapCache.getIcon("filePython.png") self._populated = False self._lazyPopulation = True class BrowserFileItem(BrowserItem): """ Class implementing the data structure for browser file items. """ def __init__(self, parent, finfo, full=True, sourceLanguage=""): """ Constructor @param parent parent item @param finfo the string for the file (string) @param full flag indicating full pathname should be displayed (boolean) @param sourceLanguage source code language of the project (string) """ BrowserItem.__init__(self, parent, os.path.basename(finfo)) self.type_ = BrowserItemFile self.fileext = os.path.splitext(finfo)[1].lower() self._filename = os.path.abspath(finfo) self._dirName = os.path.dirname(finfo) self.sourceLanguage = sourceLanguage self._moduleName = '' pixName = "" if self.isPython2File(): if self.fileext == '.py': pixName = "filePython.png" else: pixName = "filePython2.png" self._populated = False self._lazyPopulation = True self._moduleName = os.path.basename(finfo) elif self.isPython3File(): pixName = "filePython.png" self._populated = False self._lazyPopulation = True self._moduleName = os.path.basename(finfo) elif self.isRubyFile(): pixName = "fileRuby.png" self._populated = False self._lazyPopulation = True self._moduleName = os.path.basename(finfo) elif self.isDesignerFile(): pixName = "fileDesigner.png" elif self.isLinguistFile(): if self.fileext == '.ts': pixName = "fileLinguist.png" else: pixName = "fileLinguist2.png" elif self.isResourcesFile(): pixName = "fileResource.png" elif self.isProjectFile(): pixName = "fileProject.png" elif self.isMultiProjectFile(): pixName = "fileMultiProject.png" elif self.isIdlFile(): pixName = "fileIDL.png" self._populated = False self._lazyPopulation = True self._moduleName = os.path.basename(finfo) elif self.isPixmapFile(): pixName = "filePixmap.png" elif self.isSvgFile(): pixName = "fileSvg.png" elif self.isDFile(): pixName = "fileD.png" else: pixName = "fileMisc.png" if os.path.lexists(self._filename) and os.path.islink(self._filename): self.symlink = True self.icon = UI.PixmapCache.getSymlinkIcon(pixName) else: self.icon = UI.PixmapCache.getIcon(pixName) def setName(self, finfo, full=True): """ Public method to set the directory name. @param finfo the string for the file (string) @param full flag indicating full pathname should be displayed (boolean) """ self._filename = os.path.abspath(finfo) self.itemData[0] = os.path.basename(finfo) if self.isPython2File() or self.isPython3File() or \ self.isRubyFile() or self.isIdlFile(): self._dirName = os.path.dirname(finfo) self._moduleName = os.path.basename(finfo) def fileName(self): """ Public method returning the filename. @return filename (string) """ return self._filename def name(self): """ Public method to return the name of the item. @return name of the item (string) """ return self._filename def fileExt(self): """ Public method returning the file extension. @return file extension (string) """ return self.fileext def dirName(self): """ Public method returning the directory name. @return directory name (string) """ return self._dirName def moduleName(self): """ Public method returning the module name. @return module name (string) """ return self._moduleName def isPython2File(self): """ Public method to check, if this file is a Python script. @return flag indicating a Python file (boolean) """ return self.fileext in Preferences.getPython("PythonExtensions") or \ (self.fileext == "" and self.sourceLanguage in ["Python", "Python2"]) def isPython3File(self): """ Public method to check, if this file is a Python3 script. @return flag indicating a Python file (boolean) """ return self.fileext in Preferences.getPython("Python3Extensions") or \ (self.fileext == "" and self.sourceLanguage == "Python3") def isRubyFile(self): """ Public method to check, if this file is a Ruby script. @return flag indicating a Ruby file (boolean) """ return self.fileext == '.rb' or \ (self.fileext == "" and self.sourceLanguage == "Ruby") def isDesignerFile(self): """ Public method to check, if this file is a Qt-Designer file. @return flag indicating a Qt-Designer file (boolean) """ return self.fileext == '.ui' def isLinguistFile(self): """ Public method to check, if this file is a Qt-Linguist file. @return flag indicating a Qt-Linguist file (boolean) """ return self.fileext in ['.ts', '.qm'] def isResourcesFile(self): """ Public method to check, if this file is a Qt-Resources file. @return flag indicating a Qt-Resources file (boolean) """ return self.fileext == '.qrc' def isProjectFile(self): """ Public method to check, if this file is an eric project file. @return flag indicating an eric project file (boolean) """ return self.fileext in ['.e4p'] def isMultiProjectFile(self): """ Public method to check, if this file is an eric multi project file. @return flag indicating an eric project file (boolean) """ return self.fileext in ['.e4m'] def isIdlFile(self): """ Public method to check, if this file is a CORBA IDL file. @return flag indicating a CORBA IDL file (boolean) """ return self.fileext == '.idl' def isPixmapFile(self): """ Public method to check, if this file is a pixmap file. @return flag indicating a pixmap file (boolean) """ return self.fileext[1:] in QImageReader.supportedImageFormats() def isSvgFile(self): """ Public method to check, if this file is a SVG file. @return flag indicating a SVG file (boolean) """ return self.fileext == '.svg' def isDFile(self): """ Public method to check, if this file is a D file. @return flag indicating a D file (boolean) """ return self.fileext in ['.d', '.di'] or \ (self.fileext == "" and self.sourceLanguage == "D") def lessThan(self, other, column, order): """ Public method to check, if the item is less than the other one. @param other reference to item to compare against (BrowserItem) @param column column number to use for the comparison (integer) @param order sort order (Qt.SortOrder) (for special sorting) @return true, if this item is less than other (boolean) """ if not issubclass(other.__class__, BrowserFileItem): if Preferences.getUI("BrowsersListFoldersFirst"): return order == Qt.DescendingOrder if issubclass(other.__class__, BrowserFileItem): sinit = os.path.basename(self._filename).startswith('__init__.py') oinit = os.path.basename(other.fileName()).startswith('__init__.py') if sinit and not oinit: return order == Qt.AscendingOrder if not sinit and oinit: return order == Qt.DescendingOrder return BrowserItem.lessThan(self, other, column, order) class BrowserClassItem(BrowserItem): """ Class implementing the data structure for browser class items. """ def __init__(self, parent, cl, filename): """ Constructor @param parent parent item @param cl Class object to be shown @param filename filename of the file defining this class """ name = cl.name if hasattr(cl, 'super') and cl.super: supers = [] for sup in cl.super: try: sname = sup.name if sup.module != cl.module: sname = "{0}.{1}".format(sup.module, sname) except AttributeError: sname = sup supers.append(sname) name = name + "({0})".format(", ".join(supers)) BrowserItem.__init__(self, parent, name) self.type_ = BrowserItemClass self.name = name self._classObject = cl self._filename = filename self.isfunction = isinstance(self._classObject, Utilities.ClassBrowsers.ClbrBaseClasses.Function) self.ismodule = isinstance(self._classObject, Utilities.ClassBrowsers.ClbrBaseClasses.Module) if self.isfunction: if cl.isPrivate(): self.icon = UI.PixmapCache.getIcon("method_private.png") elif cl.isProtected(): self.icon = UI.PixmapCache.getIcon("method_protected.png") else: self.icon = UI.PixmapCache.getIcon("method.png") self.itemData[0] = "{0}({1})".format( name, ", ".join(self._classObject.parameters)) # if no defaults are wanted # ....format(name, ", ".join([e.split('=')[0].strip() \ # for e in self._classObject.parameters])) elif self.ismodule: self.icon = UI.PixmapCache.getIcon("module.png") else: if cl.isPrivate(): self.icon = UI.PixmapCache.getIcon("class_private.png") elif cl.isProtected(): self.icon = UI.PixmapCache.getIcon("class_protected.png") else: self.icon = UI.PixmapCache.getIcon("class.png") if self._classObject and \ (self._classObject.methods or \ self._classObject.classes or \ self._classObject.attributes): self._populated = False self._lazyPopulation = True def fileName(self): """ Public method returning the filename. @return filename (string) """ return self._filename def classObject(self): """ Public method returning the class object. @return reference to the class object """ return self._classObject def lineno(self): """ Public method returning the line number defining this object. return line number defining the object (integer) """ return self._classObject.lineno def lessThan(self, other, column, order): """ Public method to check, if the item is less than the other one. @param other reference to item to compare against (BrowserItem) @param column column number to use for the comparison (integer) @param order sort order (Qt.SortOrder) (for special sorting) @return true, if this item is less than other (boolean) """ if issubclass(other.__class__, BrowserCodingItem) or \ issubclass(other.__class__, BrowserClassAttributesItem): return order == Qt.DescendingOrder if Preferences.getUI("BrowsersListContentsByOccurrence") and column == 0: if order == Qt.AscendingOrder: return self.lineno() < other.lineno() else: return self.lineno() > other.lineno() return BrowserItem.lessThan(self, other, column, order) def isPublic(self): """ Public method returning the public visibility status. @return flag indicating public visibility (boolean) """ return self._classObject.isPublic() class BrowserMethodItem(BrowserItem): """ Class implementing the data structure for browser method items. """ def __init__(self, parent, fn, filename): """ Constructor @param parent parent item @param fn Function object to be shown @param filename filename of the file defining this class (string) """ name = fn.name BrowserItem.__init__(self, parent, name) self.type_ = BrowserItemMethod self.name = name self._functionObject = fn self._filename = filename if self._functionObject.modifier == \ Utilities.ClassBrowsers.ClbrBaseClasses.Function.Static: self.icon = UI.PixmapCache.getIcon("method_static.png") elif self._functionObject.modifier == \ Utilities.ClassBrowsers.ClbrBaseClasses.Function.Class: self.icon = UI.PixmapCache.getIcon("method_class.png") elif self._functionObject.isPrivate(): self.icon = UI.PixmapCache.getIcon("method_private.png") elif self._functionObject.isProtected(): self.icon = UI.PixmapCache.getIcon("method_protected.png") else: self.icon = UI.PixmapCache.getIcon("method.png") self.itemData[0] = "{0}({1})".format( name, ", ".join(self._functionObject.parameters)) # if no defaults are wanted # ....format(name, ", ".join( # [e.split('=')[0].strip() for e in self._functionObject.parameters])) if self._functionObject and \ (self._functionObject.methods or self._functionObject.classes): self._populated = False self._lazyPopulation = True def fileName(self): """ Public method returning the filename. @return filename (string) """ return self._filename def functionObject(self): """ Public method returning the function object. @return reference to the function object """ return self._functionObject def lineno(self): """ Public method returning the line number defining this object. return line number defining the object (integer) """ return self._functionObject.lineno def lessThan(self, other, column, order): """ Public method to check, if the item is less than the other one. @param other reference to item to compare against (BrowserItem) @param column column number to use for the comparison (integer) @param order sort order (Qt.SortOrder) (for special sorting) @return true, if this item is less than other (boolean) """ if issubclass(other.__class__, BrowserMethodItem): if self.name.startswith('__init__'): return order == Qt.AscendingOrder if other.name.startswith('__init__'): return order == Qt.DescendingOrder elif issubclass(other.__class__, BrowserClassAttributesItem): return order == Qt.DescendingOrder if Preferences.getUI("BrowsersListContentsByOccurrence") and column == 0: if order == Qt.AscendingOrder: return self.lineno() < other.lineno() else: return self.lineno() > other.lineno() return BrowserItem.lessThan(self, other, column, order) def isPublic(self): """ Public method returning the public visibility status. @return flag indicating public visibility (boolean) """ return self._functionObject.isPublic() class BrowserClassAttributesItem(BrowserItem): """ Class implementing the data structure for browser class attributes items. """ def __init__(self, parent, attributes, text, isClass=False): """ Constructor @param parent parent item @param attributes list of attributes @param text text to be shown by this item (string) @param isClass flag indicating class attributes (boolean) """ BrowserItem.__init__(self, parent, text) self.type_ = BrowserItemAttributes self._attributes = attributes.copy() self._populated = False self._lazyPopulation = True if isClass: self.icon = UI.PixmapCache.getIcon("attributes_class.png") else: self.icon = UI.PixmapCache.getIcon("attributes.png") self.__isClass = isClass def attributes(self): """ Public method returning the attribute list. @return reference to the list of attributes """ return self._attributes def isClassAttributes(self): """ Public method returning the attributes type. @return flag indicating class attributes (boolean) """ return self.__isClass def lessThan(self, other, column, order): """ Public method to check, if the item is less than the other one. @param other reference to item to compare against (BrowserItem) @param column column number to use for the comparison (integer) @param order sort order (Qt.SortOrder) (for special sorting) @return true, if this item is less than other (boolean) """ if issubclass(other.__class__, BrowserCodingItem): return order == Qt.DescendingOrder elif issubclass(other.__class__, BrowserClassItem) or \ issubclass(other.__class__, BrowserMethodItem): return order == Qt.AscendingOrder return BrowserItem.lessThan(self, other, column, order) class BrowserClassAttributeItem(BrowserItem): """ Class implementing the data structure for browser class attribute items. """ def __init__(self, parent, attribute, isClass=False): """ Constructor @param parent parent item @param attribute reference to the attribute object @param isClass flag indicating a class attribute (boolean) """ BrowserItem.__init__(self, parent, attribute.name) self.type_ = BrowserItemAttribute self._attributeObject = attribute self.__public = attribute.isPublic() if isClass: self.icon = UI.PixmapCache.getIcon("attribute_class.png") elif attribute.isPrivate(): self.icon = UI.PixmapCache.getIcon("attribute_private.png") elif attribute.isProtected(): self.icon = UI.PixmapCache.getIcon("attribute_protected.png") else: self.icon = UI.PixmapCache.getIcon("attribute.png") def isPublic(self): """ Public method returning the public visibility status. @return flag indicating public visibility (boolean) """ return self.__public def attributeObject(self): """ Public method returning the class object. @return reference to the class object """ return self._attributeObject def fileName(self): """ Public method returning the filename. @return filename (string) """ return self._attributeObject.file def lineno(self): """ Public method returning the line number defining this object. return line number defining the object (integer) """ return self._attributeObject.lineno def linenos(self): """ Public method returning the line numbers this object is assigned to. return line number the object is assigned to (list of integers) """ return self._attributeObject.linenos[:] def lessThan(self, other, column, order): """ Public method to check, if the item is less than the other one. @param other reference to item to compare against (BrowserItem) @param column column number to use for the comparison (integer) @param order sort order (Qt.SortOrder) (for special sorting) @return true, if this item is less than other (boolean) """ if Preferences.getUI("BrowsersListContentsByOccurrence") and column == 0: if order == Qt.AscendingOrder: return self.lineno() < other.lineno() else: return self.lineno() > other.lineno() return BrowserItem.lessThan(self, other, column, order) class BrowserCodingItem(BrowserItem): """ Class implementing the data structure for browser coding items. """ def __init__(self, parent, text): """ Constructor @param parent parent item @param text text to be shown by this item (string) """ BrowserItem.__init__(self, parent, text) self.type_ = BrowserItemCoding self.icon = UI.PixmapCache.getIcon("textencoding.png") def lessThan(self, other, column, order): """ Public method to check, if the item is less than the other one. @param other reference to item to compare against (BrowserItem) @param column column number to use for the comparison (integer) @param order sort order (Qt.SortOrder) (for special sorting) @return true, if this item is less than other (boolean) """ if issubclass(other.__class__, BrowserClassItem) or \ issubclass(other.__class__, BrowserClassAttributesItem): return order == Qt.AscendingOrder return BrowserItem.lessThan(self, other, column, order)