"Fossies" - the Fresh Open Source Software Archive

Member "eric6-20.9/eric/eric6/UI/BrowserModel.py" (2 Sep 2020, 67931 Bytes) of package /linux/misc/eric6-20.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "BrowserModel.py" see the Fossies "Dox" file reference documentation.

    1 # -*- coding: utf-8 -*-
    2 
    3 # Copyright (c) 2006 - 2020 Detlev Offenbach <detlev@die-offenbachs.de>
    4 #
    5 
    6 """
    7 Module implementing the browser model.
    8 """
    9 
   10 
   11 import os
   12 import fnmatch
   13 import json
   14 
   15 from PyQt5.QtCore import (
   16     QDir, QModelIndex, QAbstractItemModel, QFileSystemWatcher, Qt, QProcess,
   17     QCoreApplication
   18 )
   19 from PyQt5.QtGui import QImageReader, QFont
   20 from PyQt5.QtWidgets import QApplication
   21 
   22 import UI.PixmapCache
   23 import Preferences
   24 import Utilities
   25 
   26 BrowserItemRoot = 0
   27 BrowserItemDirectory = 1
   28 BrowserItemSysPath = 2
   29 BrowserItemFile = 3
   30 BrowserItemClass = 4
   31 BrowserItemMethod = 5
   32 BrowserItemAttributes = 6
   33 BrowserItemAttribute = 7
   34 BrowserItemCoding = 8
   35 BrowserItemImports = 9
   36 BrowserItemImport = 10
   37 
   38 
   39 class BrowserModel(QAbstractItemModel):
   40     """
   41     Class implementing the browser model.
   42     """
   43     def __init__(self, parent=None, nopopulate=False):
   44         """
   45         Constructor
   46         
   47         @param parent reference to parent object (QObject)
   48         @keyparam nopopulate flag indicating to not populate the model
   49             (boolean)
   50         """
   51         super(BrowserModel, self).__init__(parent)
   52         
   53         self.progDir = None
   54         
   55         self.__sysPathInterpreter = ""
   56         self.__sysPathItem = None
   57         
   58         if not nopopulate:
   59             self.watchedItems = {}
   60             self.watchedFileItems = {}
   61             self.watcher = QFileSystemWatcher(self)
   62             self.watcher.directoryChanged.connect(self.directoryChanged)
   63             self.watcher.fileChanged.connect(self.fileChanged)
   64             
   65             rootData = QCoreApplication.translate("BrowserModel", "Name")
   66             self.rootItem = BrowserItem(None, rootData)
   67             
   68             self.__populateModel()
   69     
   70     def columnCount(self, parent=None):
   71         """
   72         Public method to get the number of columns.
   73         
   74         @param parent index of parent item (QModelIndex)
   75         @return number of columns (integer)
   76         """
   77         if parent is None:
   78             parent = QModelIndex()
   79         
   80         if parent.isValid():
   81             item = parent.internalPointer()
   82         else:
   83             item = self.rootItem
   84         
   85         return item.columnCount() + 1
   86     
   87     def data(self, index, role):
   88         """
   89         Public method to get data of an item.
   90         
   91         @param index index of the data to retrieve (QModelIndex)
   92         @param role role of data (Qt.ItemDataRole)
   93         @return requested data
   94         """
   95         if not index.isValid():
   96             return None
   97         
   98         if role == Qt.DisplayRole:
   99             item = index.internalPointer()
  100             if index.column() < item.columnCount():
  101                 return item.data(index.column())
  102             elif (
  103                 index.column() == item.columnCount() and
  104                 index.column() < self.columnCount(self.parent(index))
  105             ):
  106                 # This is for the case where an item under a multi-column
  107                 # parent doesn't have a value for all the columns
  108                 return ""
  109         elif role == Qt.DecorationRole:
  110             if index.column() == 0:
  111                 return index.internalPointer().getIcon()
  112         elif role == Qt.FontRole:
  113             item = index.internalPointer()
  114             if item.isSymlink():
  115                 font = QFont(QApplication.font("QTreeView"))
  116                 font.setItalic(True)
  117                 return font
  118         
  119         return None
  120     
  121     def flags(self, index):
  122         """
  123         Public method to get the item flags.
  124         
  125         @param index index of the data to retrieve (QModelIndex)
  126         @return requested flags (Qt.ItemFlags)
  127         """
  128         if not index.isValid():
  129             return Qt.ItemIsEnabled
  130         
  131         return Qt.ItemIsEnabled | Qt.ItemIsSelectable
  132     
  133     def headerData(self, section, orientation, role=Qt.DisplayRole):
  134         """
  135         Public method to get the header data.
  136         
  137         @param section number of section to get data for (integer)
  138         @param orientation header orientation (Qt.Orientation)
  139         @param role role of data (Qt.ItemDataRole)
  140         @return requested header data
  141         """
  142         if orientation == Qt.Horizontal and role == Qt.DisplayRole:
  143             if section >= self.rootItem.columnCount():
  144                 return ""
  145             else:
  146                 return self.rootItem.data(section)
  147         
  148         return None
  149     
  150     def index(self, row, column, parent=None):
  151         """
  152         Public method to create an index.
  153         
  154         @param row row number of the new index (integer)
  155         @param column column number of the new index (integer)
  156         @param parent index of parent item (QModelIndex)
  157         @return index object (QModelIndex)
  158         """
  159         if parent is None:
  160             parent = QModelIndex()
  161         
  162         # The model/view framework considers negative values out-of-bounds,
  163         # however in python they work when indexing into lists. So make sure
  164         # we return an invalid index for out-of-bounds row/col
  165         if (
  166             row < 0 or
  167             column < 0 or
  168             row >= self.rowCount(parent) or
  169             column >= self.columnCount(parent)
  170         ):
  171             return QModelIndex()
  172         
  173         if not parent.isValid():
  174             parentItem = self.rootItem
  175         else:
  176             parentItem = parent.internalPointer()
  177         
  178         try:
  179             if not parentItem.isPopulated():
  180                 self.populateItem(parentItem)
  181             childItem = parentItem.child(row)
  182         except IndexError:
  183             childItem = None
  184         if childItem:
  185             return self.createIndex(row, column, childItem)
  186         else:
  187             return QModelIndex()
  188     
  189     def parent(self, index):
  190         """
  191         Public method to get the index of the parent object.
  192         
  193         @param index index of the item (QModelIndex)
  194         @return index of parent item (QModelIndex)
  195         """
  196         if not index.isValid():
  197             return QModelIndex()
  198         
  199         childItem = index.internalPointer()
  200         parentItem = childItem.parent()
  201         
  202         if parentItem == self.rootItem:
  203             return QModelIndex()
  204         
  205         return self.createIndex(parentItem.row(), 0, parentItem)
  206     
  207     def rowCount(self, parent=None):
  208         """
  209         Public method to get the number of rows.
  210         
  211         @param parent index of parent item (QModelIndex)
  212         @return number of rows (integer)
  213         """
  214         if parent is None:
  215             parent = QModelIndex()
  216         
  217         # Only the first column should have children
  218         if parent.column() > 0:
  219             return 0
  220         
  221         if not parent.isValid():
  222             parentItem = self.rootItem
  223         else:
  224             parentItem = parent.internalPointer()
  225             if not parentItem.isPopulated():    # lazy population
  226                 self.populateItem(parentItem)
  227         
  228         return parentItem.childCount()
  229 
  230     def hasChildren(self, parent=None):
  231         """
  232         Public method to check for the presence of child items.
  233         
  234         We always return True for normal items in order to do lazy
  235         population of the tree.
  236         
  237         @param parent index of parent item (QModelIndex)
  238         @return flag indicating the presence of child items (boolean)
  239         """
  240         if parent is None:
  241             parent = QModelIndex()
  242         
  243         # Only the first column should have children
  244         if parent.column() > 0:
  245             return 0
  246         
  247         if not parent.isValid():
  248             return self.rootItem.childCount() > 0
  249         
  250         if parent.internalPointer().isLazyPopulated():
  251             return True
  252         else:
  253             return parent.internalPointer().childCount() > 0
  254 
  255     def clear(self):
  256         """
  257         Public method to clear the model.
  258         """
  259         self.beginResetModel()
  260         self.rootItem.removeChildren()
  261         self.endResetModel()
  262     
  263     def item(self, index):
  264         """
  265         Public method to get a reference to an item.
  266         
  267         @param index index of the data to retrieve (QModelIndex)
  268         @return requested item reference (BrowserItem)
  269         """
  270         if not index.isValid():
  271             return None
  272         
  273         return index.internalPointer()
  274     
  275     def _addWatchedItem(self, itm):
  276         """
  277         Protected method to watch an item.
  278         
  279         @param itm item to be watched (BrowserDirectoryItem)
  280         """
  281         if isinstance(itm, BrowserDirectoryItem):
  282             dirName = itm.dirName()
  283             if (
  284                 dirName != "" and
  285                 not dirName.startswith("//") and
  286                 not dirName.startswith("\\\\")
  287             ):
  288                 if dirName not in self.watcher.directories():
  289                     self.watcher.addPath(dirName)
  290                 if dirName in self.watchedItems:
  291                     if itm not in self.watchedItems[dirName]:
  292                         self.watchedItems[dirName].append(itm)
  293                 else:
  294                     self.watchedItems[dirName] = [itm]
  295     
  296     def _removeWatchedItem(self, itm):
  297         """
  298         Protected method to remove a watched item.
  299         
  300         @param itm item to be removed (BrowserDirectoryItem)
  301         """
  302         if isinstance(itm, BrowserDirectoryItem):
  303             dirName = itm.dirName()
  304             if dirName in self.watchedItems:
  305                 if itm in self.watchedItems[dirName]:
  306                     self.watchedItems[dirName].remove(itm)
  307                 if len(self.watchedItems[dirName]) == 0:
  308                     del self.watchedItems[dirName]
  309                     self.watcher.removePath(dirName)
  310     
  311     def directoryChanged(self, path):
  312         """
  313         Public slot to handle the directoryChanged signal of the watcher.
  314         
  315         @param path path of the directory (string)
  316         """
  317         if path not in self.watchedItems:
  318             # just ignore the situation we don't have a reference to the item
  319             return
  320         
  321         if Preferences.getUI("BrowsersListHiddenFiles"):
  322             dirFilter = QDir.Filters(
  323                 QDir.AllEntries | QDir.Hidden | QDir.NoDotAndDotDot)
  324         else:
  325             dirFilter = QDir.Filters(
  326                 QDir.AllEntries | QDir.NoDot | QDir.NoDotDot)
  327         
  328         for itm in self.watchedItems[path]:
  329             oldCnt = itm.childCount()
  330             
  331             qdir = QDir(itm.dirName())
  332             
  333             entryInfoList = qdir.entryInfoList(dirFilter)
  334             
  335             # step 1: check for new entries
  336             children = itm.children()
  337             for f in entryInfoList:
  338                 fpath = Utilities.toNativeSeparators(f.absoluteFilePath())
  339                 childFound = False
  340                 for child in children:
  341                     if child.name() == fpath:
  342                         childFound = True
  343                         children.remove(child)
  344                         break
  345                 if childFound:
  346                     continue
  347                 
  348                 cnt = itm.childCount()
  349                 self.beginInsertRows(
  350                     self.createIndex(itm.row(), 0, itm), cnt, cnt)
  351                 if f.isDir():
  352                     node = BrowserDirectoryItem(
  353                         itm,
  354                         Utilities.toNativeSeparators(f.absoluteFilePath()),
  355                         False)
  356                 else:
  357                     node = BrowserFileItem(
  358                         itm,
  359                         Utilities.toNativeSeparators(f.absoluteFilePath()))
  360                 self._addItem(node, itm)
  361                 self.endInsertRows()
  362             
  363             # step 2: check for removed entries
  364             if len(entryInfoList) != itm.childCount():
  365                 for row in range(oldCnt - 1, -1, -1):
  366                     child = itm.child(row)
  367                     childname = Utilities.fromNativeSeparators(child.name())
  368                     entryFound = False
  369                     for f in entryInfoList:
  370                         if f.absoluteFilePath() == childname:
  371                             entryFound = True
  372                             entryInfoList.remove(f)
  373                             break
  374                     if entryFound:
  375                         continue
  376                     
  377                     self._removeWatchedItem(child)
  378                     self.beginRemoveRows(
  379                         self.createIndex(itm.row(), 0, itm), row, row)
  380                     itm.removeChild(child)
  381                     self.endRemoveRows()
  382     
  383     def __populateModel(self):
  384         """
  385         Private method to populate the browser model.
  386         """
  387         self.toplevelDirs = []
  388         tdp = Preferences.Prefs.settings.value('BrowserModel/ToplevelDirs')
  389         if tdp:
  390             self.toplevelDirs = tdp
  391         else:
  392             self.toplevelDirs.append(
  393                 Utilities.toNativeSeparators(QDir.homePath()))
  394             for d in QDir.drives():
  395                 self.toplevelDirs.append(Utilities.toNativeSeparators(
  396                     d.absoluteFilePath()))
  397         
  398         for d in self.toplevelDirs:
  399             itm = BrowserDirectoryItem(self.rootItem, d)
  400             self._addItem(itm, self.rootItem)
  401     
  402     def interpreterChanged(self, interpreter):
  403         """
  404         Public method to handle a change of the debug client's interpreter.
  405         
  406         @param interpreter interpreter of the debug client (string)
  407         """
  408         if interpreter and "python" in interpreter.lower():
  409             if interpreter.endswith("w.exe"):
  410                 interpreter = interpreter.replace("w.exe", ".exe")
  411             if self.__sysPathInterpreter != interpreter:
  412                 self.__sysPathInterpreter = interpreter
  413                 # step 1: remove sys.path entry
  414                 if self.__sysPathItem is not None:
  415                     self.beginRemoveRows(
  416                         QModelIndex(), self.__sysPathItem.row(),
  417                         self.__sysPathItem.row())
  418                     self.rootItem.removeChild(self.__sysPathItem)
  419                     self.endRemoveRows()
  420                     self.__sysPathItem = None
  421                 
  422                 if self.__sysPathInterpreter:
  423                     # step 2: add a new one
  424                     self.__sysPathItem = BrowserSysPathItem(self.rootItem)
  425                     self.addItem(self.__sysPathItem)
  426         else:
  427             # remove sys.path entry
  428             if self.__sysPathItem is not None:
  429                 self.beginRemoveRows(
  430                     QModelIndex(), self.__sysPathItem.row(),
  431                     self.__sysPathItem.row())
  432                 self.rootItem.removeChild(self.__sysPathItem)
  433                 self.endRemoveRows()
  434                 self.__sysPathItem = None
  435             self.__sysPathInterpreter = ""
  436     
  437     def programChange(self, dirname):
  438         """
  439         Public method to change the entry for the directory of file being
  440         debugged.
  441         
  442         @param dirname name of the directory containing the file (string)
  443         """
  444         if self.progDir:
  445             if dirname == self.progDir.dirName():
  446                 return
  447             
  448             # remove old entry
  449             self._removeWatchedItem(self.progDir)
  450             self.beginRemoveRows(
  451                 QModelIndex(), self.progDir.row(), self.progDir.row())
  452             self.rootItem.removeChild(self.progDir)
  453             self.endRemoveRows()
  454             self.progDir = None
  455         
  456         itm = BrowserDirectoryItem(self.rootItem, dirname)
  457         self.addItem(itm)
  458         self.progDir = itm
  459     
  460     def addTopLevelDir(self, dirname):
  461         """
  462         Public method to add a new toplevel directory.
  463         
  464         @param dirname name of the new toplevel directory (string)
  465         """
  466         if dirname not in self.toplevelDirs:
  467             itm = BrowserDirectoryItem(self.rootItem, dirname)
  468             self.addItem(itm)
  469             self.toplevelDirs.append(itm.dirName())
  470     
  471     def removeToplevelDir(self, index):
  472         """
  473         Public method to remove a toplevel directory.
  474         
  475         @param index index of the toplevel directory to be removed
  476             (QModelIndex)
  477         """
  478         if not index.isValid():
  479             return
  480         
  481         item = index.internalPointer()
  482         self.beginRemoveRows(index.parent(), index.row(), index.row())
  483         self.rootItem.removeChild(item)
  484         self.endRemoveRows()
  485         
  486         self.toplevelDirs.remove(item.dirName())
  487         self._removeWatchedItem(item)
  488     
  489     def saveToplevelDirs(self):
  490         """
  491         Public slot to save the toplevel directories.
  492         """
  493         Preferences.Prefs.settings.setValue(
  494             'BrowserModel/ToplevelDirs', self.toplevelDirs)
  495     
  496     def _addItem(self, itm, parentItem):
  497         """
  498         Protected slot to add an item.
  499         
  500         @param itm reference to item to add (BrowserItem)
  501         @param parentItem reference to item to add to (BrowserItem)
  502         """
  503         parentItem.appendChild(itm)
  504     
  505     def addItem(self, itm, parent=None):
  506         """
  507         Public slot to add an item.
  508         
  509         @param itm item to add (BrowserItem)
  510         @param parent index of parent item (QModelIndex)
  511         """
  512         if parent is None:
  513             parent = QModelIndex()
  514         
  515         if not parent.isValid():
  516             parentItem = self.rootItem
  517         else:
  518             parentItem = parent.internalPointer()
  519         
  520         cnt = parentItem.childCount()
  521         self.beginInsertRows(parent, cnt, cnt)
  522         self._addItem(itm, parentItem)
  523         self.endInsertRows()
  524 
  525     def populateItem(self, parentItem, repopulate=False):
  526         """
  527         Public method to populate an item's subtree.
  528         
  529         @param parentItem reference to the item to be populated
  530         @param repopulate flag indicating a repopulation (boolean)
  531         """
  532         if parentItem.type() == BrowserItemDirectory:
  533             self.populateDirectoryItem(parentItem, repopulate)
  534         elif parentItem.type() == BrowserItemSysPath:
  535             self.populateSysPathItem(parentItem, repopulate)
  536         elif parentItem.type() == BrowserItemFile:
  537             self.populateFileItem(parentItem, repopulate)
  538         elif parentItem.type() == BrowserItemClass:
  539             self.populateClassItem(parentItem, repopulate)
  540         elif parentItem.type() == BrowserItemMethod:
  541             self.populateMethodItem(parentItem, repopulate)
  542         elif parentItem.type() == BrowserItemAttributes:
  543             self.populateClassAttributesItem(parentItem, repopulate)
  544 
  545     def populateDirectoryItem(self, parentItem, repopulate=False):
  546         """
  547         Public method to populate a directory item's subtree.
  548         
  549         @param parentItem reference to the directory item to be populated
  550         @param repopulate flag indicating a repopulation (boolean)
  551         """
  552         self._addWatchedItem(parentItem)
  553         
  554         qdir = QDir(parentItem.dirName())
  555         
  556         if Preferences.getUI("BrowsersListHiddenFiles"):
  557             dirFilter = QDir.Filters(
  558                 QDir.AllEntries | QDir.Hidden | QDir.NoDotAndDotDot)
  559         else:
  560             dirFilter = QDir.Filters(
  561                 QDir.AllEntries | QDir.NoDot | QDir.NoDotDot)
  562         entryInfoList = qdir.entryInfoList(dirFilter)
  563         if len(entryInfoList) > 0:
  564             if repopulate:
  565                 self.beginInsertRows(
  566                     self.createIndex(parentItem.row(), 0, parentItem),
  567                     0, len(entryInfoList) - 1)
  568             for f in entryInfoList:
  569                 if f.isDir():
  570                     node = BrowserDirectoryItem(
  571                         parentItem,
  572                         Utilities.toNativeSeparators(f.absoluteFilePath()),
  573                         False)
  574                 else:
  575                     fileFilters = Preferences.getUI(
  576                         "BrowsersFileFilters").split(";")
  577                     if fileFilters:
  578                         fn = f.fileName()
  579                         if any(fnmatch.fnmatch(fn, ff.strip())
  580                                for ff in fileFilters):
  581                             continue
  582                     node = BrowserFileItem(
  583                         parentItem,
  584                         Utilities.toNativeSeparators(f.absoluteFilePath()))
  585                 self._addItem(node, parentItem)
  586             if repopulate:
  587                 self.endInsertRows()
  588 
  589     def populateSysPathItem(self, parentItem, repopulate=False):
  590         """
  591         Public method to populate a sys.path item's subtree.
  592         
  593         @param parentItem reference to the sys.path item to be populated
  594         @param repopulate flag indicating a repopulation (boolean)
  595         """
  596         if self.__sysPathInterpreter:
  597             script = "import sys, json; print(json.dumps(sys.path))"
  598             proc = QProcess()
  599             proc.start(self.__sysPathInterpreter, ["-c", script])
  600             finished = proc.waitForFinished(3000)
  601             if finished:
  602                 procOutput = str(proc.readAllStandardOutput(),
  603                                  Preferences.getSystem("IOEncoding"),
  604                                  'replace')
  605                 syspath = [p for p in json.loads(procOutput) if p]
  606                 if len(syspath) > 0:
  607                     if repopulate:
  608                         self.beginInsertRows(
  609                             self.createIndex(parentItem.row(), 0, parentItem),
  610                             0, len(syspath) - 1)
  611                     for p in syspath:
  612                         if os.path.isdir(p):
  613                             node = BrowserDirectoryItem(parentItem, p)
  614                         else:
  615                             node = BrowserFileItem(parentItem, p)
  616                         self._addItem(node, parentItem)
  617                     if repopulate:
  618                         self.endInsertRows()
  619             else:
  620                 proc.kill()
  621 
  622     def populateFileItem(self, parentItem, repopulate=False):
  623         """
  624         Public method to populate a file item's subtree.
  625         
  626         @param parentItem reference to the file item to be populated
  627         @param repopulate flag indicating a repopulation (boolean)
  628         """
  629         import Utilities.ClassBrowsers
  630         moduleName = parentItem.moduleName()
  631         fileName = parentItem.fileName()
  632         try:
  633             dictionary = Utilities.ClassBrowsers.readmodule(
  634                 moduleName, [parentItem.dirName()],
  635                 parentItem.isPython3File())
  636         except ImportError:
  637             return
  638         
  639         keys = list(dictionary.keys())
  640         if len(keys) > 0:
  641             if repopulate:
  642                 self.beginInsertRows(
  643                     self.createIndex(parentItem.row(), 0, parentItem),
  644                     0, len(keys) - 1)
  645             for key in keys:
  646                 if key.startswith("@@"):
  647                     # special treatment done later
  648                     continue
  649                 cl = dictionary[key]
  650                 try:
  651                     if cl.module == moduleName:
  652                         node = BrowserClassItem(parentItem, cl, fileName)
  653                         self._addItem(node, parentItem)
  654                 except AttributeError:
  655                     pass
  656             if "@@Coding@@" in keys:
  657                 node = BrowserCodingItem(
  658                     parentItem,
  659                     QCoreApplication.translate("BrowserModel", "Coding: {0}")
  660                     .format(dictionary["@@Coding@@"].coding))
  661                 self._addItem(node, parentItem)
  662             if "@@Globals@@" in keys:
  663                 node = BrowserGlobalsItem(
  664                     parentItem,
  665                     dictionary["@@Globals@@"].globals,
  666                     QCoreApplication.translate("BrowserModel", "Globals"))
  667                 self._addItem(node, parentItem)
  668             if "@@Import@@" in keys or "@@ImportFrom@@" in keys:
  669                 node = BrowserImportsItem(
  670                     parentItem,
  671                     QCoreApplication.translate("BrowserModel", "Imports"))
  672                 self._addItem(node, parentItem)
  673                 if "@@Import@@" in keys:
  674                     for importedModule in (
  675                         dictionary["@@Import@@"].getImports().values()
  676                     ):
  677                         m_node = BrowserImportItem(
  678                             node,
  679                             importedModule.importedModuleName,
  680                             importedModule.file,
  681                             importedModule.linenos)
  682                         self._addItem(m_node, node)
  683                         for importedName, linenos in (
  684                             importedModule.importedNames.items()
  685                         ):
  686                             mn_node = BrowserImportItem(
  687                                 m_node,
  688                                 importedName,
  689                                 importedModule.file,
  690                                 linenos,
  691                                 isModule=False)
  692                             self._addItem(mn_node, m_node)
  693             if repopulate:
  694                 self.endInsertRows()
  695         parentItem._populated = True
  696         if (parentItem.type_ == BrowserItemFile and
  697             fileName not in self.watchedFileItems
  698         ):
  699             # watch the file only in the file browser not the project viewer
  700             self.watcher.addPath(fileName)
  701             self.watchedFileItems[fileName] = parentItem
  702 
  703     def repopulateFileItem(self, itm):
  704         """
  705         Public method to repopulate a file item.
  706         
  707         @param itm reference to the item to be repopulated
  708         @type BrowserFileItem
  709         """
  710         if isinstance(itm, BrowserFileItem) and itm.isLazyPopulated():
  711             if not itm.isPopulated():
  712                 # item is not populated yet, nothing to do
  713                 return
  714             
  715             if itm.childCount():
  716                 index = self.createIndex(itm.row(), 0, itm)
  717                 self.beginRemoveRows(index, 0, itm.childCount() - 1)
  718                 itm.removeChildren()
  719                 self.endRemoveRows()
  720             
  721             self.populateFileItem(itm, True)
  722 
  723     def fileChanged(self, fileName):
  724         """
  725         Public method to react upon file changes.
  726         
  727         @param fileName path of the changed file
  728         @type str
  729         """
  730         if fileName in self.watchedFileItems:
  731             if os.path.exists(fileName):
  732                 # the file was changed
  733                 self.repopulateFileItem(self.watchedFileItems[fileName])
  734             else:
  735                 # the file does not exist anymore
  736                 del self.watchedFileItems[fileName]
  737 
  738     def populateClassItem(self, parentItem, repopulate=False):
  739         """
  740         Public method to populate a class item's subtree.
  741         
  742         @param parentItem reference to the class item to be populated
  743         @param repopulate flag indicating a repopulation (boolean)
  744         """
  745         cl = parentItem.classObject()
  746         file_ = parentItem.fileName()
  747         
  748         if cl is None:
  749             return
  750         
  751         # build sorted list of names
  752         keys = []
  753         for name in list(cl.classes.keys()):
  754             keys.append((name, 'c'))
  755         for name in list(cl.methods.keys()):
  756             keys.append((name, 'm'))
  757         
  758         if len(keys) > 0:
  759             if repopulate:
  760                 self.beginInsertRows(
  761                     self.createIndex(parentItem.row(), 0, parentItem),
  762                     0, len(keys) - 1)
  763             for key, kind in keys:
  764                 if kind == 'c':
  765                     node = BrowserClassItem(parentItem, cl.classes[key], file_)
  766                 elif kind == 'm':
  767                     node = BrowserMethodItem(parentItem, cl.methods[key],
  768                                              file_)
  769                 self._addItem(node, parentItem)
  770             if repopulate:
  771                 self.endInsertRows()
  772         
  773         if len(cl.attributes):
  774             node = BrowserClassAttributesItem(
  775                 parentItem, cl.attributes,
  776                 QCoreApplication.translate("BrowserModel", "Attributes"))
  777             if repopulate:
  778                 self.addItem(
  779                     node, self.createIndex(parentItem.row(), 0, parentItem))
  780             else:
  781                 self._addItem(node, parentItem)
  782         
  783         if len(cl.globals):
  784             node = BrowserClassAttributesItem(
  785                 parentItem, cl.globals,
  786                 QCoreApplication.translate("BrowserModel", "Class Attributes"),
  787                 True)
  788             if repopulate:
  789                 self.addItem(
  790                     node, self.createIndex(parentItem.row(), 0, parentItem))
  791             else:
  792                 self._addItem(node, parentItem)
  793 
  794     def populateMethodItem(self, parentItem, repopulate=False):
  795         """
  796         Public method to populate a method item's subtree.
  797         
  798         @param parentItem reference to the method item to be populated
  799         @param repopulate flag indicating a repopulation (boolean)
  800         """
  801         fn = parentItem.functionObject()
  802         file_ = parentItem.fileName()
  803         
  804         if fn is None:
  805             return
  806         
  807         # build sorted list of names
  808         keys = []
  809         for name in list(fn.classes.keys()):
  810             keys.append((name, 'c'))
  811         for name in list(fn.methods.keys()):
  812             keys.append((name, 'm'))
  813         
  814         if len(keys) > 0:
  815             if repopulate:
  816                 self.beginInsertRows(
  817                     self.createIndex(parentItem.row(), 0, parentItem),
  818                     0, len(keys) - 1)
  819             for key, kind in keys:
  820                 if kind == 'c':
  821                     node = BrowserClassItem(parentItem, fn.classes[key], file_)
  822                 elif kind == 'm':
  823                     node = BrowserMethodItem(parentItem, fn.methods[key],
  824                                              file_)
  825                 self._addItem(node, parentItem)
  826             if repopulate:
  827                 self.endInsertRows()
  828 
  829     def populateClassAttributesItem(self, parentItem, repopulate=False):
  830         """
  831         Public method to populate a class attributes item's subtree.
  832         
  833         @param parentItem reference to the class attributes item to be
  834             populated
  835         @param repopulate flag indicating a repopulation (boolean)
  836         """
  837         classAttributes = parentItem.isClassAttributes()
  838         attributes = parentItem.attributes()
  839         if not attributes:
  840             return
  841         
  842         keys = list(attributes.keys())
  843         if len(keys) > 0:
  844             if repopulate:
  845                 self.beginInsertRows(
  846                     self.createIndex(parentItem.row(), 0, parentItem),
  847                     0, len(keys) - 1)
  848             for key in keys:
  849                 node = BrowserClassAttributeItem(parentItem, attributes[key],
  850                                                  classAttributes)
  851                 self._addItem(node, parentItem)
  852             if repopulate:
  853                 self.endInsertRows()
  854 
  855 
  856 class BrowserItem(object):
  857     """
  858     Class implementing the data structure for browser items.
  859     """
  860     def __init__(self, parent, data):
  861         """
  862         Constructor
  863         
  864         @param parent reference to the parent item
  865         @param data single data of the item
  866         """
  867         self.childItems = []
  868         
  869         self.parentItem = parent
  870         self.itemData = [data]
  871         self.type_ = BrowserItemRoot
  872         self.icon = UI.PixmapCache.getIcon("empty")
  873         self._populated = True
  874         self._lazyPopulation = False
  875         self.symlink = False
  876     
  877     def appendChild(self, child):
  878         """
  879         Public method to add a child to this item.
  880         
  881         @param child reference to the child item to add (BrowserItem)
  882         """
  883         self.childItems.append(child)
  884         self._populated = True
  885     
  886     def removeChild(self, child):
  887         """
  888         Public method to remove a child.
  889         
  890         @param child reference to the child to remove (BrowserItem)
  891         """
  892         self.childItems.remove(child)
  893     
  894     def removeChildren(self):
  895         """
  896         Public method to remove all children.
  897         """
  898         self.childItems = []
  899     
  900     def child(self, row):
  901         """
  902         Public method to get a child id.
  903         
  904         @param row number of child to get the id of (integer)
  905         @return reference to the child item (BrowserItem)
  906         """
  907         return self.childItems[row]
  908     
  909     def children(self):
  910         """
  911         Public method to get the ids of all child items.
  912         
  913         @return references to all child items (list of BrowserItem)
  914         """
  915         return self.childItems[:]
  916     
  917     def childCount(self):
  918         """
  919         Public method to get the number of available child items.
  920         
  921         @return number of child items (integer)
  922         """
  923         return len(self.childItems)
  924     
  925     def columnCount(self):
  926         """
  927         Public method to get the number of available data items.
  928         
  929         @return number of data items (integer)
  930         """
  931         return len(self.itemData)
  932     
  933     def data(self, column):
  934         """
  935         Public method to get a specific data item.
  936         
  937         @param column number of the requested data item (integer)
  938         @return stored data item
  939         """
  940         try:
  941             return self.itemData[column]
  942         except IndexError:
  943             return ""
  944     
  945     def parent(self):
  946         """
  947         Public method to get the reference to the parent item.
  948         
  949         @return reference to the parent item
  950         """
  951         return self.parentItem
  952     
  953     def row(self):
  954         """
  955         Public method to get the row number of this item.
  956         
  957         @return row number (integer)
  958         """
  959         try:
  960             return self.parentItem.childItems.index(self)
  961         except ValueError:
  962             return 0
  963     
  964     def type(self):
  965         """
  966         Public method to get the item type.
  967         
  968         @return type of the item
  969         """
  970         return self.type_
  971     
  972     def isPublic(self):
  973         """
  974         Public method returning the public visibility status.
  975         
  976         @return flag indicating public visibility (boolean)
  977         """
  978         return True
  979     
  980     def getIcon(self):
  981         """
  982         Public method to get the items icon.
  983         
  984         @return the icon (QIcon)
  985         """
  986         return self.icon
  987     
  988     def isPopulated(self):
  989         """
  990         Public method to chek, if this item is populated.
  991         
  992         @return population status (boolean)
  993         """
  994         return self._populated
  995     
  996     def isLazyPopulated(self):
  997         """
  998         Public method to check, if this item should be populated lazyly.
  999         
 1000         @return lazy population flag (boolean)
 1001         """
 1002         return self._lazyPopulation
 1003     
 1004     def lessThan(self, other, column, order):
 1005         """
 1006         Public method to check, if the item is less than the other one.
 1007         
 1008         @param other reference to item to compare against (BrowserItem)
 1009         @param column column number to use for the comparison (integer)
 1010         @param order sort order (Qt.SortOrder) (for special sorting)
 1011         @return true, if this item is less than other (boolean)
 1012         """
 1013         try:
 1014             return self.itemData[column] < other.itemData[column]
 1015         except IndexError:
 1016             return False
 1017     
 1018     def isSymlink(self):
 1019         """
 1020         Public method to check, if the items is a symbolic link.
 1021         
 1022         @return flag indicating a symbolic link (boolean)
 1023         """
 1024         return self.symlink
 1025 
 1026 
 1027 class BrowserDirectoryItem(BrowserItem):
 1028     """
 1029     Class implementing the data structure for browser directory items.
 1030     """
 1031     def __init__(self, parent, dinfo, full=True):
 1032         """
 1033         Constructor
 1034         
 1035         @param parent parent item
 1036         @param dinfo dinfo is the string for the directory (string)
 1037         @param full flag indicating full pathname should be displayed (boolean)
 1038         """
 1039         self._dirName = os.path.abspath(dinfo)
 1040         
 1041         if full:
 1042             dn = self._dirName
 1043         else:
 1044             dn = os.path.basename(self._dirName)
 1045         
 1046         BrowserItem.__init__(self, parent, dn)
 1047         
 1048         self.type_ = BrowserItemDirectory
 1049         if (
 1050             not Utilities.isDrive(self._dirName) and
 1051             os.path.lexists(self._dirName) and
 1052             os.path.islink(self._dirName)
 1053         ):
 1054             self.symlink = True
 1055             self.icon = UI.PixmapCache.getSymlinkIcon("dirClosed")
 1056         else:
 1057             self.icon = UI.PixmapCache.getIcon("dirClosed")
 1058         self._populated = False
 1059         self._lazyPopulation = True
 1060 
 1061     def setName(self, dinfo, full=True):
 1062         """
 1063         Public method to set the directory name.
 1064         
 1065         @param dinfo dinfo is the string for the directory (string)
 1066         @param full flag indicating full pathname should be displayed (boolean)
 1067         """
 1068         self._dirName = os.path.abspath(dinfo)
 1069         
 1070         if full:
 1071             dn = self._dirName
 1072         else:
 1073             dn = os.path.basename(self._dirName)
 1074         self.itemData[0] = dn
 1075     
 1076     def dirName(self):
 1077         """
 1078         Public method returning the directory name.
 1079         
 1080         @return directory name (string)
 1081         """
 1082         return self._dirName
 1083     
 1084     def name(self):
 1085         """
 1086         Public method to return the name of the item.
 1087         
 1088         @return name of the item (string)
 1089         """
 1090         return self._dirName
 1091     
 1092     def lessThan(self, other, column, order):
 1093         """
 1094         Public method to check, if the item is less than the other one.
 1095         
 1096         @param other reference to item to compare against (BrowserItem)
 1097         @param column column number to use for the comparison (integer)
 1098         @param order sort order (Qt.SortOrder) (for special sorting)
 1099         @return true, if this item is less than other (boolean)
 1100         """
 1101         if issubclass(other.__class__, BrowserFileItem):
 1102             if Preferences.getUI("BrowsersListFoldersFirst"):
 1103                 return order == Qt.AscendingOrder
 1104         
 1105         return BrowserItem.lessThan(self, other, column, order)
 1106 
 1107 
 1108 class BrowserSysPathItem(BrowserItem):
 1109     """
 1110     Class implementing the data structure for browser sys.path items.
 1111     """
 1112     def __init__(self, parent):
 1113         """
 1114         Constructor
 1115         
 1116         @param parent parent item
 1117         """
 1118         BrowserItem.__init__(self, parent, "sys.path")
 1119         
 1120         self.type_ = BrowserItemSysPath
 1121         self.icon = UI.PixmapCache.getIcon("filePython")
 1122         self._populated = False
 1123         self._lazyPopulation = True
 1124     
 1125     def name(self):
 1126         """
 1127         Public method to return the name of the item.
 1128         
 1129         @return name of the item (string)
 1130         """
 1131         return "sys.path"
 1132 
 1133 
 1134 class BrowserFileItem(BrowserItem):
 1135     """
 1136     Class implementing the data structure for browser file items.
 1137     """
 1138     def __init__(self, parent, finfo, full=True, sourceLanguage=""):
 1139         """
 1140         Constructor
 1141         
 1142         @param parent parent item
 1143         @param finfo the string for the file (string)
 1144         @param full flag indicating full pathname should be displayed (boolean)
 1145         @param sourceLanguage source code language of the project (string)
 1146         """
 1147         BrowserItem.__init__(self, parent, os.path.basename(finfo))
 1148         
 1149         self.type_ = BrowserItemFile
 1150         self.fileext = os.path.splitext(finfo)[1].lower()
 1151         self._filename = os.path.abspath(finfo)
 1152         self._dirName = os.path.dirname(finfo)
 1153         self.sourceLanguage = sourceLanguage
 1154         
 1155         self._moduleName = ''
 1156         
 1157         pixName = ""
 1158         if self.isPython3File():
 1159             pixName = "filePython"
 1160             self._populated = False
 1161             self._lazyPopulation = True
 1162             self._moduleName = os.path.basename(finfo)
 1163         elif self.isRubyFile():
 1164             pixName = "fileRuby"
 1165             self._populated = False
 1166             self._lazyPopulation = True
 1167             self._moduleName = os.path.basename(finfo)
 1168         elif self.isDesignerFile():
 1169             pixName = "fileDesigner"
 1170         elif self.isLinguistFile():
 1171             if self.fileext == '.ts':
 1172                 pixName = "fileLinguist"
 1173             else:
 1174                 pixName = "fileLinguist2"
 1175         elif self.isResourcesFile():
 1176             pixName = "fileResource"
 1177         elif self.isProjectFile():
 1178             pixName = "fileProject"
 1179         elif self.isMultiProjectFile():
 1180             pixName = "fileMultiProject"
 1181         elif self.isIdlFile():
 1182             pixName = "fileIDL"
 1183             self._populated = False
 1184             self._lazyPopulation = True
 1185             self._moduleName = os.path.basename(finfo)
 1186         elif self.isProtobufFile():
 1187             pixName = "protobuf"
 1188             self._populated = False
 1189             self._lazyPopulation = True
 1190             self._moduleName = os.path.basename(finfo)
 1191         elif self.isSvgFile():
 1192             pixName = "fileSvg"
 1193         elif self.isPixmapFile():
 1194             pixName = "filePixmap"
 1195         elif self.isDFile():
 1196             pixName = "fileD"
 1197         elif self.isJavaScriptFile():
 1198             pixName = "fileJavascript"
 1199             self._populated = False
 1200             self._lazyPopulation = True
 1201             self._moduleName = os.path.basename(finfo)
 1202         else:
 1203             pixName = "fileMisc"
 1204         
 1205         if os.path.lexists(self._filename) and os.path.islink(self._filename):
 1206             self.symlink = True
 1207             self.icon = UI.PixmapCache.getSymlinkIcon(pixName)
 1208         else:
 1209             self.icon = UI.PixmapCache.getIcon(pixName)
 1210     
 1211     def setName(self, finfo, full=True):
 1212         """
 1213         Public method to set the directory name.
 1214         
 1215         @param finfo the string for the file (string)
 1216         @param full flag indicating full pathname should be displayed (boolean)
 1217         """
 1218         self._filename = os.path.abspath(finfo)
 1219         self.itemData[0] = os.path.basename(finfo)
 1220         if (
 1221             self.isPython3File() or
 1222             self.isRubyFile() or
 1223             self.isIdlFile() or
 1224             self.isProtobufFile()
 1225         ):
 1226             self._dirName = os.path.dirname(finfo)
 1227             self._moduleName = os.path.basename(finfo)
 1228     
 1229     def fileName(self):
 1230         """
 1231         Public method returning the filename.
 1232         
 1233         @return filename (string)
 1234         """
 1235         return self._filename
 1236     
 1237     def name(self):
 1238         """
 1239         Public method to return the name of the item.
 1240         
 1241         @return name of the item (string)
 1242         """
 1243         return self._filename
 1244     
 1245     def fileExt(self):
 1246         """
 1247         Public method returning the file extension.
 1248         
 1249         @return file extension (string)
 1250         """
 1251         return self.fileext
 1252     
 1253     def dirName(self):
 1254         """
 1255         Public method returning the directory name.
 1256         
 1257         @return directory name (string)
 1258         """
 1259         return self._dirName
 1260     
 1261     def moduleName(self):
 1262         """
 1263         Public method returning the module name.
 1264         
 1265         @return module name (string)
 1266         """
 1267         return self._moduleName
 1268     
 1269     def isPython3File(self):
 1270         """
 1271         Public method to check, if this file is a Python3 script.
 1272         
 1273         @return flag indicating a Python file (boolean)
 1274         """
 1275         return (
 1276             self.fileext in Preferences.getPython("Python3Extensions") or
 1277             (self.fileext == "" and self.sourceLanguage == "Python3")
 1278         )
 1279     
 1280     def isRubyFile(self):
 1281         """
 1282         Public method to check, if this file is a Ruby script.
 1283         
 1284         @return flag indicating a Ruby file (boolean)
 1285         """
 1286         return (
 1287             self.fileext == '.rb' or
 1288             (self.fileext == "" and self.sourceLanguage == "Ruby")
 1289         )
 1290     
 1291     def isDesignerFile(self):
 1292         """
 1293         Public method to check, if this file is a Qt-Designer file.
 1294         
 1295         @return flag indicating a Qt-Designer file (boolean)
 1296         """
 1297         return self.fileext == '.ui'
 1298     
 1299     def isLinguistFile(self):
 1300         """
 1301         Public method to check, if this file is a Qt-Linguist file.
 1302         
 1303         @return flag indicating a Qt-Linguist file (boolean)
 1304         """
 1305         return self.fileext in ['.ts', '.qm']
 1306     
 1307     def isResourcesFile(self):
 1308         """
 1309         Public method to check, if this file is a Qt-Resources file.
 1310         
 1311         @return flag indicating a Qt-Resources file (boolean)
 1312         """
 1313         return self.fileext == '.qrc'
 1314     
 1315     def isProjectFile(self):
 1316         """
 1317         Public method to check, if this file is an eric project file.
 1318         
 1319         @return flag indicating an eric project file (boolean)
 1320         """
 1321         return self.fileext in ['.e4p']
 1322     
 1323     def isMultiProjectFile(self):
 1324         """
 1325         Public method to check, if this file is an eric multi project file.
 1326         
 1327         @return flag indicating an eric project file (boolean)
 1328         """
 1329         return self.fileext in ['.e4m', '.e5m']
 1330     
 1331     def isIdlFile(self):
 1332         """
 1333         Public method to check, if this file is a CORBA IDL file.
 1334         
 1335         @return flag indicating a CORBA IDL file (boolean)
 1336         """
 1337         return self.fileext == '.idl'
 1338     
 1339     def isProtobufFile(self):
 1340         """
 1341         Public method to check, if this file is a Google Protocol Buffer file.
 1342         
 1343         @return flag indicating a protobuf file
 1344         @rtype bool
 1345         """
 1346         return self.fileext == ".proto"
 1347     
 1348     def isJavaScriptFile(self):
 1349         """
 1350         Public method to check, if this file is a JavaScript file.
 1351         
 1352         @return flag indicating a JavaScript file (boolean)
 1353         """
 1354         return self.fileext == '.js'
 1355     
 1356     def isPixmapFile(self):
 1357         """
 1358         Public method to check, if this file is a pixmap file.
 1359         
 1360         @return flag indicating a pixmap file (boolean)
 1361         """
 1362         return self.fileext[1:] in QImageReader.supportedImageFormats()
 1363     
 1364     def isSvgFile(self):
 1365         """
 1366         Public method to check, if this file is a SVG file.
 1367         
 1368         @return flag indicating a SVG file (boolean)
 1369         """
 1370         return self.fileext == '.svg'
 1371     
 1372     def isDFile(self):
 1373         """
 1374         Public method to check, if this file is a D file.
 1375         
 1376         @return flag indicating a D file (boolean)
 1377         """
 1378         return (
 1379             self.fileext in ['.d', '.di'] or
 1380             (self.fileext == "" and self.sourceLanguage == "D")
 1381         )
 1382     
 1383     def lessThan(self, other, column, order):
 1384         """
 1385         Public method to check, if the item is less than the other one.
 1386         
 1387         @param other reference to item to compare against (BrowserItem)
 1388         @param column column number to use for the comparison (integer)
 1389         @param order sort order (Qt.SortOrder) (for special sorting)
 1390         @return true, if this item is less than other (boolean)
 1391         """
 1392         if not issubclass(other.__class__, BrowserFileItem):
 1393             if Preferences.getUI("BrowsersListFoldersFirst"):
 1394                 return order == Qt.DescendingOrder
 1395         
 1396         if issubclass(other.__class__, BrowserFileItem):
 1397             sinit = os.path.basename(self._filename).startswith('__init__.py')
 1398             oinit = os.path.basename(other.fileName()).startswith(
 1399                 '__init__.py')
 1400             if sinit and not oinit:
 1401                 return order == Qt.AscendingOrder
 1402             if not sinit and oinit:
 1403                 return order == Qt.DescendingOrder
 1404         
 1405         return BrowserItem.lessThan(self, other, column, order)
 1406 
 1407 
 1408 class BrowserClassItem(BrowserItem):
 1409     """
 1410     Class implementing the data structure for browser class items.
 1411     """
 1412     def __init__(self, parent, cl, filename):
 1413         """
 1414         Constructor
 1415         
 1416         @param parent parent item
 1417         @param cl Class object to be shown
 1418         @param filename filename of the file defining this class
 1419         """
 1420         name = cl.name
 1421         if hasattr(cl, 'super') and cl.super:
 1422             supers = []
 1423             for sup in cl.super:
 1424                 try:
 1425                     sname = sup.name
 1426                     if sup.module != cl.module:
 1427                         sname = "{0}.{1}".format(sup.module, sname)
 1428                 except AttributeError:
 1429                     sname = sup
 1430                 supers.append(sname)
 1431             name = name + "({0})".format(", ".join(supers))
 1432         
 1433         BrowserItem.__init__(self, parent, name)
 1434         
 1435         self.type_ = BrowserItemClass
 1436         self._name = name
 1437         self._classObject = cl
 1438         self._filename = filename
 1439         
 1440         import Utilities.ClassBrowsers.ClbrBaseClasses
 1441         self.isfunction = isinstance(
 1442             self._classObject,
 1443             Utilities.ClassBrowsers.ClbrBaseClasses.Function)
 1444         self.ismodule = isinstance(
 1445             self._classObject,
 1446             Utilities.ClassBrowsers.ClbrBaseClasses.Module)
 1447         self.isenum = isinstance(
 1448             self._classObject,
 1449             Utilities.ClassBrowsers.ClbrBaseClasses.Enum)
 1450         if self.isfunction:
 1451             if cl.isPrivate():
 1452                 self.icon = UI.PixmapCache.getIcon("method_private")
 1453             elif cl.isProtected():
 1454                 self.icon = UI.PixmapCache.getIcon("method_protected")
 1455             else:
 1456                 self.icon = UI.PixmapCache.getIcon("method")
 1457             self.itemData[0] = "{0}({1})".format(
 1458                 name, ", ".join(self._classObject.parameters))
 1459             if self._classObject.annotation:
 1460                 self.itemData[0] = "{0} {1}".format(
 1461                     self.itemData[0], self._classObject.annotation)
 1462             ## if no defaults are wanted
 1463             ## ....format(name,
 1464             ##            ", ".join([e.split('=')[0].strip() \
 1465             ##                       for e in self._classObject.parameters]))
 1466         elif self.ismodule:
 1467             self.icon = UI.PixmapCache.getIcon("module")
 1468         elif self.isenum:
 1469             self.icon = UI.PixmapCache.getIcon("attribute")
 1470         else:
 1471             if cl.isPrivate():
 1472                 self.icon = UI.PixmapCache.getIcon("class_private")
 1473             elif cl.isProtected():
 1474                 self.icon = UI.PixmapCache.getIcon("class_protected")
 1475             else:
 1476                 self.icon = UI.PixmapCache.getIcon("class")
 1477         if (
 1478             self._classObject and
 1479             (self._classObject.methods or
 1480              self._classObject.classes or
 1481              self._classObject.attributes)
 1482         ):
 1483             self._populated = False
 1484             self._lazyPopulation = True
 1485     
 1486     def name(self):
 1487         """
 1488         Public method to return the name of the item.
 1489         
 1490         @return name of the item (string)
 1491         """
 1492         return '{0}@@{1}'.format(self._filename, self.lineno())
 1493     
 1494     def fileName(self):
 1495         """
 1496         Public method returning the filename.
 1497         
 1498         @return filename (string)
 1499         """
 1500         return self._filename
 1501     
 1502     def classObject(self):
 1503         """
 1504         Public method returning the class object.
 1505         
 1506         @return reference to the class object
 1507         """
 1508         return self._classObject
 1509     
 1510     def lineno(self):
 1511         """
 1512         Public method returning the line number defining this object.
 1513         
 1514         @return line number defining the object (integer)
 1515         """
 1516         return self._classObject.lineno
 1517     
 1518     def boundaries(self):
 1519         """
 1520         Public method returning the boundaries of the method definition.
 1521         
 1522         @return tuple with start end end line number (integer, integer)
 1523         """
 1524         return (self._classObject.lineno, self._classObject.endlineno)
 1525     
 1526     def lessThan(self, other, column, order):
 1527         """
 1528         Public method to check, if the item is less than the other one.
 1529         
 1530         @param other reference to item to compare against (BrowserItem)
 1531         @param column column number to use for the comparison (integer)
 1532         @param order sort order (Qt.SortOrder) (for special sorting)
 1533         @return true, if this item is less than other (boolean)
 1534         """
 1535         if issubclass(
 1536             other.__class__,
 1537             (BrowserCodingItem, BrowserClassAttributesItem)
 1538         ):
 1539             return order == Qt.DescendingOrder
 1540         
 1541         if (
 1542             Preferences.getUI("BrowsersListContentsByOccurrence") and
 1543             column == 0
 1544         ):
 1545             if order == Qt.AscendingOrder:
 1546                 return self.lineno() < other.lineno()
 1547             else:
 1548                 return self.lineno() > other.lineno()
 1549         
 1550         return BrowserItem.lessThan(self, other, column, order)
 1551     
 1552     def isPublic(self):
 1553         """
 1554         Public method returning the public visibility status.
 1555         
 1556         @return flag indicating public visibility (boolean)
 1557         """
 1558         return self._classObject.isPublic()
 1559 
 1560 
 1561 class BrowserMethodItem(BrowserItem):
 1562     """
 1563     Class implementing the data structure for browser method items.
 1564     """
 1565     def __init__(self, parent, fn, filename):
 1566         """
 1567         Constructor
 1568         
 1569         @param parent parent item
 1570         @param fn Function object to be shown
 1571         @param filename filename of the file defining this class (string)
 1572         """
 1573         name = fn.name
 1574         BrowserItem.__init__(self, parent, name)
 1575         
 1576         import Utilities.ClassBrowsers.ClbrBaseClasses
 1577         self.type_ = BrowserItemMethod
 1578         self._name = name
 1579         self._functionObject = fn
 1580         self._filename = filename
 1581         if (
 1582             self._functionObject.modifier ==
 1583             Utilities.ClassBrowsers.ClbrBaseClasses.Function.Static
 1584         ):
 1585             self.icon = UI.PixmapCache.getIcon("method_static")
 1586         elif (
 1587             self._functionObject.modifier ==
 1588             Utilities.ClassBrowsers.ClbrBaseClasses.Function.Class
 1589         ):
 1590             self.icon = UI.PixmapCache.getIcon("method_class")
 1591         elif self._functionObject.isPrivate():
 1592             self.icon = UI.PixmapCache.getIcon("method_private")
 1593         elif self._functionObject.isProtected():
 1594             self.icon = UI.PixmapCache.getIcon("method_protected")
 1595         else:
 1596             self.icon = UI.PixmapCache.getIcon("method")
 1597         self.itemData[0] = "{0}({1})".format(
 1598             name, ", ".join(self._functionObject.parameters))
 1599         if self._functionObject.annotation:
 1600             self.itemData[0] = "{0} {1}".format(
 1601                 self.itemData[0], self._functionObject.annotation)
 1602         # if no defaults are wanted
 1603         # ....format(name,
 1604         #            ", ".join([e.split('=')[0].strip()
 1605         #                       for e in self._functionObject.parameters]))
 1606         if (
 1607             self._functionObject and
 1608             (self._functionObject.methods or self._functionObject.classes)
 1609         ):
 1610             self._populated = False
 1611             self._lazyPopulation = True
 1612     
 1613     def name(self):
 1614         """
 1615         Public method to return the name of the item.
 1616         
 1617         @return name of the item (string)
 1618         """
 1619         return '{0}@@{1}'.format(self._filename, self.lineno())
 1620     
 1621     def fileName(self):
 1622         """
 1623         Public method returning the filename.
 1624         
 1625         @return filename (string)
 1626         """
 1627         return self._filename
 1628     
 1629     def functionObject(self):
 1630         """
 1631         Public method returning the function object.
 1632         
 1633         @return reference to the function object
 1634         """
 1635         return self._functionObject
 1636     
 1637     def lineno(self):
 1638         """
 1639         Public method returning the line number defining this object.
 1640         
 1641         @return line number defining the object (integer)
 1642         """
 1643         return self._functionObject.lineno
 1644     
 1645     def boundaries(self):
 1646         """
 1647         Public method returning the boundaries of the method definition.
 1648         
 1649         @return tuple with start end end line number (integer, integer)
 1650         """
 1651         return (self._functionObject.lineno, self._functionObject.endlineno)
 1652     
 1653     def lessThan(self, other, column, order):
 1654         """
 1655         Public method to check, if the item is less than the other one.
 1656         
 1657         @param other reference to item to compare against (BrowserItem)
 1658         @param column column number to use for the comparison (integer)
 1659         @param order sort order (Qt.SortOrder) (for special sorting)
 1660         @return true, if this item is less than other (boolean)
 1661         """
 1662         if issubclass(other.__class__, BrowserMethodItem):
 1663             if self._name.startswith('__init__'):
 1664                 return order == Qt.AscendingOrder
 1665             if other._name.startswith('__init__'):
 1666                 return order == Qt.DescendingOrder
 1667         elif issubclass(other.__class__, BrowserClassAttributesItem):
 1668             return order == Qt.DescendingOrder
 1669         
 1670         if (
 1671             Preferences.getUI("BrowsersListContentsByOccurrence") and
 1672             column == 0
 1673         ):
 1674             if order == Qt.AscendingOrder:
 1675                 return self.lineno() < other.lineno()
 1676             else:
 1677                 return self.lineno() > other.lineno()
 1678         
 1679         return BrowserItem.lessThan(self, other, column, order)
 1680     
 1681     def isPublic(self):
 1682         """
 1683         Public method returning the public visibility status.
 1684         
 1685         @return flag indicating public visibility (boolean)
 1686         """
 1687         return self._functionObject.isPublic()
 1688 
 1689 
 1690 class BrowserClassAttributesItem(BrowserItem):
 1691     """
 1692     Class implementing the data structure for browser class attributes items.
 1693     """
 1694     def __init__(self, parent, attributes, text, isClass=False):
 1695         """
 1696         Constructor
 1697         
 1698         @param parent parent item
 1699         @param attributes list of attributes
 1700         @param text text to be shown by this item (string)
 1701         @param isClass flag indicating class attributes (boolean)
 1702         """
 1703         BrowserItem.__init__(self, parent, text)
 1704         
 1705         self.type_ = BrowserItemAttributes
 1706         self._attributes = attributes.copy()
 1707         self._populated = False
 1708         self._lazyPopulation = True
 1709         if isClass:
 1710             self.icon = UI.PixmapCache.getIcon("attributes_class")
 1711         else:
 1712             self.icon = UI.PixmapCache.getIcon("attributes")
 1713         self.__isClass = isClass
 1714     
 1715     def name(self):
 1716         """
 1717         Public method to return the name of the item.
 1718         
 1719         @return name of the item (string)
 1720         """
 1721         return '{0}@@{1}'.format(self.parentItem.name(), self.data(0))
 1722     
 1723     def attributes(self):
 1724         """
 1725         Public method returning the attribute list.
 1726         
 1727         @return reference to the list of attributes
 1728         """
 1729         return self._attributes
 1730     
 1731     def isClassAttributes(self):
 1732         """
 1733         Public method returning the attributes type.
 1734         
 1735         @return flag indicating class attributes (boolean)
 1736         """
 1737         return self.__isClass
 1738     
 1739     def lessThan(self, other, column, order):
 1740         """
 1741         Public method to check, if the item is less than the other one.
 1742         
 1743         @param other reference to item to compare against (BrowserItem)
 1744         @param column column number to use for the comparison (integer)
 1745         @param order sort order (Qt.SortOrder) (for special sorting)
 1746         @return true, if this item is less than other (boolean)
 1747         """
 1748         if issubclass(other.__class__, BrowserCodingItem):
 1749             return order == Qt.DescendingOrder
 1750         elif issubclass(
 1751             other.__class__,
 1752             (BrowserClassItem, BrowserMethodItem)
 1753         ):
 1754             return order == Qt.AscendingOrder
 1755         
 1756         return BrowserItem.lessThan(self, other, column, order)
 1757 
 1758 
 1759 class BrowserClassAttributeItem(BrowserItem):
 1760     """
 1761     Class implementing the data structure for browser class attribute items.
 1762     """
 1763     def __init__(self, parent, attribute, isClass=False):
 1764         """
 1765         Constructor
 1766         
 1767         @param parent parent item
 1768         @param attribute reference to the attribute object
 1769         @param isClass flag indicating a class attribute (boolean)
 1770         """
 1771         BrowserItem.__init__(self, parent, attribute.name)
 1772         
 1773         self.type_ = BrowserItemAttribute
 1774         self._attributeObject = attribute
 1775         self.__public = attribute.isPublic()
 1776         if isClass:
 1777             self.icon = UI.PixmapCache.getIcon("attribute_class")
 1778         elif attribute.isPrivate():
 1779             self.icon = UI.PixmapCache.getIcon("attribute_private")
 1780         elif attribute.isProtected():
 1781             self.icon = UI.PixmapCache.getIcon("attribute_protected")
 1782         else:
 1783             self.icon = UI.PixmapCache.getIcon("attribute")
 1784     
 1785     def isPublic(self):
 1786         """
 1787         Public method returning the public visibility status.
 1788         
 1789         @return flag indicating public visibility (boolean)
 1790         """
 1791         return self.__public
 1792     
 1793     def attributeObject(self):
 1794         """
 1795         Public method returning the class object.
 1796         
 1797         @return reference to the class object
 1798         """
 1799         return self._attributeObject
 1800     
 1801     def fileName(self):
 1802         """
 1803         Public method returning the filename.
 1804         
 1805         @return filename (string)
 1806         """
 1807         return self._attributeObject.file
 1808     
 1809     def lineno(self):
 1810         """
 1811         Public method returning the line number defining this object.
 1812         
 1813         @return line number defining the object (integer)
 1814         """
 1815         return self._attributeObject.lineno
 1816     
 1817     def linenos(self):
 1818         """
 1819         Public method returning the line numbers this object is assigned to.
 1820         
 1821         @return line number the object is assigned to (list of integers)
 1822         """
 1823         return self._attributeObject.linenos[:]
 1824     
 1825     def lessThan(self, other, column, order):
 1826         """
 1827         Public method to check, if the item is less than the other one.
 1828         
 1829         @param other reference to item to compare against (BrowserItem)
 1830         @param column column number to use for the comparison (integer)
 1831         @param order sort order (Qt.SortOrder) (for special sorting)
 1832         @return true, if this item is less than other (boolean)
 1833         """
 1834         if (
 1835             Preferences.getUI("BrowsersListContentsByOccurrence") and
 1836             column == 0
 1837         ):
 1838             if order == Qt.AscendingOrder:
 1839                 return self.lineno() < other.lineno()
 1840             else:
 1841                 return self.lineno() > other.lineno()
 1842         
 1843         return BrowserItem.lessThan(self, other, column, order)
 1844 
 1845 
 1846 class BrowserGlobalsItem(BrowserClassAttributesItem):
 1847     """
 1848     Class implementing the data structure for browser globals items.
 1849     """
 1850     def __init__(self, parent, attributes, text):
 1851         """
 1852         Constructor
 1853         
 1854         @param parent parent item
 1855         @param attributes list of attributes
 1856         @param text text to be shown by this item (string)
 1857         """
 1858         BrowserClassAttributesItem.__init__(self, parent, attributes, text)
 1859 
 1860 
 1861 class BrowserCodingItem(BrowserItem):
 1862     """
 1863     Class implementing the data structure for browser coding items.
 1864     """
 1865     def __init__(self, parent, text):
 1866         """
 1867         Constructor
 1868         
 1869         @param parent parent item
 1870         @param text text to be shown by this item (string)
 1871         """
 1872         BrowserItem.__init__(self, parent, text)
 1873         
 1874         self.type_ = BrowserItemCoding
 1875         self.icon = UI.PixmapCache.getIcon("textencoding")
 1876     
 1877     def lessThan(self, other, column, order):
 1878         """
 1879         Public method to check, if the item is less than the other one.
 1880         
 1881         @param other reference to item to compare against (BrowserItem)
 1882         @param column column number to use for the comparison (integer)
 1883         @param order sort order (Qt.SortOrder) (for special sorting)
 1884         @return true, if this item is less than other (boolean)
 1885         """
 1886         if issubclass(
 1887             other.__class__,
 1888             (BrowserClassItem, BrowserClassAttributesItem, BrowserImportItem)
 1889         ):
 1890             return order == Qt.AscendingOrder
 1891         
 1892         return BrowserItem.lessThan(self, other, column, order)
 1893 
 1894 
 1895 class BrowserImportsItem(BrowserItem):
 1896     """
 1897     Class implementing the data structure for browser import items.
 1898     """
 1899     def __init__(self, parent, text):
 1900         """
 1901         Constructor
 1902         
 1903         @param parent parent item
 1904         @param text text to be shown by this item (string)
 1905         """
 1906         BrowserItem.__init__(self, parent, text)
 1907         
 1908         self.type_ = BrowserItemImports
 1909         self.icon = UI.PixmapCache.getIcon("imports")
 1910     
 1911     def lessThan(self, other, column, order):
 1912         """
 1913         Public method to check, if the item is less than the other one.
 1914         
 1915         @param other reference to item to compare against (BrowserItem)
 1916         @param column column number to use for the comparison (integer)
 1917         @param order sort order (Qt.SortOrder) (for special sorting)
 1918         @return true, if this item is less than other (boolean)
 1919         """
 1920         if issubclass(
 1921             other.__class__,
 1922             (BrowserClassItem, BrowserClassAttributesItem)
 1923         ):
 1924             return order == Qt.AscendingOrder
 1925         
 1926         return BrowserItem.lessThan(self, other, column, order)
 1927 
 1928 
 1929 class BrowserImportItem(BrowserItem):
 1930     """
 1931     Class implementing the data structure for browser imported module and
 1932     imported names items.
 1933     """
 1934     def __init__(self, parent, text, filename, lineNumbers, isModule=True):
 1935         """
 1936         Constructor
 1937         
 1938         @param parent parent item
 1939         @param text text to be shown by this item (string)
 1940         @param filename name of the file (string)
 1941         @param lineNumbers list of line numbers of the import statement
 1942             (list of integer)
 1943         @param isModule flag indicating a module item entry (boolean)
 1944         """
 1945         BrowserItem.__init__(self, parent, text)
 1946         
 1947         self.__filename = filename
 1948         self.__linenos = lineNumbers[:]
 1949         
 1950         self.type_ = BrowserItemImport
 1951         if isModule:
 1952             self.icon = UI.PixmapCache.getIcon("importedModule")
 1953         else:
 1954             self.icon = UI.PixmapCache.getIcon("importedName")
 1955     
 1956     def fileName(self):
 1957         """
 1958         Public method returning the filename.
 1959         
 1960         @return filename (string)
 1961         """
 1962         return self.__filename
 1963     
 1964     def lineno(self):
 1965         """
 1966         Public method returning the line number of the first import.
 1967         
 1968         @return line number of the first import (integer)
 1969         """
 1970         return self.__linenos[0]
 1971     
 1972     def linenos(self):
 1973         """
 1974         Public method returning the line numbers of all imports.
 1975         
 1976         @return line numbers of all imports (list of integers)
 1977         """
 1978         return self.__linenos[:]
 1979     
 1980     def lessThan(self, other, column, order):
 1981         """
 1982         Public method to check, if the item is less than the other one.
 1983         
 1984         @param other reference to item to compare against (BrowserItem)
 1985         @param column column number to use for the comparison (integer)
 1986         @param order sort order (Qt.SortOrder) (for special sorting)
 1987         @return true, if this item is less than other (boolean)
 1988         """
 1989         if (
 1990             Preferences.getUI("BrowsersListContentsByOccurrence") and
 1991             column == 0
 1992         ):
 1993             if order == Qt.AscendingOrder:
 1994                 return self.lineno() < other.lineno()
 1995             else:
 1996                 return self.lineno() > other.lineno()
 1997         
 1998         return BrowserItem.lessThan(self, other, column, order)