|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 # Copyright (c) 2011 Detlev Offenbach <detlev@die-offenbachs.de> |
|
4 # |
|
5 |
|
6 """ |
|
7 Module implementing the editor assembly widget containing the navigation combos and |
|
8 the editor widget. |
|
9 """ |
|
10 |
|
11 from PyQt4.QtCore import QTimer |
|
12 from PyQt4.QtGui import QWidget, QGridLayout, QComboBox |
|
13 |
|
14 from .Editor import Editor |
|
15 |
|
16 from Utilities.ModuleParser import Module, Function, getTypeFromTypeName |
|
17 |
|
18 import UI.PixmapCache |
|
19 |
|
20 |
|
21 class EditorAssembly(QWidget): |
|
22 """ |
|
23 Class implementing the editor assembly widget containing the navigation combos and |
|
24 the editor widget. |
|
25 """ |
|
26 def __init__(self, dbs, fn=None, vm=None, filetype="", editor=None, tv=None): |
|
27 """ |
|
28 Constructor |
|
29 |
|
30 @param dbs reference to the debug server object |
|
31 @param fn name of the file to be opened (string). If it is None, |
|
32 a new (empty) editor is opened |
|
33 @param vm reference to the view manager object (ViewManager.ViewManager) |
|
34 @param filetype type of the source file (string) |
|
35 @param editor reference to an Editor object, if this is a cloned view |
|
36 @param tv reference to the task viewer object |
|
37 """ |
|
38 super().__init__() |
|
39 |
|
40 self.__layout = QGridLayout(self) |
|
41 self.__layout.setContentsMargins(0, 0, 0, 0) |
|
42 self.__layout.setSpacing(1) |
|
43 |
|
44 self.__globalsCombo = QComboBox() |
|
45 self.__membersCombo = QComboBox() |
|
46 self.__editor = Editor(dbs, fn, vm, filetype, editor, tv) |
|
47 |
|
48 self.__layout.addWidget(self.__globalsCombo, 0, 0) |
|
49 self.__layout.addWidget(self.__membersCombo, 0, 1) |
|
50 self.__layout.addWidget(self.__editor, 1, 0, 1, -1) |
|
51 |
|
52 self.__module = None |
|
53 |
|
54 self.__globalsCombo.activated[int].connect(self.__globalsActivated) |
|
55 self.__membersCombo.activated[int].connect(self.__membersActivated) |
|
56 |
|
57 self.__parseTimer = QTimer(self) |
|
58 self.__parseTimer.setSingleShot(True) |
|
59 self.__parseTimer.setInterval(5 * 1000) |
|
60 self.__parseTimer.timeout.connect(self.__parseEditor) |
|
61 self.__editor.textChanged.connect(self.__resetParseTimer) |
|
62 |
|
63 QTimer.singleShot(0, self.__parseEditor) |
|
64 |
|
65 def getEditor(self): |
|
66 """ |
|
67 Public method to get the reference to the editor widget. |
|
68 |
|
69 @return reference to the editor widget (Editor) |
|
70 """ |
|
71 return self.__editor |
|
72 |
|
73 def __globalsActivated(self, index): |
|
74 """ |
|
75 Private method to jump to the line of the selected global entry and to populate |
|
76 the members combo box. |
|
77 |
|
78 @param index index of the selected entry (integer) |
|
79 """ |
|
80 # step 1: go to the line of the selected entry |
|
81 lineno = self.__globalsCombo.itemData(index) |
|
82 txt = self.__editor.text(lineno - 1).rstrip() |
|
83 pos = len(txt.replace(txt.strip(), "")) |
|
84 self.__editor.gotoLine(lineno, pos if pos == 0 else pos +1) |
|
85 self.__editor.setFocus() |
|
86 |
|
87 # step 2: populate the members combo, if the entry is a class |
|
88 self.__membersCombo.clear() |
|
89 entryName = self.__globalsCombo.itemText(index) |
|
90 if self.__module and entryName in self.__module.classes: |
|
91 cl = self.__module.classes[entryName] |
|
92 |
|
93 # step 2.1: add class methods |
|
94 items = [] |
|
95 for meth in cl.methods.values(): |
|
96 if meth.modifier == Function.Static: |
|
97 icon = UI.PixmapCache.getIcon("method_static.png") |
|
98 elif meth.modifier == Function.Class: |
|
99 icon = UI.PixmapCache.getIcon("method_class.png") |
|
100 elif meth.isPrivate(): |
|
101 icon = UI.PixmapCache.getIcon("method_private.png") |
|
102 elif meth.isProtected(): |
|
103 icon = UI.PixmapCache.getIcon("method_protected.png") |
|
104 else: |
|
105 icon = UI.PixmapCache.getIcon("method.png") |
|
106 items.append((meth.name, icon, meth.lineno)) |
|
107 for itm in sorted(items): |
|
108 self.__membersCombo.addItem(itm[1], itm[0], itm[2]) |
|
109 |
|
110 # step 2.2: add class instance attributes |
|
111 items = [] |
|
112 for attr in cl.attributes.values(): |
|
113 if attr.isPrivate(): |
|
114 icon = UI.PixmapCache.getIcon("attribute_private.png") |
|
115 elif attr.isProtected(): |
|
116 icon = UI.PixmapCache.getIcon("attribute_protected.png") |
|
117 else: |
|
118 icon = UI.PixmapCache.getIcon("attribute.png") |
|
119 items.append((attr.name, icon, attr.lineno)) |
|
120 for itm in sorted(items): |
|
121 self.__membersCombo.addItem(itm[1], itm[0], itm[2]) |
|
122 |
|
123 # step 2.3: add class attributes |
|
124 items = [] |
|
125 icon = UI.PixmapCache.getIcon("attribute_class.png") |
|
126 for glob in cl.globals.values(): |
|
127 items.append((glob.name, icon, glob.lineno)) |
|
128 for itm in sorted(items): |
|
129 self.__membersCombo.addItem(itm[1], itm[0], itm[2]) |
|
130 |
|
131 def __membersActivated(self, index): |
|
132 """ |
|
133 Private method to jump to the line of the selected members entry. |
|
134 |
|
135 @param index index of the selected entry (integer) |
|
136 """ |
|
137 lineno = self.__membersCombo.itemData(index) |
|
138 txt = self.__editor.text(lineno - 1).rstrip() |
|
139 pos = len(txt.replace(txt.strip(), "")) |
|
140 self.__editor.gotoLine(lineno, pos if pos == 0 else pos +1) |
|
141 self.__editor.setFocus() |
|
142 |
|
143 def __resetParseTimer(self): |
|
144 """ |
|
145 Private slot to reset the parse timer. |
|
146 """ |
|
147 self.__parseTimer.stop() |
|
148 self.__parseTimer.start() |
|
149 |
|
150 def __parseEditor(self): |
|
151 """ |
|
152 Private method to parse the editor source and repopulate the globals combo. |
|
153 """ |
|
154 self.__module = None |
|
155 sourceType = getTypeFromTypeName(self.__editor.determineFileType()) |
|
156 if sourceType != -1: |
|
157 src = self.__editor.text() |
|
158 if src: |
|
159 fn = self.__editor.getFileName() |
|
160 if fn is None: |
|
161 fn = "" |
|
162 self.__module = Module("", fn, sourceType) |
|
163 self.__module.scan(src) |
|
164 |
|
165 self.__globalsCombo.clear() |
|
166 self.__membersCombo.clear() |
|
167 |
|
168 self.__globalsCombo.addItem("") |
|
169 |
|
170 # step 1: add classes |
|
171 items = [] |
|
172 for cl in self.__module.classes.values(): |
|
173 if cl.isPrivate(): |
|
174 icon = UI.PixmapCache.getIcon("class_private.png") |
|
175 elif cl.isProtected(): |
|
176 icon = UI.PixmapCache.getIcon("class_protected.png") |
|
177 else: |
|
178 icon = UI.PixmapCache.getIcon("class.png") |
|
179 items.append((cl.name, icon, cl.lineno)) |
|
180 for itm in sorted(items): |
|
181 self.__globalsCombo.addItem(itm[1], itm[0], itm[2]) |
|
182 |
|
183 # step 2: add functions |
|
184 items = [] |
|
185 for func in self.__module.functions.values(): |
|
186 if func.isPrivate(): |
|
187 icon = UI.PixmapCache.getIcon("method_private.png") |
|
188 elif func.isProtected(): |
|
189 icon = UI.PixmapCache.getIcon("method_protected.png") |
|
190 else: |
|
191 icon = UI.PixmapCache.getIcon("method.png") |
|
192 items.append((func.name, icon, func.lineno)) |
|
193 for itm in sorted(items): |
|
194 self.__globalsCombo.addItem(itm[1], itm[0], itm[2]) |
|
195 |
|
196 # step 3: add attributes |
|
197 items = [] |
|
198 for glob in self.__module.globals.values(): |
|
199 if glob.isPrivate(): |
|
200 icon = UI.PixmapCache.getIcon("attribute_private.png") |
|
201 elif glob.isProtected(): |
|
202 icon = UI.PixmapCache.getIcon("attribute_protected.png") |
|
203 else: |
|
204 icon = UI.PixmapCache.getIcon("attribute.png") |
|
205 items.append((glob.name, icon, glob.lineno)) |
|
206 for itm in sorted(items): |
|
207 self.__globalsCombo.addItem(itm[1], itm[0], itm[2]) |