Debugger/CallTraceViewer.py

changeset 2171
c7dd548d67d8
parent 2170
f4e0f6133ace
child 2302
f29e9405c851
equal deleted inserted replaced
2170:f4e0f6133ace 2171:c7dd548d67d8
5 5
6 """ 6 """
7 Module implementing the Call Trace viewer widget. 7 Module implementing the Call Trace viewer widget.
8 """ 8 """
9 9
10 from PyQt4.QtCore import pyqtSlot, pyqtSignal 10 from PyQt4.QtCore import pyqtSlot, pyqtSignal, Qt, QRegExp, QFileInfo
11 from PyQt4.QtGui import QWidget, QTreeWidgetItem 11 from PyQt4.QtGui import QWidget, QTreeWidgetItem
12
13 from E5Gui.E5Application import e5App
14 from E5Gui import E5FileDialog, E5MessageBox
12 15
13 from .Ui_CallTraceViewer import Ui_CallTraceViewer 16 from .Ui_CallTraceViewer import Ui_CallTraceViewer
14 17
15 import UI.PixmapCache 18 import UI.PixmapCache
16 import Preferences 19 import Preferences
20 import Utilities
17 21
18 22
19 class CallTraceViewer(QWidget, Ui_CallTraceViewer): 23 class CallTraceViewer(QWidget, Ui_CallTraceViewer):
20 """ 24 """
21 Class implementing the Call Trace viewer widget. 25 Class implementing the Call Trace viewer widget.
46 self.callTrace.setHeaderItem(self.__headerItem) 50 self.callTrace.setHeaderItem(self.__headerItem)
47 51
48 self.__callStack = [] 52 self.__callStack = []
49 53
50 self.__entryFormat = "{0}:{1} ({2})" 54 self.__entryFormat = "{0}:{1} ({2})"
55 self.__entryRe = QRegExp(r"""(.+):(\d+)\s\((.*)\)""")
56
57 self.__projectMode = False
58 self.__project = None
51 59
52 self.__callTraceEnabled = Preferences.toBool( 60 self.__callTraceEnabled = Preferences.toBool(
53 Preferences.Prefs.settings.value("CallTrace/Enabled", False)) 61 Preferences.Prefs.settings.value("CallTrace/Enabled", False))
54
55 if self.__callTraceEnabled: 62 if self.__callTraceEnabled:
63 self.startTraceButton.setEnabled(False)
64 else:
56 self.stopTraceButton.setEnabled(False) 65 self.stopTraceButton.setEnabled(False)
57 else:
58 self.startTraceButton.setEnabled(False)
59 66
60 self.__dbs.callTraceInfo.connect(self.__addCallTraceInfo) 67 self.__dbs.callTraceInfo.connect(self.__addCallTraceInfo)
61 68
69 def __setCallTraceEnabled(self, enabled):
70 """
71 Private slot to set the call trace enabled status.
72
73 @param enabled flag indicating the new state (boolean)
74 """
75 self.__dbs.setCallTraceEnabled(enabled)
76 self.stopTraceButton.setEnabled(enabled)
77 self.startTraceButton.setEnabled(not enabled)
78 self.__callTraceEnabled = enabled
79 Preferences.Prefs.settings.setValue("CallTrace/Enabled", enabled)
80
62 @pyqtSlot() 81 @pyqtSlot()
63 def on_startTraceButton_clicked(self): 82 def on_startTraceButton_clicked(self):
64 """ 83 """
65 Private slot to start call tracing. 84 Private slot to start call tracing.
66 """ 85 """
67 self.__dbs.setCallTraceEnabled(True) 86 self.__setCallTraceEnabled(True)
68 self.stopTraceButton.setEnabled(True)
69 self.startTraceButton.setEnabled(False)
70 Preferences.Prefs.settings.setValue("CallTrace/Enabled", True)
71 87
72 @pyqtSlot() 88 @pyqtSlot()
73 def on_stopTraceButton_clicked(self): 89 def on_stopTraceButton_clicked(self):
74 """ 90 """
75 Private slot to start call tracing. 91 Private slot to start call tracing.
76 """ 92 """
77 self.__dbs.setCallTraceEnabled(False) 93 self.__setCallTraceEnabled(False)
78 self.stopTraceButton.setEnabled(False)
79 self.startTraceButton.setEnabled(True)
80 Preferences.Prefs.settings.setValue("CallTrace/Enabled", False)
81 94
82 @pyqtSlot() 95 @pyqtSlot()
83 def on_resizeButton_clicked(self): 96 def on_resizeButton_clicked(self):
84 """ 97 """
85 Private slot to resize the columns of the call trace to their contents. 98 Private slot to resize the columns of the call trace to their contents.
95 self.clear() 108 self.clear()
96 109
97 @pyqtSlot() 110 @pyqtSlot()
98 def on_saveButton_clicked(self): 111 def on_saveButton_clicked(self):
99 """ 112 """
100 Slot documentation goes here. 113 Private slot to save the call trace info to a file.
101 """ 114 """
102 # TODO: not implemented yet 115 if self.callTrace.topLevelItemCount() > 0:
103 raise NotImplementedError 116 fname, selectedFilter = E5FileDialog.getSaveFileNameAndFilter(
117 self,
118 self.trUtf8("Save Call Trace Info"),
119 "",
120 self.trUtf8("Text Files (*.txt);;All Files (*)"),
121 None,
122 E5FileDialog.Options(E5FileDialog.DontConfirmOverwrite))
123 if fname:
124 ext = QFileInfo(fname).suffix()
125 if not ext:
126 ex = selectedFilter.split("(*")[1].split(")")[0]
127 if ex:
128 fname += ex
129 if QFileInfo(fname).exists():
130 res = E5MessageBox.yesNo(self,
131 self.trUtf8("Save Call Trace Info"),
132 self.trUtf8("<p>The file <b>{0}</b> already exists."
133 " Overwrite it?</p>").format(fname),
134 icon=E5MessageBox.Warning)
135 if not res:
136 return
137 fname = Utilities.toNativeSeparators(fname)
138
139 try:
140 f = open(fname, "w", encoding="utf-8")
141 itm = self.callTrace.topLevelItem(0)
142 while itm is not None:
143 isCall = itm.data(0, Qt.UserRole)
144 if isCall:
145 call = "->"
146 else:
147 call = "<-"
148 f.write("{0} {1} || {2}\n".format(call,
149 itm.text(1), itm.text(2)))
150 itm = self.callTrace.itemBelow(itm)
151 f.close()
152 except IOError as err:
153 E5MessageBox.critical(self,
154 self.trUtf8("Error saving Call Trace Info"),
155 self.trUtf8("""<p>The call trace info could not be written"""
156 """ to <b>{0}</b></p><p>Reason: {1}</p>""")\
157 .format(fname, str(err)))
104 158
105 @pyqtSlot(QTreeWidgetItem, int) 159 @pyqtSlot(QTreeWidgetItem, int)
106 def on_callTrace_itemDoubleClicked(self, item, column): 160 def on_callTrace_itemDoubleClicked(self, item, column):
107 """ 161 """
108 Slot documentation goes here. 162 Private slot to open the double clicked file in an editor.
109 """ 163
110 # TODO: not implemented yet 164 @param item reference to the double clicked item (QTreeWidgetItem)
111 raise NotImplementedError 165 @param column column that was double clicked (integer)
166 """
167 if item is not None and column > 0:
168 columnStr = item.text(column)
169 if self.__entryRe.exactMatch(columnStr.strip()):
170 filename, lineno, func = self.__entryRe.capturedTexts()[1:]
171 try:
172 lineno = int(lineno)
173 except ValueError:
174 # do nothing, if the line info is not an integer
175 return
176 if self.__projectMode:
177 filename = self.__project.getAbsolutePath(filename)
178 self.sourceFile.emit(filename, lineno)
112 179
113 def clear(self): 180 def clear(self):
114 """ 181 """
115 Public slot to clear the call trace info. 182 Public slot to clear the call trace info.
116 """ 183 """
117 self.callTrace.clear() 184 self.callTrace.clear()
118 self.__callStack = [] 185 self.__callStack = []
186
187 def setProjectMode(self, enabled):
188 """
189 Public slot to set the call trace viewer to project mode.
190
191 In project mode the call trace info is shown with project relative
192 path names.
193
194 @param enabled flag indicating to enable the project mode (boolean)
195 """
196 self.__projectMode = enabled
197 if enabled and self.__project is None:
198 self.__project = e5App().getObject("Project")
119 199
120 def __addCallTraceInfo(self, isCall, fromFile, fromLine, fromFunction, 200 def __addCallTraceInfo(self, isCall, fromFile, fromLine, fromFunction,
121 toFile, toLine, toFunction): 201 toFile, toLine, toFunction):
122 """ 202 """
123 Private method to add an entry to the call trace viewer. 203 Private method to add an entry to the call trace viewer.
134 icon = UI.PixmapCache.getIcon("forward.png") 214 icon = UI.PixmapCache.getIcon("forward.png")
135 else: 215 else:
136 icon = UI.PixmapCache.getIcon("back.png") 216 icon = UI.PixmapCache.getIcon("back.png")
137 parentItem = self.__callStack[-1] if self.__callStack else self.callTrace 217 parentItem = self.__callStack[-1] if self.__callStack else self.callTrace
138 218
219 if self.__projectMode:
220 fromFile = self.__project.getRelativePath(fromFile)
221 toFile = self.__project.getRelativePath(toFile)
222
139 itm = QTreeWidgetItem(parentItem, ["", 223 itm = QTreeWidgetItem(parentItem, ["",
140 self.__entryFormat.format(fromFile, fromLine, fromFunction), 224 self.__entryFormat.format(fromFile, fromLine, fromFunction),
141 self.__entryFormat.format(toFile, toLine, toFunction)]) 225 self.__entryFormat.format(toFile, toLine, toFunction)])
142 itm.setIcon(0, icon) 226 itm.setIcon(0, icon)
227 itm.setData(0, Qt.UserRole, isCall)
143 itm.setExpanded(True) 228 itm.setExpanded(True)
144 229
145 if isCall: 230 if isCall:
146 self.__callStack.append(itm) 231 self.__callStack.append(itm)
147 else: 232 else:
148 self.__callStack.pop(-1) 233 if self.__callStack:
234 self.__callStack.pop(-1)
149 235
150 def isCallTraceEnabled(self): 236 def isCallTraceEnabled(self):
151 """ 237 """
152 Public method to get the state of the call trace function. 238 Public method to get the state of the call trace function.
153 239

eric ide

mercurial