src/eric7/QScintilla/EditorOutlineModel.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
11 import contextlib 11 import contextlib
12 12
13 from PyQt6.QtCore import QCoreApplication, QModelIndex 13 from PyQt6.QtCore import QCoreApplication, QModelIndex
14 14
15 from UI.BrowserModel import ( 15 from UI.BrowserModel import (
16 BrowserModel, BrowserItem, BrowserClassItem, BrowserCodingItem, 16 BrowserModel,
17 BrowserGlobalsItem, BrowserImportsItem, BrowserImportItem, 17 BrowserItem,
18 BrowserClassAttributesItem, BrowserMethodItem 18 BrowserClassItem,
19 BrowserCodingItem,
20 BrowserGlobalsItem,
21 BrowserImportsItem,
22 BrowserImportItem,
23 BrowserClassAttributesItem,
24 BrowserMethodItem,
19 ) 25 )
20 26
21 import Preferences 27 import Preferences
22 28
23 29
24 class EditorOutlineModel(BrowserModel): 30 class EditorOutlineModel(BrowserModel):
25 """ 31 """
26 Class implementing the editor outline model. 32 Class implementing the editor outline model.
27 """ 33 """
34
28 SupportedLanguages = ( 35 SupportedLanguages = (
29 "IDL", "JavaScript", "Protocol", "Python3", "MicroPython", "Cython", 36 "IDL",
37 "JavaScript",
38 "Protocol",
39 "Python3",
40 "MicroPython",
41 "Cython",
30 "Ruby", 42 "Ruby",
31 ) 43 )
32 44
33 def __init__(self, editor, populate=True): 45 def __init__(self, editor, populate=True):
34 """ 46 """
35 Constructor 47 Constructor
36 48
37 @param editor reference to the editor containing the source text 49 @param editor reference to the editor containing the source text
38 @type Editor 50 @type Editor
39 @param populate flag indicating to populate the outline 51 @param populate flag indicating to populate the outline
40 @type bool 52 @type bool
41 """ 53 """
42 super().__init__(nopopulate=True) 54 super().__init__(nopopulate=True)
43 55
44 self.__editor = editor 56 self.__editor = editor
45 57
46 self.__populated = False 58 self.__populated = False
47 59
48 rootData = QCoreApplication.translate("EditorOutlineModel", "Name") 60 rootData = QCoreApplication.translate("EditorOutlineModel", "Name")
49 self.rootItem = BrowserItem(None, rootData) 61 self.rootItem = BrowserItem(None, rootData)
50 62
51 if populate: 63 if populate:
52 self.__populateModel() 64 self.__populateModel()
53 65
54 def __populateModel(self, repopulate=False): 66 def __populateModel(self, repopulate=False):
55 """ 67 """
56 Private slot to populate the model. 68 Private slot to populate the model.
57 69
58 @param repopulate flag indicating a repopulation 70 @param repopulate flag indicating a repopulation
59 @type bool 71 @type bool
60 """ 72 """
61 self.__filename = self.__editor.getFileName() 73 self.__filename = self.__editor.getFileName()
62 self.__module = os.path.basename(self.__filename) 74 self.__module = os.path.basename(self.__filename)
63 75
64 language = self.__editor.getLanguage() 76 language = self.__editor.getLanguage()
65 if language in EditorOutlineModel.SupportedLanguages: 77 if language in EditorOutlineModel.SupportedLanguages:
66 if language == "IDL": 78 if language == "IDL":
67 from Utilities.ClassBrowsers import idlclbr 79 from Utilities.ClassBrowsers import idlclbr
80
68 dictionary = idlclbr.scan( 81 dictionary = idlclbr.scan(
69 self.__editor.text(), self.__filename, self.__module) 82 self.__editor.text(), self.__filename, self.__module
83 )
70 idlclbr._modules.clear() 84 idlclbr._modules.clear()
71 elif language == "Protocol": 85 elif language == "Protocol":
72 from Utilities.ClassBrowsers import protoclbr 86 from Utilities.ClassBrowsers import protoclbr
87
73 dictionary = protoclbr.scan( 88 dictionary = protoclbr.scan(
74 self.__editor.text(), self.__filename, self.__module) 89 self.__editor.text(), self.__filename, self.__module
90 )
75 protoclbr._modules.clear() 91 protoclbr._modules.clear()
76 elif language == "Ruby": 92 elif language == "Ruby":
77 from Utilities.ClassBrowsers import rbclbr 93 from Utilities.ClassBrowsers import rbclbr
94
78 dictionary = rbclbr.scan( 95 dictionary = rbclbr.scan(
79 self.__editor.text(), self.__filename, self.__module) 96 self.__editor.text(), self.__filename, self.__module
97 )
80 rbclbr._modules.clear() 98 rbclbr._modules.clear()
81 elif language == "JavaScript": 99 elif language == "JavaScript":
82 from Utilities.ClassBrowsers import jsclbr 100 from Utilities.ClassBrowsers import jsclbr
101
83 dictionary = jsclbr.scan( 102 dictionary = jsclbr.scan(
84 self.__editor.text(), self.__filename, self.__module) 103 self.__editor.text(), self.__filename, self.__module
104 )
85 jsclbr._modules.clear() 105 jsclbr._modules.clear()
86 elif language in ("Python3", "MicroPython", "Cython"): 106 elif language in ("Python3", "MicroPython", "Cython"):
87 from Utilities.ClassBrowsers import pyclbr 107 from Utilities.ClassBrowsers import pyclbr
108
88 dictionary = pyclbr.scan( 109 dictionary = pyclbr.scan(
89 self.__editor.text(), self.__filename, self.__module) 110 self.__editor.text(), self.__filename, self.__module
111 )
90 pyclbr._modules.clear() 112 pyclbr._modules.clear()
91 113
92 keys = list(dictionary.keys()) 114 keys = list(dictionary.keys())
93 if len(keys) > 0: 115 if len(keys) > 0:
94 parentItem = self.rootItem 116 parentItem = self.rootItem
95 117
96 if repopulate: 118 if repopulate:
97 last = len(keys) - 1 119 last = len(keys) - 1
98 if ( 120 if "@@Coding@@" in keys and not Preferences.getEditor(
99 "@@Coding@@" in keys and 121 "SourceOutlineShowCoding"
100 not Preferences.getEditor("SourceOutlineShowCoding")
101 ): 122 ):
102 last -= 1 123 last -= 1
103 self.beginInsertRows(QModelIndex(), 0, last) 124 self.beginInsertRows(QModelIndex(), 0, last)
104 125
105 for key in keys: 126 for key in keys:
106 if key.startswith("@@"): 127 if key.startswith("@@"):
107 # special treatment done later 128 # special treatment done later
108 continue 129 continue
109 cl = dictionary[key] 130 cl = dictionary[key]
110 with contextlib.suppress(AttributeError): 131 with contextlib.suppress(AttributeError):
111 if cl.module == self.__module: 132 if cl.module == self.__module:
112 node = BrowserClassItem( 133 node = BrowserClassItem(parentItem, cl, self.__filename)
113 parentItem, cl, self.__filename)
114 self._addItem(node, parentItem) 134 self._addItem(node, parentItem)
115 if ( 135 if "@@Coding@@" in keys and Preferences.getEditor(
116 "@@Coding@@" in keys and 136 "SourceOutlineShowCoding"
117 Preferences.getEditor("SourceOutlineShowCoding")
118 ): 137 ):
119 node = BrowserCodingItem( 138 node = BrowserCodingItem(
120 parentItem, 139 parentItem,
121 QCoreApplication.translate( 140 QCoreApplication.translate(
122 "EditorOutlineModel", "Coding: {0}") 141 "EditorOutlineModel", "Coding: {0}"
123 .format(dictionary["@@Coding@@"].coding), 142 ).format(dictionary["@@Coding@@"].coding),
124 dictionary["@@Coding@@"].linenumber) 143 dictionary["@@Coding@@"].linenumber,
144 )
125 self._addItem(node, parentItem) 145 self._addItem(node, parentItem)
126 if "@@Globals@@" in keys: 146 if "@@Globals@@" in keys:
127 node = BrowserGlobalsItem( 147 node = BrowserGlobalsItem(
128 parentItem, 148 parentItem,
129 dictionary["@@Globals@@"].globals, 149 dictionary["@@Globals@@"].globals,
130 QCoreApplication.translate( 150 QCoreApplication.translate("EditorOutlineModel", "Globals"),
131 "EditorOutlineModel", "Globals")) 151 )
132 self._addItem(node, parentItem) 152 self._addItem(node, parentItem)
133 if "@@Import@@" in keys or "@@ImportFrom@@" in keys: 153 if "@@Import@@" in keys or "@@ImportFrom@@" in keys:
134 node = BrowserImportsItem( 154 node = BrowserImportsItem(
135 parentItem, 155 parentItem,
136 QCoreApplication.translate( 156 QCoreApplication.translate("EditorOutlineModel", "Imports"),
137 "EditorOutlineModel", "Imports")) 157 )
138 self._addItem(node, parentItem) 158 self._addItem(node, parentItem)
139 if "@@Import@@" in keys: 159 if "@@Import@@" in keys:
140 for importedModule in ( 160 for importedModule in (
141 dictionary["@@Import@@"].getImports().values() 161 dictionary["@@Import@@"].getImports().values()
142 ): 162 ):
143 m_node = BrowserImportItem( 163 m_node = BrowserImportItem(
144 node, 164 node,
145 importedModule.importedModuleName, 165 importedModule.importedModuleName,
146 importedModule.file, 166 importedModule.file,
147 importedModule.linenos) 167 importedModule.linenos,
168 )
148 self._addItem(m_node, node) 169 self._addItem(m_node, node)
149 for importedName, linenos in ( 170 for (
150 importedModule.importedNames.items() 171 importedName,
151 ): 172 linenos,
173 ) in importedModule.importedNames.items():
152 mn_node = BrowserImportItem( 174 mn_node = BrowserImportItem(
153 m_node, 175 m_node,
154 importedName, 176 importedName,
155 importedModule.file, 177 importedModule.file,
156 linenos, 178 linenos,
157 isModule=False) 179 isModule=False,
180 )
158 self._addItem(mn_node, m_node) 181 self._addItem(mn_node, m_node)
159 if repopulate: 182 if repopulate:
160 self.endInsertRows() 183 self.endInsertRows()
161 184
162 self.__populated = True 185 self.__populated = True
163 else: 186 else:
164 self.clear() 187 self.clear()
165 self.__populated = False 188 self.__populated = False
166 189
167 def isPopulated(self): 190 def isPopulated(self):
168 """ 191 """
169 Public method to check, if the model is populated. 192 Public method to check, if the model is populated.
170 193
171 @return flag indicating a populated model 194 @return flag indicating a populated model
172 @rtype bool 195 @rtype bool
173 """ 196 """
174 return self.__populated 197 return self.__populated
175 198
176 def repopulate(self): 199 def repopulate(self):
177 """ 200 """
178 Public slot to repopulate the model. 201 Public slot to repopulate the model.
179 """ 202 """
180 self.clear() 203 self.clear()
181 self.__populateModel(repopulate=True) 204 self.__populateModel(repopulate=True)
182 205
183 def editor(self): 206 def editor(self):
184 """ 207 """
185 Public method to retrieve a reference to the editor. 208 Public method to retrieve a reference to the editor.
186 209
187 @return reference to the editor 210 @return reference to the editor
188 @rtype Editor 211 @rtype Editor
189 """ 212 """
190 return self.__editor 213 return self.__editor
191 214
192 def fileName(self): 215 def fileName(self):
193 """ 216 """
194 Public method to retrieve the file name of the editor. 217 Public method to retrieve the file name of the editor.
195 218
196 @return file name of the editor 219 @return file name of the editor
197 @rtype str 220 @rtype str
198 """ 221 """
199 return self.__filename 222 return self.__filename
200 223
201 def itemIndexByLine(self, lineno): 224 def itemIndexByLine(self, lineno):
202 """ 225 """
203 Public method to find an item's index given a line number. 226 Public method to find an item's index given a line number.
204 227
205 @param lineno one based line number of the item 228 @param lineno one based line number of the item
206 @type int 229 @type int
207 @return index of the item found 230 @return index of the item found
208 @rtype QModelIndex 231 @rtype QModelIndex
209 """ 232 """
233
210 def findItem(lineno, parent): 234 def findItem(lineno, parent):
211 """ 235 """
212 Function to iteratively search for an item containing the given 236 Function to iteratively search for an item containing the given
213 line. 237 line.
214 238
215 @param lineno one based line number of the item 239 @param lineno one based line number of the item
216 @type int 240 @type int
217 @param parent reference to the parent item 241 @param parent reference to the parent item
218 @type BrowserItem 242 @type BrowserItem
219 @return found item or None 243 @return found item or None
230 if itm is not None: 254 if itm is not None:
231 return itm 255 return itm
232 elif isinstance(child, (BrowserClassItem, BrowserMethodItem)): 256 elif isinstance(child, (BrowserClassItem, BrowserMethodItem)):
233 start, end = child.boundaries() 257 start, end = child.boundaries()
234 if end == -1: 258 if end == -1:
235 end = 1000000 # assume end of file 259 end = 1000000 # assume end of file
236 if start <= lineno <= end: 260 if start <= lineno <= end:
237 itm = findItem(lineno, child) 261 itm = findItem(lineno, child)
238 if itm is not None: 262 if itm is not None:
239 return itm 263 return itm
240 else: 264 else:
241 return child 265 return child
242 elif hasattr(child, "linenos"): 266 elif hasattr(child, "linenos"):
243 if lineno in child.linenos(): 267 if lineno in child.linenos():
244 return child 268 return child
245 elif ( 269 elif hasattr(child, "lineno") and lineno == child.lineno():
246 hasattr(child, "lineno") and
247 lineno == child.lineno()
248 ):
249 return child 270 return child
250 else: 271 else:
251 return None 272 return None
252 273
253 if self.__populated: 274 if self.__populated:
254 for rootChild in self.rootItem.children(): 275 for rootChild in self.rootItem.children():
255 itm = None 276 itm = None
256 if isinstance(rootChild, BrowserClassItem): 277 if isinstance(rootChild, BrowserClassItem):
257 start, end = rootChild.boundaries() 278 start, end = rootChild.boundaries()
258 if end == -1: 279 if end == -1:
259 end = 1000000 # assume end of file 280 end = 1000000 # assume end of file
260 if start <= lineno <= end: 281 if start <= lineno <= end:
261 itm = findItem(lineno, rootChild) 282 itm = findItem(lineno, rootChild)
262 if itm is None: 283 if itm is None:
263 itm = rootChild 284 itm = rootChild
264 elif isinstance(rootChild, 285 elif isinstance(rootChild, (BrowserImportsItem, BrowserGlobalsItem)):
265 (BrowserImportsItem, BrowserGlobalsItem)):
266 itm = findItem(lineno, rootChild) 286 itm = findItem(lineno, rootChild)
267 elif ( 287 elif (
268 isinstance(rootChild, BrowserCodingItem) and 288 isinstance(rootChild, BrowserCodingItem)
269 lineno == rootChild.lineno() 289 and lineno == rootChild.lineno()
270 ): 290 ):
271 itm = rootChild 291 itm = rootChild
272 if itm is not None: 292 if itm is not None:
273 return self.createIndex(itm.row(), 0, itm) 293 return self.createIndex(itm.row(), 0, itm)
274 else: 294 else:
275 return QModelIndex() 295 return QModelIndex()
276 296
277 return QModelIndex() 297 return QModelIndex()

eric ide

mercurial