src/eric7/QScintilla/EditorOutlineModel.py

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

eric ide

mercurial