]>
Commit | Line | Data |
---|---|---|
1f780e48 RD |
1 | #---------------------------------------------------------------------------- |
2 | # Name: DebuggerService.py | |
3 | # Purpose: Debugger Service for Python. | |
4 | # | |
5 | # Author: Matt Fryer | |
6 | # | |
7 | # Created: 12/9/04 | |
8 | # CVS-ID: $Id$ | |
9 | # Copyright: (c) 2004-2005 ActiveGrid, Inc. | |
10 | # License: wxWindows License | |
11 | #---------------------------------------------------------------------------- | |
12 | ||
13 | import wx | |
14 | import wx.lib.intctrl | |
15 | import wx.lib.docview | |
16 | import wx.lib.dialogs | |
17 | import wx.gizmos | |
18 | import wx._core | |
19 | import wx.lib.pydocview | |
20 | import Service | |
21 | import STCTextEditor | |
22 | import CodeEditor | |
23 | import PythonEditor | |
24 | from IDE import ACTIVEGRID_BASE_IDE | |
25 | if not ACTIVEGRID_BASE_IDE: | |
26 | import ProcessModelEditor | |
27 | import wx.lib.scrolledpanel as scrolled | |
28 | import sys | |
29 | import time | |
30 | import SimpleXMLRPCServer | |
31 | import xmlrpclib | |
32 | import os | |
33 | import threading | |
34 | import process | |
35 | import Queue | |
36 | import SocketServer | |
37 | import ProjectEditor | |
38 | import types | |
39 | from xml.dom.minidom import parse, parseString | |
40 | import bz2 | |
41 | import pickle | |
42 | import DebuggerHarness | |
43 | import traceback | |
44 | import StringIO | |
45 | if wx.Platform == '__WXMSW__': | |
46 | import win32api | |
47 | _WINDOWS = True | |
48 | else: | |
49 | _WINDOWS = False | |
50 | _ = wx.GetTranslation | |
51 | ||
52 | _VERBOSE = False | |
53 | _WATCHES_ON = False | |
54 | ||
55 | # Class to read from stdout or stderr and write the result to a text control. | |
56 | # Args: file=file-like object | |
57 | # callback_function= function that takes a single argument, the line of text | |
58 | # read. | |
59 | class OutputReaderThread(threading.Thread): | |
60 | def __init__(self, file, callback_function, callbackOnExit=None, accumulate=True): | |
61 | threading.Thread.__init__(self) | |
62 | self._file = file | |
63 | self._callback_function = callback_function | |
64 | self._keepGoing = True | |
65 | self._lineCount = 0 | |
66 | self._accumulate = accumulate | |
67 | self._callbackOnExit = callbackOnExit | |
68 | ||
69 | def run(self): | |
70 | file = self._file | |
71 | start = time.time() | |
72 | output = "" | |
73 | while self._keepGoing: | |
74 | try: | |
75 | # This could block--how to handle that? | |
76 | text = file.readline() | |
77 | if text == '' or text == None: | |
78 | self._keepGoing = False | |
79 | elif not self._accumulate: | |
80 | self._callback_function(text) | |
81 | else: | |
82 | # Should use a buffer? StringIO? | |
83 | output += text | |
84 | # Seems as though the read blocks if we got an error, so, to be | |
85 | # sure that at least some of the exception gets printed, always | |
86 | # send the first hundred lines back as they come in. | |
87 | if self._lineCount < 100: | |
88 | self._callback_function(output) | |
89 | self._lineCount += 1 | |
90 | output = "" | |
91 | elif time.time() - start > 0.25: | |
92 | try: | |
93 | self._callback_function(output) | |
94 | except wx._core.PyDeadObjectError: | |
95 | # GUI was killed while we were blocked. | |
96 | self._keepGoing = False | |
97 | start = time.time() | |
98 | output = "" | |
99 | except: | |
100 | tp, val, tb = sys.exc_info() | |
101 | print "Exception in OutputReaderThread.run():", tp, val | |
102 | self._keepGoing = False | |
103 | if self._callbackOnExit: | |
104 | try: | |
105 | self._callbackOnExit() | |
106 | except wx._core.PyDeadObjectError: | |
107 | pass | |
108 | if _VERBOSE: print "Exiting OutputReaderThread" | |
109 | ||
110 | def AskToStop(self): | |
111 | self._keepGoing = False | |
112 | ||
113 | import wx.lib.newevent | |
114 | (UpdateTextEvent, EVT_UPDATE_STDTEXT) = wx.lib.newevent.NewEvent() | |
115 | (UpdateErrorEvent, EVT_UPDATE_ERRTEXT) = wx.lib.newevent.NewEvent() | |
116 | ||
117 | class Executor: | |
118 | ||
119 | def GetPythonExecutablePath(): | |
120 | config = wx.ConfigBase_Get() | |
121 | path = config.Read("ActiveGridPythonLocation") | |
122 | if path: | |
123 | return path | |
124 | wx.MessageBox(_("To proceed I need to know the location of the python.exe you would like to use.\nTo set this, go to Tools-->Options and use the 'Python' tab to enter a value.\n"), _("Python Executable Location Unknown")) | |
125 | return None | |
126 | GetPythonExecutablePath = staticmethod(GetPythonExecutablePath) | |
127 | ||
128 | def __init__(self, fileName, wxComponent, arg1=None, arg2=None, arg3=None, arg4=None, arg5=None, arg6=None, arg7=None, arg8=None, arg9=None, callbackOnExit=None): | |
129 | self._fileName = fileName | |
130 | self._stdOutCallback = self.OutCall | |
131 | self._stdErrCallback = self.ErrCall | |
132 | self._callbackOnExit = callbackOnExit | |
133 | self._wxComponent = wxComponent | |
134 | path = Executor.GetPythonExecutablePath() | |
135 | self._cmd = '"' + path + '" -u \"' + fileName + '\"' | |
136 | #Better way to do this? Quotes needed for windows file paths. | |
137 | if(arg1 != None): | |
138 | self._cmd += ' \"' + arg1 + '\"' | |
139 | if(arg2 != None): | |
140 | self._cmd += ' \"' + arg2 + '\"' | |
141 | if(arg3 != None): | |
142 | self._cmd += ' \"' + arg3 + '\"' | |
143 | if(arg4 != None): | |
144 | self._cmd += ' \"' + arg4 + '\"' | |
145 | if(arg5 != None): | |
146 | self._cmd += ' \"' + arg5 + '\"' | |
147 | if(arg6 != None): | |
148 | self._cmd += ' \"' + arg6 + '\"' | |
149 | if(arg7 != None): | |
150 | self._cmd += ' \"' + arg7 + '\"' | |
151 | if(arg8 != None): | |
152 | self._cmd += ' \"' + arg8 + '\"' | |
153 | if(arg9 != None): | |
154 | self._cmd += ' \"' + arg9 + '\"' | |
155 | ||
156 | self._stdOutReader = None | |
157 | self._stdErrReader = None | |
158 | self._process = None | |
159 | ||
160 | def OutCall(self, text): | |
161 | evt = UpdateTextEvent(value = text) | |
162 | wx.PostEvent(self._wxComponent, evt) | |
163 | ||
164 | def ErrCall(self, text): | |
165 | evt = UpdateErrorEvent(value = text) | |
166 | wx.PostEvent(self._wxComponent, evt) | |
167 | ||
168 | def Execute(self, arguments, startIn=None, environment=None): | |
169 | if not startIn: | |
170 | startIn = str(os.getcwd()) | |
171 | startIn = os.path.abspath(startIn) | |
172 | command = self._cmd + ' ' + arguments | |
173 | #stdinput = process.IOBuffer() | |
174 | #self._process = process.ProcessProxy(command, mode='b', cwd=startIn, stdin=stdinput) | |
175 | self._process = process.ProcessOpen(command, mode='b', cwd=startIn, env=environment) | |
176 | # Kick off threads to read stdout and stderr and write them | |
177 | # to our text control. | |
178 | self._stdOutReader = OutputReaderThread(self._process.stdout, self._stdOutCallback, callbackOnExit=self._callbackOnExit) | |
179 | self._stdOutReader.start() | |
180 | self._stdErrReader = OutputReaderThread(self._process.stderr, self._stdErrCallback, accumulate=False) | |
181 | self._stdErrReader.start() | |
182 | ||
183 | ||
184 | def DoStopExecution(self): | |
185 | if(self._process != None): | |
186 | self._process.kill() | |
187 | self._process.close() | |
188 | self._process = None | |
189 | if(self._stdOutReader != None): | |
190 | self._stdOutReader.AskToStop() | |
191 | if(self._stdErrReader != None): | |
192 | self._stdErrReader.AskToStop() | |
193 | ||
194 | class RunCommandUI(wx.Panel): | |
195 | ||
196 | def __init__(self, parent, id, fileName): | |
197 | wx.Panel.__init__(self, parent, id) | |
198 | self._noteBook = parent | |
199 | ||
200 | self.KILL_PROCESS_ID = wx.NewId() | |
201 | self.CLOSE_TAB_ID = wx.NewId() | |
202 | ||
203 | self.Bind(wx.EVT_END_PROCESS, self.OnProcessEnded) | |
204 | ||
205 | # GUI Initialization follows | |
206 | sizer = wx.BoxSizer(wx.HORIZONTAL) | |
207 | self._tb = tb = wx.ToolBar(self, -1, wx.DefaultPosition, (30,1000), wx.TB_VERTICAL| wx.TB_FLAT, "Runner" ) | |
208 | tb.SetToolBitmapSize((16,16)) | |
209 | sizer.Add(tb, 0, wx.EXPAND |wx.ALIGN_LEFT|wx.ALL, 1) | |
210 | ||
211 | close_bmp = getCloseBitmap() | |
212 | tb.AddSimpleTool( self.CLOSE_TAB_ID, close_bmp, _('Close Window')) | |
213 | wx.EVT_TOOL(self, self.CLOSE_TAB_ID, self.OnToolClicked) | |
214 | ||
215 | stop_bmp = getStopBitmap() | |
216 | tb.AddSimpleTool(self.KILL_PROCESS_ID, stop_bmp, _("Stop the Run.")) | |
217 | wx.EVT_TOOL(self, self.KILL_PROCESS_ID, self.OnToolClicked) | |
218 | ||
219 | tb.Realize() | |
220 | self._textCtrl = STCTextEditor.TextCtrl(self, wx.NewId()) #id) | |
221 | sizer.Add(self._textCtrl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1) | |
222 | self._textCtrl.SetViewLineNumbers(False) | |
223 | self._textCtrl.SetReadOnly(True) | |
224 | if wx.Platform == '__WXMSW__': | |
225 | font = "Courier New" | |
226 | else: | |
227 | font = "Courier" | |
228 | self._textCtrl.SetFont(wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = font)) | |
229 | self._textCtrl.SetFontColor(wx.BLACK) | |
230 | self._textCtrl.StyleClearAll() | |
231 | ||
232 | #Disabling for now...may interfere with file open. wx.stc.EVT_STC_DOUBLECLICK(self._textCtrl, self._textCtrl.GetId(), self.OnDoubleClick) | |
233 | ||
234 | self.SetSizer(sizer) | |
235 | sizer.Fit(self) | |
236 | ||
237 | # Executor initialization | |
238 | self._executor = Executor(fileName, self, callbackOnExit=self.ExecutorFinished) | |
239 | self.Bind(EVT_UPDATE_STDTEXT, self.AppendText) | |
240 | self.Bind(EVT_UPDATE_ERRTEXT, self.AppendErrorText) | |
241 | ||
242 | def __del__(self): | |
243 | self._executor.DoStopExecution() | |
244 | ||
245 | def Execute(self, initialArgs, startIn, environment): | |
246 | self._executor.Execute(initialArgs, startIn, environment) | |
247 | ||
248 | def ExecutorFinished(self): | |
249 | self._tb.EnableTool(self.KILL_PROCESS_ID, False) | |
250 | nb = self.GetParent() | |
251 | for i in range(0,nb.GetPageCount()): | |
252 | if self == nb.GetPage(i): | |
253 | text = nb.GetPageText(i) | |
254 | newText = text.replace("Running", "Finished") | |
255 | nb.SetPageText(i, newText) | |
256 | break | |
257 | ||
258 | def StopExecution(self): | |
259 | self.Unbind(EVT_UPDATE_STDTEXT) | |
260 | self.Unbind(EVT_UPDATE_ERRTEXT) | |
261 | self._executor.DoStopExecution() | |
262 | ||
263 | def AppendText(self, event): | |
264 | self._textCtrl.SetReadOnly(False) | |
265 | self._textCtrl.AddText(event.value) | |
266 | self._textCtrl.ScrollToLine(self._textCtrl.GetLineCount()) | |
267 | self._textCtrl.SetReadOnly(True) | |
268 | ||
269 | def AppendErrorText(self, event): | |
270 | self._textCtrl.SetReadOnly(False) | |
271 | self._textCtrl.SetFontColor(wx.RED) | |
272 | self._textCtrl.StyleClearAll() | |
273 | self._textCtrl.AddText(event.value) | |
274 | self._textCtrl.ScrollToLine(self._textCtrl.GetLineCount()) | |
275 | self._textCtrl.SetFontColor(wx.BLACK) | |
276 | self._textCtrl.StyleClearAll() | |
277 | self._textCtrl.SetReadOnly(True) | |
278 | ||
279 | #------------------------------------------------------------------------------ | |
280 | # Event handling | |
281 | #----------------------------------------------------------------------------- | |
282 | ||
283 | def OnToolClicked(self, event): | |
284 | id = event.GetId() | |
285 | ||
286 | if id == self.KILL_PROCESS_ID: | |
287 | self._executor.DoStopExecution() | |
288 | ||
289 | elif id == self.CLOSE_TAB_ID: | |
290 | self._executor.DoStopExecution() | |
291 | index = self._noteBook.GetSelection() | |
292 | self._noteBook.GetPage(index).Show(False) | |
293 | self._noteBook.RemovePage(index) | |
294 | ||
295 | def OnDoubleClick(self, event): | |
296 | # Looking for a stack trace line. | |
297 | lineText, pos = self._textCtrl.GetCurLine() | |
298 | fileBegin = lineText.find("File \"") | |
299 | fileEnd = lineText.find("\", line ") | |
300 | lineEnd = lineText.find(", in ") | |
301 | if lineText == "\n" or fileBegin == -1 or fileEnd == -1 or lineEnd == -1: | |
302 | # Check the line before the one that was clicked on | |
303 | lineNumber = self._textCtrl.GetCurrentLine() | |
304 | if(lineNumber == 0): | |
305 | return | |
306 | lineText = self._textCtrl.GetLine(lineNumber - 1) | |
307 | fileBegin = lineText.find("File \"") | |
308 | fileEnd = lineText.find("\", line ") | |
309 | lineEnd = lineText.find(", in ") | |
310 | if lineText == "\n" or fileBegin == -1 or fileEnd == -1 or lineEnd == -1: | |
311 | return | |
312 | ||
313 | filename = lineText[fileBegin + 6:fileEnd] | |
314 | lineNum = int(lineText[fileEnd + 8:lineEnd]) | |
315 | ||
316 | foundView = None | |
317 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
318 | for openDoc in openDocs: | |
319 | if openDoc.GetFilename() == filename: | |
320 | foundView = openDoc.GetFirstView() | |
321 | break | |
322 | ||
323 | if not foundView: | |
324 | doc = wx.GetApp().GetDocumentManager().CreateDocument(filename, wx.lib.docview.DOC_SILENT) | |
325 | foundView = doc.GetFirstView() | |
326 | ||
327 | if foundView: | |
328 | foundView.GetFrame().SetFocus() | |
329 | foundView.Activate() | |
330 | foundView.GotoLine(lineNum) | |
331 | startPos = foundView.PositionFromLine(lineNum) | |
332 | ||
333 | # FACTOR THIS INTO DocManager | |
334 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
335 | for openDoc in openDocs: | |
336 | if(isinstance(openDoc.GetFirstView(), CodeEditor.CodeView)): | |
337 | openDoc.GetFirstView().GetCtrl().ClearCurrentLineMarkers() | |
338 | ||
339 | foundView.GetCtrl().MarkerAdd(lineNum -1, CodeEditor.CodeCtrl.CURRENT_LINE_MARKER_NUM) | |
340 | ||
341 | def OnProcessEnded(self, evt): | |
342 | self._executor.DoStopExecution() | |
343 | ||
344 | DEFAULT_PORT = 32032 | |
345 | DEFAULT_HOST = 'localhost' | |
346 | PORT_COUNT = 21 | |
347 | ||
348 | class DebugCommandUI(wx.Panel): | |
349 | debuggerPortList = None | |
350 | debuggers = [] | |
351 | ||
352 | def NotifyDebuggersOfBreakpointChange(): | |
353 | for debugger in DebugCommandUI.debuggers: | |
354 | debugger.BreakPointChange() | |
355 | ||
356 | NotifyDebuggersOfBreakpointChange = staticmethod(NotifyDebuggersOfBreakpointChange) | |
357 | ||
358 | def DebuggerRunning(): | |
359 | for debugger in DebugCommandUI.debuggers: | |
360 | if debugger._executor: | |
361 | return True | |
362 | return False | |
363 | DebuggerRunning = staticmethod(DebuggerRunning) | |
364 | ||
365 | def ShutdownAllDebuggers(): | |
366 | for debugger in DebugCommandUI.debuggers: | |
367 | debugger.StopExecution() | |
368 | ||
369 | ShutdownAllDebuggers = staticmethod(ShutdownAllDebuggers) | |
370 | ||
371 | def GetAvailablePort(): | |
372 | for index in range( 0, len(DebugCommandUI.debuggerPortList)): | |
373 | port = DebugCommandUI.debuggerPortList[index] | |
374 | if DebugCommandUI.PortAvailable(port): | |
375 | DebugCommandUI.debuggerPortList.pop(index) | |
376 | return port | |
377 | wx.MessageBox(_("Out of ports for debugging! Please restart the application builder.\nIf that does not work, check for and remove running instances of python."), _("Out of Ports")) | |
378 | assert False, "Out of ports for debugger." | |
379 | ||
380 | GetAvailablePort = staticmethod(GetAvailablePort) | |
381 | ||
382 | def ReturnPortToPool(port): | |
383 | config = wx.ConfigBase_Get() | |
384 | startingPort = config.ReadInt("DebuggerStartingPort", DEFAULT_PORT) | |
385 | if port in range(startingPort, startingPort + PORT_COUNT): | |
386 | DebugCommandUI.debuggerPortList.append(port) | |
387 | ||
388 | ReturnPortToPool = staticmethod(ReturnPortToPool) | |
389 | ||
390 | def PortAvailable(port): | |
391 | config = wx.ConfigBase_Get() | |
392 | hostname = config.Read("DebuggerHostName", DEFAULT_HOST) | |
393 | try: | |
394 | server = AGXMLRPCServer((hostname, port)) | |
395 | server.server_close() | |
396 | if _VERBOSE: print "Port ", str(port), " available." | |
397 | return True | |
398 | except: | |
399 | tp,val,tb = sys.exc_info() | |
400 | if _VERBOSE: traceback.print_exception(tp, val, tb) | |
401 | if _VERBOSE: print "Port ", str(port), " unavailable." | |
402 | return False | |
403 | ||
404 | PortAvailable = staticmethod(PortAvailable) | |
405 | ||
406 | def NewPortRange(): | |
407 | config = wx.ConfigBase_Get() | |
408 | startingPort = config.ReadInt("DebuggerStartingPort", DEFAULT_PORT) | |
409 | DebugCommandUI.debuggerPortList = range(startingPort, startingPort + PORT_COUNT) | |
410 | NewPortRange = staticmethod(NewPortRange) | |
411 | ||
412 | def __init__(self, parent, id, command, service): | |
413 | # Check for ports before creating the panel. | |
414 | if not DebugCommandUI.debuggerPortList: | |
415 | DebugCommandUI.NewPortRange() | |
416 | self._debuggerPort = str(DebugCommandUI.GetAvailablePort()) | |
417 | self._guiPort = str(DebugCommandUI.GetAvailablePort()) | |
418 | self._debuggerBreakPort = str(DebugCommandUI.GetAvailablePort()) | |
419 | ||
420 | wx.Panel.__init__(self, parent, id) | |
421 | ||
422 | self._parentNoteBook = parent | |
423 | self._command = command | |
424 | self._textCtrl = None | |
425 | self._service = service | |
426 | self._executor = None | |
427 | self.STEP_ID = wx.NewId() | |
428 | self.CONTINUE_ID = wx.NewId() | |
429 | self.STEP_OUT_ID = wx.NewId() | |
430 | self.NEXT_ID = wx.NewId() | |
431 | self.KILL_PROCESS_ID = wx.NewId() | |
432 | self.CLOSE_WINDOW_ID = wx.NewId() | |
433 | self.BREAK_INTO_DEBUGGER_ID = wx.NewId() | |
434 | self.CLEAR_ID = wx.NewId() | |
435 | self.ADD_WATCH_ID = wx.NewId() | |
436 | sizer = wx.BoxSizer(wx.VERTICAL) | |
437 | self._tb = tb = wx.ToolBar(self, -1, wx.DefaultPosition, (1000,30), wx.TB_HORIZONTAL| wx.NO_BORDER| wx.TB_FLAT| wx.TB_TEXT, "Debugger" ) | |
438 | sizer.Add(tb, 0, wx.EXPAND |wx.ALIGN_LEFT|wx.ALL, 1) | |
439 | tb.SetToolBitmapSize((16,16)) | |
440 | ||
441 | close_bmp = getCloseBitmap() | |
442 | tb.AddSimpleTool( self.CLOSE_WINDOW_ID, close_bmp, _('Close Window')) | |
443 | wx.EVT_TOOL(self, self.CLOSE_WINDOW_ID, self.StopAndRemoveUI) | |
444 | ||
445 | stop_bmp = getStopBitmap() | |
446 | tb.AddSimpleTool( self.KILL_PROCESS_ID, stop_bmp, _("Stop Debugging")) | |
447 | wx.EVT_TOOL(self, self.KILL_PROCESS_ID, self.StopExecution) | |
448 | ||
449 | tb.AddSeparator() | |
450 | ||
451 | break_bmp = getBreakBitmap() | |
452 | tb.AddSimpleTool( self.BREAK_INTO_DEBUGGER_ID, break_bmp, _("Break into Debugger")) | |
453 | wx.EVT_TOOL(self, self.BREAK_INTO_DEBUGGER_ID, self.BreakExecution) | |
454 | ||
455 | tb.AddSeparator() | |
456 | ||
457 | continue_bmp = getContinueBitmap() | |
458 | tb.AddSimpleTool( self.CONTINUE_ID, continue_bmp, _("Continue Execution")) | |
459 | wx.EVT_TOOL(self, self.CONTINUE_ID, self.OnContinue) | |
460 | ||
461 | tb.AddSeparator() | |
462 | ||
463 | next_bmp = getNextBitmap() | |
464 | tb.AddSimpleTool( self.NEXT_ID, next_bmp, _("Step to next line")) | |
465 | wx.EVT_TOOL(self, self.NEXT_ID, self.OnNext) | |
466 | ||
467 | step_bmp = getStepInBitmap() | |
468 | tb.AddSimpleTool( self.STEP_ID, step_bmp, _("Step in")) | |
469 | wx.EVT_TOOL(self, self.STEP_ID, self.OnSingleStep) | |
470 | ||
471 | stepOut_bmp = getStepReturnBitmap() | |
472 | tb.AddSimpleTool(self.STEP_OUT_ID, stepOut_bmp, _("Stop at function return")) | |
473 | wx.EVT_TOOL(self, self.STEP_OUT_ID, self.OnStepOut) | |
474 | ||
475 | tb.AddSeparator() | |
476 | if _WATCHES_ON: | |
477 | watch_bmp = getAddWatchBitmap() | |
478 | tb.AddSimpleTool(self.ADD_WATCH_ID, watch_bmp, _("Add a watch")) | |
479 | wx.EVT_TOOL(self, self.ADD_WATCH_ID, self.OnAddWatch) | |
480 | tb.AddSeparator() | |
481 | ||
482 | clear_bmp = getClearOutputBitmap() | |
483 | tb.AddSimpleTool(self.CLEAR_ID, clear_bmp, _("Clear output pane")) | |
484 | wx.EVT_TOOL(self, self.CLEAR_ID, self.OnClearOutput) | |
485 | ||
486 | tb.Realize() | |
487 | self.framesTab = None | |
488 | self.DisableWhileDebuggerRunning() | |
489 | self._notebook = wx.Notebook(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.LB_DEFAULT, "Debugger") | |
490 | sizer.Add(self._notebook, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1) | |
491 | self.consoleTab = self.MakeConsoleTab(self._notebook, wx.NewId(), None) | |
492 | self.framesTab = self.MakeFramesTab(self._notebook, wx.NewId(), None) | |
493 | self.breakPointsTab = self.MakeBreakPointsTab(self._notebook, wx.NewId(), None) | |
494 | self._notebook.AddPage(self.consoleTab, "Output") | |
495 | self._notebook.AddPage(self.framesTab, "Frames") | |
496 | self._notebook.AddPage(self.breakPointsTab, "Break Points") | |
497 | ||
498 | self._statusBar = wx.StatusBar( self, -1) | |
499 | self._statusBar.SetFieldsCount(1) | |
500 | sizer.Add(self._statusBar, 0, wx.EXPAND |wx.ALIGN_LEFT|wx.ALL, 1) | |
501 | ||
502 | self.SetStatusText("Starting debug...") | |
503 | ||
504 | self.SetSizer(sizer) | |
505 | sizer.Fit(self) | |
506 | config = wx.ConfigBase_Get() | |
507 | self._debuggerHost = self._guiHost = config.Read("DebuggerHostName", DEFAULT_HOST) | |
508 | url = 'http://' + self._debuggerHost + ':' + self._debuggerPort + '/' | |
509 | self._breakURL = 'http://' + self._debuggerHost + ':' + self._debuggerBreakPort + '/' | |
510 | self._callback = DebuggerCallback(self._guiHost, self._guiPort, url, self._breakURL, self) | |
511 | if DebuggerHarness.__file__.find('library.zip') > 0: | |
512 | try: | |
513 | fname = DebuggerHarness.__file__ | |
514 | parts = fname.split('library.zip') | |
515 | path = os.path.join(parts[0],'activegrid', 'tool', 'DebuggerHarness.py') | |
516 | except: | |
517 | tp, val, tb = sys.exc_info() | |
518 | traceback.print_exception(tp, val, tb) | |
519 | ||
520 | else: | |
521 | print "Starting debugger on these ports: %s, %s, %s" % (str(self._debuggerPort) , str(self._guiPort) , str(self._debuggerBreakPort)) | |
522 | path = DebuggerService.ExpandPath(DebuggerHarness.__file__) | |
523 | self._executor = Executor(path, self, self._debuggerHost, \ | |
524 | self._debuggerPort, self._debuggerBreakPort, self._guiHost, self._guiPort, self._command, callbackOnExit=self.ExecutorFinished) | |
525 | ||
526 | self.Bind(EVT_UPDATE_STDTEXT, self.AppendText) | |
527 | self.Bind(EVT_UPDATE_ERRTEXT, self.AppendErrorText) | |
528 | DebugCommandUI.debuggers.append(self) | |
529 | self._stopped = False | |
530 | ||
531 | def OnSingleStep(self, event): | |
532 | self._callback.SingleStep() | |
533 | ||
534 | def OnContinue(self, event): | |
535 | self._callback.Continue() | |
536 | ||
537 | def OnStepOut(self, event): | |
538 | self._callback.Return() | |
539 | ||
540 | def OnNext(self, event): | |
541 | self._callback.Next() | |
542 | ||
543 | def BreakPointChange(self): | |
544 | if not self._stopped: | |
545 | self._callback.pushBreakpoints() | |
546 | self.breakPointsTab.PopulateBPList() | |
547 | ||
548 | def __del__(self): | |
549 | if self in DebugCommandUI.debuggers: | |
550 | DebugCommandUI.debuggers.remove(self) | |
551 | ||
552 | def SwitchToOutputTab(self): | |
553 | self._notebook.SetSelection(0) | |
554 | ||
555 | def DisableWhileDebuggerRunning(self): | |
556 | self._tb.EnableTool(self.STEP_ID, False) | |
557 | self._tb.EnableTool(self.CONTINUE_ID, False) | |
558 | self._tb.EnableTool(self.STEP_OUT_ID, False) | |
559 | self._tb.EnableTool(self.NEXT_ID, False) | |
560 | self._tb.EnableTool(self.BREAK_INTO_DEBUGGER_ID, True) | |
561 | if _WATCHES_ON: | |
562 | self._tb.EnableTool(self.ADD_WATCH_ID, False) | |
563 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
564 | for openDoc in openDocs: | |
565 | if(isinstance(openDoc.GetFirstView(), CodeEditor.CodeView)): | |
566 | openDoc.GetFirstView().GetCtrl().ClearCurrentLineMarkers() | |
567 | if self.framesTab: | |
568 | self.framesTab.ClearWhileRunning() | |
569 | #wx.GetApp().ProcessPendingEvents() #Yield(True) | |
570 | ||
571 | def EnableWhileDebuggerStopped(self): | |
572 | self._tb.EnableTool(self.STEP_ID, True) | |
573 | self._tb.EnableTool(self.CONTINUE_ID, True) | |
574 | self._tb.EnableTool(self.STEP_OUT_ID, True) | |
575 | self._tb.EnableTool(self.NEXT_ID, True) | |
576 | if _WATCHES_ON: | |
577 | self._tb.EnableTool(self.ADD_WATCH_ID, True) | |
578 | self._tb.EnableTool(self.BREAK_INTO_DEBUGGER_ID, False) | |
579 | #if _WINDOWS: | |
580 | # wx.GetApp().GetTopWindow().RequestUserAttention() | |
581 | ||
582 | def ExecutorFinished(self): | |
583 | if _VERBOSE: print "In ExectorFinished" | |
584 | try: | |
585 | self.DisableAfterStop() | |
586 | except wx._core.PyDeadObjectError: | |
587 | pass | |
588 | try: | |
589 | nb = self.GetParent() | |
590 | for i in range(0, nb.GetPageCount()): | |
591 | if self == nb.GetPage(i): | |
592 | text = nb.GetPageText(i) | |
593 | newText = text.replace("Debugging", "Finished") | |
594 | nb.SetPageText(i, newText) | |
595 | if _VERBOSE: print "In ExectorFinished, changed tab title." | |
596 | break | |
597 | except: | |
598 | if _VERBOSE: print "In ExectorFinished, got exception" | |
599 | ||
600 | def DisableAfterStop(self): | |
601 | self.DisableWhileDebuggerRunning() | |
602 | self._tb.EnableTool(self.BREAK_INTO_DEBUGGER_ID, False) | |
603 | self._tb.EnableTool(self.KILL_PROCESS_ID, False) | |
604 | ||
605 | def SynchCurrentLine(self, filename, lineNum): | |
606 | # FACTOR THIS INTO DocManager | |
607 | self.DeleteCurrentLineMarkers() | |
608 | ||
609 | # Filename will be <string> if we're in a bit of code that was executed from | |
610 | # a string (rather than a file). I haven't been able to get the original string | |
611 | # for display. | |
612 | if filename == '<string>': | |
613 | return | |
614 | foundView = None | |
615 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
616 | for openDoc in openDocs: | |
617 | # This ugliness to prevent comparison failing because the drive letter | |
618 | # gets lowercased occasionally. Don't know why that happens or why it | |
619 | # only happens occasionally. | |
620 | if DebuggerService.ComparePaths(openDoc.GetFilename(),filename): | |
621 | foundView = openDoc.GetFirstView() | |
622 | break | |
623 | ||
624 | if not foundView: | |
625 | if _VERBOSE: | |
626 | print "filename=", filename | |
627 | doc = wx.GetApp().GetDocumentManager().CreateDocument(DebuggerService.ExpandPath(filename), wx.lib.docview.DOC_SILENT) | |
628 | foundView = doc.GetFirstView() | |
629 | ||
630 | if foundView: | |
631 | foundView.GetFrame().SetFocus() | |
632 | foundView.Activate() | |
633 | foundView.GotoLine(lineNum) | |
634 | startPos = foundView.PositionFromLine(lineNum) | |
635 | ||
636 | foundView.GetCtrl().MarkerAdd(lineNum -1, CodeEditor.CodeCtrl.CURRENT_LINE_MARKER_NUM) | |
637 | ||
638 | def DeleteCurrentLineMarkers(self): | |
639 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
640 | for openDoc in openDocs: | |
641 | if(isinstance(openDoc.GetFirstView(), CodeEditor.CodeView)): | |
642 | openDoc.GetFirstView().GetCtrl().ClearCurrentLineMarkers() | |
643 | ||
644 | def LoadFramesListXML(self, framesXML): | |
645 | self.framesTab.LoadFramesListXML(framesXML) | |
646 | ||
647 | def SetStatusText(self, text): | |
648 | self._statusBar.SetStatusText(text,0) | |
649 | ||
650 | def Execute(self, initialArgs, startIn, environment): | |
651 | self._callback.start() | |
652 | self._executor.Execute(initialArgs, startIn, environment) | |
653 | self._callback.waitForRPC() | |
654 | ||
655 | def BreakExecution(self, event): | |
656 | self._callback.BreakExecution() | |
657 | ||
658 | ||
659 | def StopExecution(self, event): | |
660 | self._stopped = True | |
661 | self.DisableAfterStop() | |
662 | try: | |
663 | self._callback.ServerClose() | |
664 | except: | |
665 | pass | |
666 | try: | |
667 | if self._executor: | |
668 | self._executor.DoStopExecution() | |
669 | self._executor = None | |
670 | except: | |
671 | pass | |
672 | self.DeleteCurrentLineMarkers() | |
673 | DebugCommandUI.ReturnPortToPool(self._debuggerPort) | |
674 | DebugCommandUI.ReturnPortToPool(self._guiPort) | |
675 | DebugCommandUI.ReturnPortToPool(self._debuggerBreakPort) | |
676 | ||
677 | def StopAndRemoveUI(self, event): | |
678 | self.StopExecution(None) | |
679 | if self in DebugCommandUI.debuggers: | |
680 | DebugCommandUI.debuggers.remove(self) | |
681 | index = self._parentNoteBook.GetSelection() | |
682 | self._parentNoteBook.GetPage(index).Show(False) | |
683 | self._parentNoteBook.RemovePage(index) | |
684 | ||
685 | def GetConsoleTextControl(self): | |
686 | return self._textCtrl | |
687 | ||
688 | def OnClearOutput(self, event): | |
689 | self._textCtrl.SetReadOnly(False) | |
690 | self._textCtrl.ClearAll() | |
691 | self._textCtrl.SetReadOnly(True) | |
692 | ||
693 | def OnAddWatch(self, event): | |
694 | if self.framesTab: | |
695 | self.framesTab.OnWatch(event) | |
696 | ||
697 | def MakeConsoleTab(self, parent, id, debugger): | |
698 | panel = wx.Panel(parent, id) | |
699 | sizer = wx.BoxSizer(wx.HORIZONTAL) | |
700 | self._textCtrl = STCTextEditor.TextCtrl(panel, wx.NewId()) | |
701 | sizer.Add(self._textCtrl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1) | |
702 | self._textCtrl.SetViewLineNumbers(False) | |
703 | self._textCtrl.SetReadOnly(True) | |
704 | if wx.Platform == '__WXMSW__': | |
705 | font = "Courier New" | |
706 | else: | |
707 | font = "Courier" | |
708 | self._textCtrl.SetFont(wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = font)) | |
709 | self._textCtrl.SetFontColor(wx.BLACK) | |
710 | self._textCtrl.StyleClearAll() | |
711 | panel.SetSizer(sizer) | |
712 | sizer.Fit(panel) | |
713 | ||
714 | return panel | |
715 | ||
716 | def MakeFramesTab(self, parent, id, debugger): | |
717 | panel = FramesUI(parent, id, self) | |
718 | return panel | |
719 | ||
720 | def MakeBreakPointsTab(self, parent, id, debugger): | |
721 | panel = BreakpointsUI(parent, id, self) | |
722 | return panel | |
723 | ||
724 | def AppendText(self, event): | |
725 | self._textCtrl.SetReadOnly(False) | |
726 | self._textCtrl.AddText(event.value) | |
727 | self._textCtrl.ScrollToLine(self._textCtrl.GetLineCount()) | |
728 | self._textCtrl.SetReadOnly(True) | |
729 | ||
730 | def AppendErrorText(self, event): | |
731 | self._textCtrl.SetReadOnly(False) | |
732 | self._textCtrl.SetFontColor(wx.RED) | |
733 | self._textCtrl.StyleClearAll() | |
734 | self._textCtrl.AddText(event.value) | |
735 | self._textCtrl.ScrollToLine(self._textCtrl.GetLineCount()) | |
736 | self._textCtrl.SetFontColor(wx.BLACK) | |
737 | self._textCtrl.StyleClearAll() | |
738 | self._textCtrl.SetReadOnly(True) | |
739 | ||
740 | class BreakpointsUI(wx.Panel): | |
741 | def __init__(self, parent, id, ui): | |
742 | wx.Panel.__init__(self, parent, id) | |
743 | self._ui = ui | |
744 | self.currentItem = None | |
745 | self.clearBPID = wx.NewId() | |
746 | self.Bind(wx.EVT_MENU, self.ClearBreakPoint, id=self.clearBPID) | |
747 | self.syncLineID = wx.NewId() | |
748 | self.Bind(wx.EVT_MENU, self.SyncBPLine, id=self.syncLineID) | |
749 | ||
750 | sizer = wx.BoxSizer(wx.VERTICAL) | |
751 | p1 = self | |
752 | self._bpListCtrl = wx.ListCtrl(p1, -1, pos=wx.DefaultPosition, size=(1000,1000), style=wx.LC_REPORT) | |
753 | sizer.Add(self._bpListCtrl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1) | |
754 | self._bpListCtrl.InsertColumn(0, "File") | |
755 | self._bpListCtrl.InsertColumn(1, "Line") | |
756 | self._bpListCtrl.InsertColumn(2, "Path") | |
757 | self._bpListCtrl.SetColumnWidth(0, 150) | |
758 | self._bpListCtrl.SetColumnWidth(1, 50) | |
759 | self._bpListCtrl.SetColumnWidth(2, 450) | |
760 | self._bpListCtrl.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnListRightClick) | |
761 | self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.ListItemSelected, self._bpListCtrl) | |
762 | self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.ListItemDeselected, self._bpListCtrl) | |
763 | ||
764 | self.PopulateBPList() | |
765 | ||
766 | p1.SetSizer(sizer) | |
767 | sizer.Fit(p1) | |
768 | p1.Layout() | |
769 | ||
770 | def PopulateBPList(self): | |
771 | list = self._bpListCtrl | |
772 | list.DeleteAllItems() | |
773 | ||
774 | bps = wx.GetApp().GetService(DebuggerService).GetMasterBreakpointDict() | |
775 | index = 0 | |
776 | for fileName in bps.keys(): | |
777 | shortFile = os.path.basename(fileName) | |
778 | lines = bps[fileName] | |
779 | if lines: | |
780 | for line in lines: | |
781 | list.InsertStringItem(index, shortFile) | |
782 | list.SetStringItem(index, 1, str(line)) | |
783 | list.SetStringItem(index, 2, fileName) | |
784 | ||
785 | def OnListRightClick(self, event): | |
786 | menu = wx.Menu() | |
787 | item = wx.MenuItem(menu, self.clearBPID, "Clear Breakpoint") | |
788 | menu.AppendItem(item) | |
789 | item = wx.MenuItem(menu, self.syncLineID, "Goto Source Line") | |
790 | menu.AppendItem(item) | |
791 | self.PopupMenu(menu, event.GetPosition()) | |
792 | menu.Destroy() | |
793 | ||
794 | def SyncBPLine(self, event): | |
795 | if self.currentItem != -1: | |
796 | list = self._bpListCtrl | |
797 | fileName = list.GetItem(self.currentItem, 2).GetText() | |
798 | lineNumber = list.GetItem(self.currentItem, 1).GetText() | |
799 | self._ui.SynchCurrentLine( fileName, int(lineNumber) ) | |
800 | ||
801 | def ClearBreakPoint(self, event): | |
802 | if self.currentItem >= 0: | |
803 | list = self._bpListCtrl | |
804 | fileName = list.GetItem(self.currentItem, 2).GetText() | |
805 | lineNumber = list.GetItem(self.currentItem, 1).GetText() | |
806 | wx.GetApp().GetService(DebuggerService).OnToggleBreakpoint(None, line=int(lineNumber) -1, fileName=fileName ) | |
807 | ||
808 | def ListItemSelected(self, event): | |
809 | self.currentItem = event.m_itemIndex | |
810 | ||
811 | def ListItemDeselected(self, event): | |
812 | self.currentItem = -1 | |
813 | ||
814 | class Watch: | |
815 | CODE_ALL_FRAMES = 1 | |
816 | CODE_THIS_BLOCK = 2 | |
817 | CODE_THIS_LINE = 4 | |
818 | CODE_RUN_ONCE = 8 | |
819 | ||
820 | def __init__(self, name, command, show_code=CODE_ALL_FRAMES): | |
821 | self._name = name | |
822 | self._command = command | |
823 | self._show_code = show_code | |
824 | ||
825 | class WatchDialog(wx.Dialog): | |
826 | WATCH_ALL_FRAMES = "Watch in all frames" | |
827 | WATCH_THIS_FRAME = "Watch in this frame only" | |
828 | WATCH_ONCE = "Watch once and delete" | |
829 | def __init__(self, parent, title, chain): | |
830 | wx.Dialog.__init__(self, parent, -1, title, style=wx.DEFAULT_DIALOG_STYLE) | |
831 | self._chain = chain | |
832 | self.label_2 = wx.StaticText(self, -1, "Watch Name:") | |
833 | self._watchNameTextCtrl = wx.TextCtrl(self, -1, "") | |
834 | self.label_3 = wx.StaticText(self, -1, "eval(", style=wx.ALIGN_RIGHT) | |
835 | self._watchValueTextCtrl = wx.TextCtrl(self, -1, "") | |
836 | self.label_4 = wx.StaticText(self, -1, ",frame.f_globals, frame.f_locals)") | |
837 | self.radio_box_1 = wx.RadioBox(self, -1, "Watch Information", choices=[WatchDialog.WATCH_ALL_FRAMES, WatchDialog.WATCH_THIS_FRAME, WatchDialog.WATCH_ONCE], majorDimension=0, style=wx.RA_SPECIFY_ROWS) | |
838 | ||
839 | self._okButton = wx.Button(self, wx.ID_OK, "OK", size=(75,-1)) | |
840 | self._okButton.SetDefault() | |
841 | self._okButton.SetHelpText(_("The OK button completes the dialog")) | |
842 | def OnOkClick(event): | |
843 | if self._watchNameTextCtrl.GetValue() == "": | |
844 | wx.MessageBox(_("You must enter a name for the watch."), _("Add Watch")) | |
845 | return | |
846 | if self._watchValueTextCtrl.GetValue() == "": | |
847 | wx.MessageBox(_("You must enter some code to run for the watch."), _("Add Watch")) | |
848 | return | |
849 | self.EndModal(wx.ID_OK) | |
850 | self.Bind(wx.EVT_BUTTON, OnOkClick, self._okButton) | |
851 | ||
852 | self._cancelButton = wx.Button(self, wx.ID_CANCEL, _("Cancel"), size=(75,-1)) | |
853 | self._cancelButton.SetHelpText(_("The Cancel button cancels the dialog.")) | |
854 | ||
855 | self.__set_properties() | |
856 | self.__do_layout() | |
857 | ||
858 | def GetSettings(self): | |
859 | return self._watchNameTextCtrl.GetValue(), self._watchValueTextCtrl.GetValue(), self.GetSendFrame(), self.GetRunOnce() | |
860 | ||
861 | def GetSendFrame(self): | |
862 | return (WatchDialog.WATCH_ALL_FRAMES != self.radio_box_1.GetStringSelection()) | |
863 | ||
864 | def GetRunOnce(self): | |
865 | return (WatchDialog.WATCH_ONCE == self.radio_box_1.GetStringSelection()) | |
866 | ||
867 | def __set_properties(self): | |
868 | self.SetTitle("Add a Watch") | |
869 | #self.SetSize((400, 250)) | |
870 | self.radio_box_1.SetSelection(0) | |
871 | ||
872 | def __do_layout(self): | |
873 | sizer_1 = wx.BoxSizer(wx.VERTICAL) | |
874 | grid_sizer_4 = wx.FlexGridSizer(1, 3, 5, 5) | |
875 | grid_sizer_2 = wx.FlexGridSizer(1, 2, 5, 5) | |
876 | grid_sizer_2.Add(self.label_2, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0) | |
877 | grid_sizer_2.Add(self._watchNameTextCtrl, 0, wx.EXPAND, 0) | |
878 | grid_sizer_2.AddGrowableCol(1) | |
879 | sizer_1.Add(grid_sizer_2, 1, wx.EXPAND, 0) | |
880 | grid_sizer_4.Add(self.label_3, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0) | |
881 | grid_sizer_4.Add(self._watchValueTextCtrl, 0, wx.EXPAND, 0) | |
882 | grid_sizer_4.AddGrowableCol(1) | |
883 | grid_sizer_4.Add(self.label_4, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0) | |
884 | sizer_1.Add(grid_sizer_4, 0, wx.EXPAND, 0) | |
885 | sizer_1.Add(self.radio_box_1, 0, wx.EXPAND, 0) | |
886 | ||
887 | box = wx.BoxSizer(wx.HORIZONTAL) | |
888 | box.Add(self._okButton, 0, wx.ALIGN_RIGHT|wx.ALL, 5) | |
889 | box.Add(self._cancelButton, 0, wx.ALIGN_RIGHT|wx.ALL, 5) | |
890 | sizer_1.Add(box, 1, wx.EXPAND, 0) | |
891 | self.SetAutoLayout(True) | |
892 | self.SetSizer(sizer_1) | |
893 | self.Layout() | |
894 | ||
895 | class FramesUI(wx.SplitterWindow): | |
896 | def __init__(self, parent, id, ui): | |
897 | wx.SplitterWindow.__init__(self, parent, id, style = wx.SP_3D) | |
898 | self._ui = ui | |
899 | sizer = wx.BoxSizer(wx.VERTICAL) | |
900 | self._p1 = p1 = wx.ScrolledWindow(self, -1) | |
901 | p1.Bind(wx.EVT_SIZE, self.OnSize) | |
902 | ||
903 | self._framesListCtrl = wx.ListCtrl(p1, -1, pos=wx.DefaultPosition, size=(250,150), style=wx.LC_REPORT) | |
904 | sizer.Add(self._framesListCtrl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1) | |
905 | self._framesListCtrl.InsertColumn(0, "Frame") | |
906 | self._framesListCtrl.SetColumnWidth(0, 250) | |
907 | self._framesListCtrl.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnListRightClick) | |
908 | self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.ListItemSelected, self._framesListCtrl) | |
909 | self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.ListItemDeselected, self._framesListCtrl) | |
910 | ||
911 | sizer2 = wx.BoxSizer(wx.VERTICAL) | |
912 | self._p2 = p2 = wx.ScrolledWindow(self, -1) | |
913 | p2.Bind(wx.EVT_SIZE, self.OnSize) | |
914 | ||
915 | self._treeCtrl = wx.gizmos.TreeListCtrl(p2, -1, size=(530,250), style=wx.TR_DEFAULT_STYLE| wx.TR_FULL_ROW_HIGHLIGHT) | |
916 | self._treeCtrl.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnRightClick) | |
917 | sizer2.Add(self._framesListCtrl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1) | |
918 | tree = self._treeCtrl | |
919 | tree.AddColumn("Thing") | |
920 | tree.AddColumn("Value") | |
921 | tree.SetMainColumn(0) # the one with the tree in it... | |
922 | tree.SetColumnWidth(0, 175) | |
923 | tree.SetColumnWidth(1, 355) | |
924 | self._root = tree.AddRoot("Frame") | |
925 | tree.SetItemText(self._root, "", 1) | |
926 | ||
927 | self.SetMinimumPaneSize(20) | |
928 | self.SplitVertically(p1, p2, 250) | |
929 | self.currentItem = None | |
930 | self.Layout() | |
931 | ||
932 | def OnRightClick(self, event): | |
933 | #Refactor this... | |
934 | self._introspectItem = event.GetItem() | |
935 | self._parentChain = self.GetItemChain(event.GetItem()) | |
936 | watchOnly = len(self._parentChain) < 1 | |
937 | if not _WATCHES_ON and watchOnly: | |
938 | return | |
939 | menu = wx.Menu() | |
940 | if not watchOnly: | |
941 | if not hasattr(self, "introspectID"): | |
942 | self.introspectID = wx.NewId() | |
943 | self.Bind(wx.EVT_MENU, self.OnIntrospect, id=self.introspectID) | |
944 | item = wx.MenuItem(menu, self.introspectID, "Attempt Introspection") | |
945 | menu.AppendItem(item) | |
946 | menu.AppendSeparator() | |
947 | if _WATCHES_ON: | |
948 | if not hasattr(self, "watchID"): | |
949 | self.watchID = wx.NewId() | |
950 | self.Bind(wx.EVT_MENU, self.OnWatch, id=self.watchID) | |
951 | item = wx.MenuItem(menu, self.watchID, "Create a Watch") | |
952 | menu.AppendItem(item) | |
953 | menu.AppendSeparator() | |
954 | if not watchOnly: | |
955 | if not hasattr(self, "viewID"): | |
956 | self.viewID = wx.NewId() | |
957 | self.Bind(wx.EVT_MENU, self.OnView, id=self.viewID) | |
958 | item = wx.MenuItem(menu, self.viewID, "View in Dialog") | |
959 | menu.AppendItem(item) | |
960 | offset = wx.Point(x=0, y=20) | |
961 | menuSpot = event.GetPoint() + offset | |
962 | self._treeCtrl.PopupMenu(menu, menuSpot) | |
963 | menu.Destroy() | |
964 | self._parentChain = None | |
965 | self._introspectItem = None | |
966 | ||
967 | def GetItemChain(self, item): | |
968 | parentChain = [] | |
969 | if item: | |
970 | if _VERBOSE: print 'Exploding: %s' % self._treeCtrl.GetItemText(item, 0) | |
971 | while item != self._root: | |
972 | text = self._treeCtrl.GetItemText(item, 0) | |
973 | if _VERBOSE: print "Appending ", text | |
974 | parentChain.append(text) | |
975 | item = self._treeCtrl.GetItemParent(item) | |
976 | parentChain.reverse() | |
977 | return parentChain | |
978 | ||
979 | def OnView(self, event): | |
980 | title = self._treeCtrl.GetItemText(self._introspectItem,0) | |
981 | value = self._treeCtrl.GetItemText(self._introspectItem,1) | |
982 | dlg = wx.lib.dialogs.ScrolledMessageDialog(self, value, title, style=wx.DD_DEFAULT_STYLE | wx.RESIZE_BORDER) | |
983 | dlg.Show() | |
984 | ||
985 | def OnWatch(self, event): | |
986 | try: | |
987 | if hasattr(self, '_parentChain'): | |
988 | wd = WatchDialog(wx.GetApp().GetTopWindow(), "Add a Watch", self._parentChain) | |
989 | else: | |
990 | wd = WatchDialog(wx.GetApp().GetTopWindow(), "Add a Watch", None) | |
991 | if wd.ShowModal() == wx.ID_OK: | |
992 | name, text, send_frame, run_once = wd.GetSettings() | |
993 | if send_frame: | |
994 | frameNode = self._stack[int(self.currentItem)] | |
995 | message = frameNode.getAttribute("message") | |
996 | else: | |
997 | message = "" | |
998 | binType = self._ui._callback._debuggerServer.add_watch(name, text, message, run_once) | |
999 | xmldoc = bz2.decompress(binType.data) | |
1000 | domDoc = parseString(xmldoc) | |
1001 | nodeList = domDoc.getElementsByTagName('watch') | |
1002 | if len(nodeList) == 1: | |
1003 | watchValue = nodeList.item(0).getAttribute("message") | |
1004 | except: | |
1005 | tp, val, tb = sys.exc_info() | |
1006 | traceback.print_exception(tp, val, tb) | |
1007 | ||
1008 | def OnIntrospect(self, event): | |
1009 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) | |
1010 | ||
1011 | try: | |
1012 | list = self._framesListCtrl | |
1013 | frameNode = self._stack[int(self.currentItem)] | |
1014 | message = frameNode.getAttribute("message") | |
1015 | binType = self._ui._callback._debuggerServer.attempt_introspection(message, self._parentChain) | |
1016 | xmldoc = bz2.decompress(binType.data) | |
1017 | ||
1018 | domDoc = parseString(xmldoc) | |
1019 | nodeList = domDoc.getElementsByTagName('replacement') | |
1020 | replacementNode = nodeList.item(0) | |
1021 | if len(replacementNode.childNodes): | |
1022 | thingToWalk = replacementNode.childNodes.item(0) | |
1023 | tree = self._treeCtrl | |
1024 | parent = tree.GetItemParent(self._introspectItem) | |
1025 | treeNode = self.AppendSubTreeFromNode(thingToWalk, thingToWalk.getAttribute('name'), parent, insertBefore=self._introspectItem) | |
1026 | tree.Delete(self._introspectItem) | |
1027 | except: | |
1028 | tp,val,tb = sys.exc_info() | |
1029 | traceback.print_exception(tp, val, tb) | |
1030 | ||
1031 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) | |
1032 | ||
1033 | def OnSize(self, event): | |
1034 | self._treeCtrl.SetSize(self._p2.GetSize()) | |
1035 | w,h = self._p1.GetClientSizeTuple() | |
1036 | self._framesListCtrl.SetDimensions(0, 0, w, h) | |
1037 | ||
1038 | def ClearWhileRunning(self): | |
1039 | list = self._framesListCtrl | |
1040 | list.DeleteAllItems() | |
1041 | tree = self._treeCtrl | |
1042 | tree.Hide() | |
1043 | ||
1044 | def OnListRightClick(self, event): | |
1045 | if not hasattr(self, "syncFrameID"): | |
1046 | self.syncFrameID = wx.NewId() | |
1047 | self.Bind(wx.EVT_MENU, self.OnSyncFrame, id=self.syncFrameID) | |
1048 | menu = wx.Menu() | |
1049 | item = wx.MenuItem(menu, self.syncFrameID, "Goto Source Line") | |
1050 | menu.AppendItem(item) | |
1051 | self.PopupMenu(menu, event.GetPosition()) | |
1052 | menu.Destroy() | |
1053 | ||
1054 | def OnSyncFrame(self, event): | |
1055 | list = self._framesListCtrl | |
1056 | frameNode = self._stack[int(self.currentItem)] | |
1057 | file = frameNode.getAttribute("file") | |
1058 | line = frameNode.getAttribute("line") | |
1059 | self._ui.SynchCurrentLine( file, int(line) ) | |
1060 | ||
1061 | def LoadFramesListXML(self, framesXML): | |
1062 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT)) | |
1063 | try: | |
1064 | domDoc = parseString(framesXML) | |
1065 | list = self._framesListCtrl | |
1066 | list.DeleteAllItems() | |
1067 | self._stack = [] | |
1068 | nodeList = domDoc.getElementsByTagName('frame') | |
1069 | frame_count = -1 | |
1070 | for index in range(0, nodeList.length): | |
1071 | frameNode = nodeList.item(index) | |
1072 | message = frameNode.getAttribute("message") | |
1073 | list.InsertStringItem(index, message) | |
1074 | self._stack.append(frameNode) | |
1075 | frame_count += 1 | |
1076 | list.Select(frame_count) | |
1077 | self._p1.FitInside() | |
1078 | frameNode = nodeList.item(index) | |
1079 | file = frameNode.getAttribute("file") | |
1080 | line = frameNode.getAttribute("line") | |
1081 | self._ui.SynchCurrentLine( file, int(line) ) | |
1082 | except: | |
1083 | tp,val,tb=sys.exc_info() | |
1084 | traceback.print_exception(tp, val, tb) | |
1085 | ||
1086 | wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT)) | |
1087 | ||
1088 | def ListItemDeselected(self, event): | |
1089 | pass | |
1090 | ||
1091 | def ListItemSelected(self, event): | |
1092 | self.currentItem = event.m_itemIndex | |
1093 | frameNode = self._stack[int(self.currentItem)] | |
1094 | self.PopulateTreeFromFrameNode(frameNode) | |
1095 | # Temporarily doing this to test out automatically swicting to source line. | |
1096 | self.OnSyncFrame(None) | |
1097 | ||
1098 | def PopulateTreeFromFrameNode(self, frameNode): | |
1099 | tree = self._treeCtrl | |
1100 | tree.Show(True) | |
1101 | root = self._root | |
1102 | tree.DeleteChildren(root) | |
1103 | children = frameNode.childNodes | |
1104 | firstChild = None | |
1105 | for index in range(0, children.length): | |
1106 | subNode = children.item(index) | |
1107 | treeNode = self.AppendSubTreeFromNode(subNode, subNode.getAttribute('name'), root) | |
1108 | if not firstChild: | |
1109 | firstChild = treeNode | |
1110 | tree.Expand(root) | |
1111 | tree.Expand(firstChild) | |
1112 | self._p2.FitInside() | |
1113 | ||
1114 | def AppendSubTreeFromNode(self, node, name, parent, insertBefore=None): | |
1115 | tree = self._treeCtrl | |
1116 | if insertBefore != None: | |
1117 | treeNode = tree.InsertItem(parent, insertBefore, name) | |
1118 | else: | |
1119 | treeNode = tree.AppendItem(parent, name) | |
1120 | children = node.childNodes | |
1121 | if children.length == 0: | |
1122 | tree.SetItemText(treeNode, self.StripOuterSingleQuotes(node.getAttribute("value")), 1) | |
1123 | for index in range(0, children.length): | |
1124 | subNode = children.item(index) | |
1125 | if self.HasChildren(subNode): | |
1126 | self.AppendSubTreeFromNode(subNode, subNode.getAttribute("name"), treeNode) | |
1127 | else: | |
1128 | name = subNode.getAttribute("name") | |
1129 | value = self.StripOuterSingleQuotes(subNode.getAttribute("value")) | |
1130 | n = tree.AppendItem(treeNode, name) | |
1131 | tree.SetItemText(n, value, 1) | |
1132 | return treeNode | |
1133 | ||
1134 | def StripOuterSingleQuotes(self, string): | |
1135 | if string.startswith("'") and string.endswith("'"): | |
1136 | return string[1:-1] | |
1137 | elif type(string) == types.UnicodeType: | |
1138 | return string[1:-1] | |
1139 | else: | |
1140 | return string | |
1141 | ||
1142 | def HasChildren(self, node): | |
1143 | try: | |
1144 | return node.childNodes.length > 0 | |
1145 | except: | |
1146 | tp,val,tb=sys.exc_info() | |
1147 | return False | |
1148 | ||
1149 | class DebuggerView(Service.ServiceView): | |
1150 | ||
1151 | #---------------------------------------------------------------------------- | |
1152 | # Overridden methods | |
1153 | #---------------------------------------------------------------------------- | |
1154 | ||
1155 | def __init__(self, service): | |
1156 | Service.ServiceView.__init__(self, service) | |
1157 | ||
1158 | def _CreateControl(self, parent, id): | |
1159 | return None | |
1160 | ||
1161 | #------------------------------------------------------------------------------ | |
1162 | # Event handling | |
1163 | #----------------------------------------------------------------------------- | |
1164 | ||
1165 | def OnToolClicked(self, event): | |
1166 | self.GetFrame().ProcessEvent(event) | |
1167 | ||
1168 | #------------------------------------------------------------------------------ | |
1169 | # Class methods | |
1170 | #----------------------------------------------------------------------------- | |
1171 | ||
1172 | class Interaction: | |
1173 | def __init__(self, message, framesXML, info=None, quit=False): | |
1174 | self._framesXML = framesXML | |
1175 | self._message = message | |
1176 | self._info = info | |
1177 | self._quit = quit | |
1178 | ||
1179 | def getFramesXML(self): | |
1180 | return self._framesXML | |
1181 | ||
1182 | def getMessage(self): | |
1183 | return self._message | |
1184 | ||
1185 | def getInfo(self): | |
1186 | return self._info | |
1187 | ||
1188 | def getQuit(self): | |
1189 | return self._quit | |
1190 | ||
1191 | class AGXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer): | |
1192 | def __init__(self, address, logRequests=0): | |
1193 | SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, address, logRequests=logRequests) | |
1194 | ||
1195 | class RequestHandlerThread(threading.Thread): | |
1196 | def __init__(self, queue, address): | |
1197 | threading.Thread.__init__(self) | |
1198 | self._keepGoing = True | |
1199 | self._queue = queue | |
1200 | self._address = address | |
1201 | self._server = AGXMLRPCServer(self._address,logRequests=0) | |
1202 | self._server.register_function(self.interaction) | |
1203 | self._server.register_function(self.quit) | |
1204 | self._server.register_function(self.dummyOperation) | |
1205 | if _VERBOSE: print "RequestHandlerThread on fileno %s" % str(self._server.fileno()) | |
1206 | ||
1207 | def run(self): | |
1208 | while self._keepGoing: | |
1209 | try: | |
1210 | self._server.handle_request() | |
1211 | except: | |
1212 | tp, val, tb = sys.exc_info() | |
1213 | traceback.print_exception(tp, val, tb) | |
1214 | self._keepGoing = False | |
1215 | if _VERBOSE: print "Exiting Request Handler Thread." | |
1216 | ||
1217 | def interaction(self, message, frameXML, info): | |
1218 | if _VERBOSE: print "In RequestHandlerThread.interaction -- adding to queue" | |
1219 | interaction = Interaction(message, frameXML, info) | |
1220 | self._queue.put(interaction) | |
1221 | return "" | |
1222 | ||
1223 | def quit(self): | |
1224 | interaction = Interaction(None, None, info=None, quit=True) | |
1225 | self._queue.put(interaction) | |
1226 | return "" | |
1227 | ||
1228 | def dummyOperation(self): | |
1229 | return "" | |
1230 | ||
1231 | def AskToStop(self): | |
1232 | self._keepGoing = False | |
1233 | if type(self._server) is not types.NoneType: | |
1234 | try: | |
1235 | # This is a really ugly way to make sure this thread isn't blocked in | |
1236 | # handle_request. | |
1237 | url = 'http://' + self._address[0] + ':' + str(self._address[1]) + '/' | |
1238 | tempServer = xmlrpclib.ServerProxy(url, allow_none=1) | |
1239 | tempServer.dummyOperation() | |
1240 | except: | |
1241 | tp, val, tb = sys.exc_info() | |
1242 | traceback.print_exception(tp, val, tb) | |
1243 | self._server.server_close() | |
1244 | ||
1245 | ||
1246 | class RequestBreakThread(threading.Thread): | |
1247 | def __init__(self, server, interrupt=False, pushBreakpoints=False, breakDict=None, kill=False): | |
1248 | threading.Thread.__init__(self) | |
1249 | self._server = server | |
1250 | ||
1251 | self._interrupt = interrupt | |
1252 | self._pushBreakpoints = pushBreakpoints | |
1253 | self._breakDict = breakDict | |
1254 | self._kill = kill | |
1255 | ||
1256 | def run(self): | |
1257 | try: | |
1258 | if _VERBOSE: print "RequestBreakThread, before call" | |
1259 | if self._interrupt: | |
1260 | self._server.break_requested() | |
1261 | if self._pushBreakpoints: | |
1262 | self._server.update_breakpoints(xmlrpclib.Binary(pickle.dumps(self._breakDict))) | |
1263 | if self._kill: | |
1264 | try: | |
1265 | self._server.die() | |
1266 | except: | |
1267 | pass | |
1268 | if _VERBOSE: print "RequestBreakThread, after call" | |
1269 | except: | |
1270 | tp,val,tb = sys.exc_info() | |
1271 | traceback.print_exception(tp, val, tb) | |
1272 | ||
1273 | class DebuggerOperationThread(threading.Thread): | |
1274 | def __init__(self, function): | |
1275 | threading.Thread.__init__(self) | |
1276 | self._function = function | |
1277 | ||
1278 | def run(self): | |
1279 | if _VERBOSE: print "In DOT, before call" | |
1280 | try: | |
1281 | self._function() | |
1282 | except: | |
1283 | tp,val,tb = sys.exc_info() | |
1284 | traceback.print_exception(tp, val, tb) | |
1285 | if _VERBOSE: print "In DOT, after call" | |
1286 | ||
1287 | class DebuggerCallback: | |
1288 | ||
1289 | def __init__(self, host, port, debugger_url, break_url, debuggerUI): | |
1290 | if _VERBOSE: print "+++++++ Creating server on port, ", str(port) | |
1291 | ||
1292 | self._queue = Queue.Queue(50) | |
1293 | self._host = host | |
1294 | self._port = int(port) | |
1295 | threading._VERBOSE = _VERBOSE | |
1296 | self._serverHandlerThread = RequestHandlerThread(self._queue, (self._host, self._port)) | |
1297 | ||
1298 | self._debugger_url = debugger_url | |
1299 | self._debuggerServer = None | |
1300 | self._waiting = False | |
1301 | self._service = wx.GetApp().GetService(DebuggerService) | |
1302 | self._debuggerUI = debuggerUI | |
1303 | self._break_url = break_url | |
1304 | self._breakServer = None | |
1305 | self._firstInteraction = True | |
1306 | self._pendingBreak = False | |
1307 | ||
1308 | def start(self): | |
1309 | self._serverHandlerThread.start() | |
1310 | ||
1311 | def ServerClose(self): | |
1312 | rbt = RequestBreakThread(self._breakServer, kill=True) | |
1313 | rbt.start() | |
1314 | self.setWaiting(False) | |
1315 | if self._serverHandlerThread: | |
1316 | self._serverHandlerThread.AskToStop() | |
1317 | self._serverHandlerThread = None | |
1318 | ||
1319 | def BreakExecution(self): | |
1320 | rbt = RequestBreakThread(self._breakServer, interrupt=True) | |
1321 | rbt.start() | |
1322 | ||
1323 | def SingleStep(self): | |
1324 | self._debuggerUI.DisableWhileDebuggerRunning() | |
1325 | #dot = DebuggerOperationThread(self._debuggerServer.set_step) | |
1326 | #dot.start() | |
1327 | self._debuggerServer.set_step() # Figure out where to set allowNone | |
1328 | self.waitForRPC() | |
1329 | ||
1330 | def Next(self): | |
1331 | self._debuggerUI.DisableWhileDebuggerRunning() | |
1332 | #dot = DebuggerOperationThread(self._debuggerServer.set_next) | |
1333 | #dot.start() | |
1334 | self._debuggerServer.set_next() | |
1335 | self.waitForRPC() | |
1336 | ||
1337 | def Continue(self): | |
1338 | self._debuggerUI.DisableWhileDebuggerRunning() | |
1339 | #dot = DebuggerOperationThread(self._debuggerServer.set_continue) | |
1340 | #dot.start() | |
1341 | self._debuggerServer.set_continue() | |
1342 | self.waitForRPC() | |
1343 | ||
1344 | def Return(self): | |
1345 | self._debuggerUI.DisableWhileDebuggerRunning() | |
1346 | #dot = DebuggerOperationThread(self._debuggerServer.set_return) | |
1347 | #dot.start() | |
1348 | self._debuggerServer.set_return() | |
1349 | self.waitForRPC() | |
1350 | ||
1351 | def setWaiting(self, value): | |
1352 | self._waiting = value | |
1353 | ||
1354 | def getWaiting(self): | |
1355 | return self._waiting | |
1356 | ||
1357 | def readQueue(self): | |
1358 | if self._queue.qsize(): | |
1359 | try: | |
1360 | item = self._queue.get_nowait() | |
1361 | if item.getQuit(): | |
1362 | self.interaction(None, None, None, True) | |
1363 | else: | |
1364 | data = bz2.decompress(item.getFramesXML().data) | |
1365 | self.interaction(item.getMessage().data, data, item.getInfo(), False) | |
1366 | except Queue.Empty: | |
1367 | pass | |
1368 | ||
1369 | def pushBreakpoints(self): | |
1370 | rbt = RequestBreakThread(self._breakServer, pushBreakpoints=True, breakDict=self._service.GetMasterBreakpointDict()) | |
1371 | rbt.start() | |
1372 | ||
1373 | ||
1374 | def waitForRPC(self): | |
1375 | self.setWaiting(True) | |
1376 | while self.getWaiting(): | |
1377 | try: | |
1378 | self.readQueue() | |
1379 | import time | |
1380 | time.sleep(0.02) | |
1381 | except: | |
1382 | tp, val, tb = sys.exc_info() | |
1383 | traceback.print_exception(tp, val, tb) | |
1384 | wx.GetApp().Yield(True) | |
1385 | if _VERBOSE: print "Exiting waitForRPC." | |
1386 | ||
1387 | def interaction(self, message, frameXML, info, quit): | |
1388 | ||
1389 | #This method should be hit as the debugger starts. | |
1390 | if self._firstInteraction: | |
1391 | self._firstInteraction = False | |
1392 | self._debuggerServer = xmlrpclib.ServerProxy(self._debugger_url, allow_none=1) | |
1393 | self._breakServer = xmlrpclib.ServerProxy(self._break_url, allow_none=1) | |
1394 | self.pushBreakpoints() | |
1395 | self.setWaiting(False) | |
1396 | if _VERBOSE: print "+"*40 | |
1397 | if(quit): | |
1398 | self._debuggerUI.StopExecution(None) | |
1399 | return "" | |
1400 | if(info != ""): | |
1401 | if _VERBOSE: print "Hit interaction with exception" | |
1402 | #self._debuggerUI.StopExecution(None) | |
1403 | #self._debuggerUI.SetStatusText("Got exception: " + str(info)) | |
1404 | self._debuggerUI.SwitchToOutputTab() | |
1405 | else: | |
1406 | if _VERBOSE: print "Hit interaction no exception" | |
1407 | self._debuggerUI.SetStatusText(message) | |
1408 | self._debuggerUI.LoadFramesListXML(frameXML) | |
1409 | self._debuggerUI.EnableWhileDebuggerStopped() | |
1410 | if _VERBOSE: print "+"*40 | |
1411 | ||
1412 | class DebuggerService(Service.Service): | |
1413 | ||
1414 | #---------------------------------------------------------------------------- | |
1415 | # Constants | |
1416 | #---------------------------------------------------------------------------- | |
1417 | TOGGLE_BREAKPOINT_ID = wx.NewId() | |
1418 | CLEAR_ALL_BREAKPOINTS = wx.NewId() | |
1419 | RUN_ID = wx.NewId() | |
1420 | DEBUG_ID = wx.NewId() | |
1421 | ||
1422 | def ComparePaths(first, second): | |
1423 | one = DebuggerService.ExpandPath(first) | |
1424 | two = DebuggerService.ExpandPath(second) | |
1425 | if _WINDOWS: | |
1426 | return one.lower() == two.lower() | |
1427 | else: | |
1428 | return one == two | |
1429 | ComparePaths = staticmethod(ComparePaths) | |
1430 | ||
1431 | # Make sure we're using an expanded path on windows. | |
1432 | def ExpandPath(path): | |
1433 | if _WINDOWS: | |
1434 | try: | |
1435 | return win32api.GetLongPathName(path) | |
1436 | except: | |
1437 | print "Cannot get long path for %s" % path | |
1438 | ||
1439 | return path | |
1440 | ||
1441 | ExpandPath = staticmethod(ExpandPath) | |
1442 | ||
1443 | #---------------------------------------------------------------------------- | |
1444 | # Overridden methods | |
1445 | #---------------------------------------------------------------------------- | |
1446 | ||
1447 | def __init__(self, serviceName, embeddedWindowLocation = wx.lib.pydocview.EMBEDDED_WINDOW_LEFT): | |
1448 | Service.Service.__init__(self, serviceName, embeddedWindowLocation) | |
1449 | self.BREAKPOINT_DICT_STRING = "MasterBreakpointDict" | |
1450 | config = wx.ConfigBase_Get() | |
1451 | pickledbps = config.Read(self.BREAKPOINT_DICT_STRING) | |
1452 | if pickledbps: | |
1453 | try: | |
1454 | self._masterBPDict = pickle.loads(pickledbps.encode('ascii')) | |
1455 | except: | |
1456 | tp, val, tb = sys.exc_info() | |
1457 | traceback.print_exception(tp,val,tb) | |
1458 | self._masterBPDict = {} | |
1459 | else: | |
1460 | self._masterBPDict = {} | |
1461 | ||
1462 | def OnCloseFrame(self, event): | |
1463 | # IS THIS THE RIGHT PLACE? | |
1464 | try: | |
1465 | config = wx.ConfigBase_Get() | |
1466 | config.Write(self.BREAKPOINT_DICT_STRING, pickle.dumps(self._masterBPDict)) | |
1467 | except: | |
1468 | tp,val,tb = sys.exc_info() | |
1469 | traceback.print_exception(tp, val, tb) | |
1470 | return True | |
1471 | ||
1472 | def _CreateView(self): | |
1473 | return DebuggerView(self) | |
1474 | ||
1475 | ||
1476 | #---------------------------------------------------------------------------- | |
1477 | # Service specific methods | |
1478 | #---------------------------------------------------------------------------- | |
1479 | ||
1480 | def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None): | |
1481 | #Service.Service.InstallControls(self, frame, menuBar, toolBar, statusBar, document) | |
1482 | ||
1483 | config = wx.ConfigBase_Get() | |
1484 | ||
1485 | debuggerMenu = wx.Menu() | |
1486 | if not menuBar.FindItemById(DebuggerService.CLEAR_ALL_BREAKPOINTS): | |
1487 | ||
1488 | debuggerMenu.Append(DebuggerService.RUN_ID, _("&Run...\tCtrl+R"), _("Runs a file")) | |
1489 | wx.EVT_MENU(frame, DebuggerService.RUN_ID, frame.ProcessEvent) | |
1490 | wx.EVT_UPDATE_UI(frame, DebuggerService.RUN_ID, frame.ProcessUpdateUIEvent) | |
1491 | ||
1492 | debuggerMenu.Append(DebuggerService.DEBUG_ID, _("&Debug...\tCtrl+D"), _("Debugs a file")) | |
1493 | wx.EVT_MENU(frame, DebuggerService.DEBUG_ID, frame.ProcessEvent) | |
1494 | wx.EVT_UPDATE_UI(frame, DebuggerService.DEBUG_ID, frame.ProcessUpdateUIEvent) | |
1495 | ||
1496 | debuggerMenu.AppendSeparator() | |
1497 | ||
1498 | debuggerMenu.Append(DebuggerService.TOGGLE_BREAKPOINT_ID, _("&Toggle Breakpoint...\tCtrl+B"), _("Toggle a breakpoint")) | |
1499 | wx.EVT_MENU(frame, DebuggerService.TOGGLE_BREAKPOINT_ID, self.ProcessEvent) | |
1500 | wx.EVT_UPDATE_UI(frame, DebuggerService.TOGGLE_BREAKPOINT_ID, self.ProcessUpdateUIEvent) | |
1501 | ||
1502 | debuggerMenu.Append(DebuggerService.CLEAR_ALL_BREAKPOINTS, _("&Clear All Breakpoints"), _("Clear All Breakpoints")) | |
1503 | wx.EVT_MENU(frame, DebuggerService.CLEAR_ALL_BREAKPOINTS, self.ProcessEvent) | |
1504 | wx.EVT_UPDATE_UI(frame, DebuggerService.CLEAR_ALL_BREAKPOINTS, self.ProcessUpdateUIEvent) | |
1505 | ||
1506 | ||
1507 | viewMenuIndex = menuBar.FindMenu(_("&Project")) | |
1508 | menuBar.Insert(viewMenuIndex + 1, debuggerMenu, _("&Run")) | |
1509 | ||
1510 | return True | |
1511 | ||
1512 | ||
1513 | ||
1514 | #---------------------------------------------------------------------------- | |
1515 | # Event Processing Methods | |
1516 | #---------------------------------------------------------------------------- | |
1517 | ||
1518 | def ProcessEventBeforeWindows(self, event): | |
1519 | return False | |
1520 | ||
1521 | ||
1522 | def ProcessEvent(self, event): | |
1523 | if Service.Service.ProcessEvent(self, event): | |
1524 | return True | |
1525 | ||
1526 | an_id = event.GetId() | |
1527 | if an_id == DebuggerService.TOGGLE_BREAKPOINT_ID: | |
1528 | self.OnToggleBreakpoint(event) | |
1529 | return True | |
1530 | elif an_id == DebuggerService.CLEAR_ALL_BREAKPOINTS: | |
1531 | self.ClearAllBreakpoints() | |
1532 | return True | |
1533 | elif an_id == DebuggerService.RUN_ID: | |
1534 | self.OnRunProject(event) | |
1535 | return True | |
1536 | elif an_id == DebuggerService.DEBUG_ID: | |
1537 | self.OnDebugProject(event) | |
1538 | return True | |
1539 | return False | |
1540 | ||
1541 | def ProcessUpdateUIEvent(self, event): | |
1542 | if Service.Service.ProcessUpdateUIEvent(self, event): | |
1543 | return True | |
1544 | ||
1545 | an_id = event.GetId() | |
1546 | if an_id == DebuggerService.TOGGLE_BREAKPOINT_ID: | |
1547 | currentView = self.GetDocumentManager().GetCurrentView() | |
1548 | event.Enable(isinstance(currentView, PythonEditor.PythonView)) | |
1549 | return True | |
1550 | elif an_id == DebuggerService.CLEAR_ALL_BREAKPOINTS: | |
1551 | event.Enable(self.HasBreakpointsSet()) | |
1552 | return True | |
1553 | elif an_id == DebuggerService.RUN_ID: | |
1554 | event.Enable(self.HasAnyFiles()) | |
1555 | return True | |
1556 | elif an_id == DebuggerService.DEBUG_ID: | |
1557 | event.Enable(self.HasAnyFiles()) | |
1558 | return True | |
1559 | else: | |
1560 | return False | |
1561 | ||
1562 | #---------------------------------------------------------------------------- | |
1563 | # Class Methods | |
1564 | #---------------------------------------------------------------------------- | |
1565 | ||
1566 | def OnDebugProject(self, event): | |
1567 | if not Executor.GetPythonExecutablePath(): | |
1568 | return | |
1569 | if DebugCommandUI.DebuggerRunning(): | |
1570 | wx.MessageBox(_("A debugger is already running. Please shut down the other debugger first."), _("Debugger Running")) | |
1571 | return | |
1572 | self.ShowWindow(True) | |
1573 | projectService = wx.GetApp().GetService(ProjectEditor.ProjectService) | |
1574 | project = projectService.GetView().GetDocument() | |
1575 | dlg = CommandPropertiesDialog(self.GetView().GetFrame(), 'Debug Python File', projectService, None, pythonOnly=True, okButtonName="Debug", debugging=True) | |
1576 | if dlg.ShowModal() == wx.ID_OK: | |
1577 | fileToDebug, initialArgs, startIn, isPython, environment = dlg.GetSettings() | |
1578 | dlg.Destroy() | |
1579 | else: | |
1580 | dlg.Destroy() | |
1581 | return | |
1582 | self.PromptToSaveFiles() | |
1583 | ||
1584 | shortFile = os.path.basename(fileToDebug) | |
1585 | fileToDebug = DebuggerService.ExpandPath(fileToDebug) | |
1586 | try: | |
1587 | page = DebugCommandUI(Service.ServiceView.bottomTab, -1, str(fileToDebug), self) | |
1588 | count = Service.ServiceView.bottomTab.GetPageCount() | |
1589 | Service.ServiceView.bottomTab.AddPage(page, "Debugging: " + shortFile) | |
1590 | Service.ServiceView.bottomTab.SetSelection(count) | |
1591 | page.Execute(initialArgs, startIn, environment) | |
1592 | except: | |
1593 | pass | |
1594 | ||
1595 | def HasAnyFiles(self): | |
1596 | docs = wx.GetApp().GetDocumentManager().GetDocuments() | |
1597 | return len(docs) > 0 | |
1598 | ||
1599 | def PromptToSaveFiles(self, running=True): | |
1600 | filesModified = False | |
1601 | docs = wx.GetApp().GetDocumentManager().GetDocuments() | |
1602 | for doc in docs: | |
1603 | if doc.IsModified(): | |
1604 | filesModified = True | |
1605 | break | |
1606 | if filesModified: | |
1607 | frame = self.GetView().GetFrame() | |
1608 | if running: | |
1609 | yesNoMsg = wx.MessageDialog(frame, | |
1610 | _("Files have been modified.\nWould you like to save all files before running?"), | |
1611 | _("Run"), | |
1612 | wx.YES_NO | |
1613 | ) | |
1614 | else: | |
1615 | yesNoMsg = wx.MessageDialog(frame, | |
1616 | _("Files have been modified.\nWould you like to save all files before debugging?"), | |
1617 | _("Debug"), | |
1618 | wx.YES_NO | |
1619 | ) | |
1620 | if yesNoMsg.ShowModal() == wx.ID_YES: | |
1621 | docs = wx.GetApp().GetDocumentManager().GetDocuments() | |
1622 | for doc in docs: | |
1623 | doc.Save() | |
1624 | ||
1625 | def OnExit(self): | |
1626 | DebugCommandUI.ShutdownAllDebuggers() | |
1627 | ||
1628 | def OnRunProject(self, event): | |
1629 | if not Executor.GetPythonExecutablePath(): | |
1630 | return | |
1631 | projectService = wx.GetApp().GetService(ProjectEditor.ProjectService) | |
1632 | project = projectService.GetView().GetDocument() | |
1633 | dlg = CommandPropertiesDialog(self.GetView().GetFrame(), 'Run', projectService, None) | |
1634 | if dlg.ShowModal() == wx.ID_OK: | |
1635 | fileToRun, initialArgs, startIn, isPython, environment = dlg.GetSettings() | |
1636 | ||
1637 | ||
1638 | dlg.Destroy() | |
1639 | else: | |
1640 | dlg.Destroy() | |
1641 | return | |
1642 | self.PromptToSaveFiles() | |
1643 | # This will need to change when we can run more than .py and .bpel files. | |
1644 | if not isPython: | |
1645 | projectService.RunProcessModel(fileToRun) | |
1646 | return | |
1647 | ||
1648 | self.ShowWindow(True) | |
1649 | shortFile = os.path.basename(fileToRun) | |
1650 | page = RunCommandUI(Service.ServiceView.bottomTab, -1, str(fileToRun)) | |
1651 | count = Service.ServiceView.bottomTab.GetPageCount() | |
1652 | Service.ServiceView.bottomTab.AddPage(page, "Running: " + shortFile) | |
1653 | Service.ServiceView.bottomTab.SetSelection(count) | |
1654 | page.Execute(initialArgs, startIn, environment) | |
1655 | ||
1656 | def OnToggleBreakpoint(self, event, line=-1, fileName=None): | |
1657 | if not fileName: | |
1658 | view = wx.GetApp().GetDocumentManager().GetCurrentView() | |
1659 | # Test to make sure we aren't the project view. | |
1660 | if not hasattr(view, 'MarkerExists'): | |
1661 | return | |
1662 | fileName = wx.GetApp().GetDocumentManager().GetCurrentDocument().GetFilename() | |
1663 | if line < 0: | |
1664 | line = view.GetCtrl().GetCurrentLine() | |
1665 | if self.BreakpointSet(fileName, line + 1): | |
1666 | self.ClearBreak(fileName, line + 1) | |
1667 | else: | |
1668 | self.SetBreak(fileName, line + 1) | |
1669 | # Now refresh all the markers icons in all the open views. | |
1670 | self.ClearAllBreakpointMarkers() | |
1671 | self.SetAllBreakpointMarkers() | |
1672 | ||
1673 | def SilentToggleBreakpoint(self, fileName, line): | |
1674 | found = False | |
1675 | for lineNumber in self.GetBreakpointList(fileName): | |
1676 | if int(lineNumber) == int(line): | |
1677 | found = True | |
1678 | break | |
1679 | if found: | |
1680 | self.SetBreak(fileName, line) | |
1681 | else: | |
1682 | self.ClearBreak(fileName, line) | |
1683 | ||
1684 | def SetBreak(self, fileName, line): | |
1685 | expandedName = DebuggerService.ExpandPath(fileName) | |
1686 | if not self._masterBPDict.has_key(expandedName): | |
1687 | self._masterBPDict[expandedName] = [line] | |
1688 | else: | |
1689 | self._masterBPDict[expandedName] += [line] | |
1690 | # If we're already debugging, pass this bp off to the DebuggerCallback | |
1691 | self.NotifyDebuggersOfBreakpointChange() | |
1692 | ||
1693 | def NotifyDebuggersOfBreakpointChange(self): | |
1694 | DebugCommandUI.NotifyDebuggersOfBreakpointChange() | |
1695 | ||
1696 | def GetBreakpointList(self, fileName): | |
1697 | expandedName = DebuggerService.ExpandPath(fileName) | |
1698 | if not self._masterBPDict.has_key(expandedName): | |
1699 | return [] | |
1700 | else: | |
1701 | return self._masterBPDict[expandedName] | |
1702 | ||
1703 | def BreakpointSet(self, fileName, line): | |
1704 | expandedName = DebuggerService.ExpandPath(fileName) | |
1705 | if not self._masterBPDict.has_key(expandedName): | |
1706 | return False | |
1707 | else: | |
1708 | newList = [] | |
1709 | for number in self._masterBPDict[expandedName]: | |
1710 | if(int(number) == int(line)): | |
1711 | return True | |
1712 | return False | |
1713 | ||
1714 | def ClearBreak(self, fileName, line): | |
1715 | expandedName = DebuggerService.ExpandPath(fileName) | |
1716 | if not self._masterBPDict.has_key(expandedName): | |
1717 | print "In ClearBreak: no key" | |
1718 | return | |
1719 | else: | |
1720 | newList = [] | |
1721 | for number in self._masterBPDict[expandedName]: | |
1722 | if(int(number) != int(line)): | |
1723 | newList.append(number) | |
1724 | self._masterBPDict[expandedName] = newList | |
1725 | self.NotifyDebuggersOfBreakpointChange() | |
1726 | ||
1727 | def HasBreakpointsSet(self): | |
1728 | for key, value in self._masterBPDict.items(): | |
1729 | if len(value) > 0: | |
1730 | return True | |
1731 | return False | |
1732 | ||
1733 | def ClearAllBreakpoints(self): | |
1734 | self._masterBPDict = {} | |
1735 | self.NotifyDebuggersOfBreakpointChange() | |
1736 | self.ClearAllBreakpointMarkers() | |
1737 | ||
1738 | def ClearAllBreakpointMarkers(self): | |
1739 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
1740 | for openDoc in openDocs: | |
1741 | if(isinstance(openDoc.GetFirstView(), CodeEditor.CodeView)): | |
1742 | openDoc.GetFirstView().MarkerDeleteAll(CodeEditor.CodeCtrl.BREAKPOINT_MARKER_NUM) | |
1743 | ||
1744 | def GetMasterBreakpointDict(self): | |
1745 | return self._masterBPDict | |
1746 | ||
1747 | def SetAllBreakpointMarkers(self): | |
1748 | openDocs = wx.GetApp().GetDocumentManager().GetDocuments() | |
1749 | for openDoc in openDocs: | |
1750 | if(isinstance(openDoc.GetFirstView(), CodeEditor.CodeView)): | |
1751 | self.SetCurrentBreakpointMarkers(openDoc.GetFirstView()) | |
1752 | ||
1753 | def SetCurrentBreakpointMarkers(self, view): | |
1754 | if isinstance(view, CodeEditor.CodeView) and hasattr(view, 'GetDocument'): | |
1755 | view.MarkerDeleteAll(CodeEditor.CodeCtrl.BREAKPOINT_MARKER_NUM) | |
1756 | for linenum in self.GetBreakpointList(view.GetDocument().GetFilename()): | |
1757 | view.MarkerAdd(lineNum=int(linenum) - 1, marker_index=CodeEditor.CodeCtrl.BREAKPOINT_MARKER_NUM) | |
1758 | ||
1759 | class DebuggerOptionsPanel(wx.Panel): | |
1760 | ||
1761 | ||
1762 | def __init__(self, parent, id): | |
1763 | wx.Panel.__init__(self, parent, id) | |
1764 | SPACE = 10 | |
1765 | config = wx.ConfigBase_Get() | |
1766 | localHostStaticText = wx.StaticText(self, -1, _("Local Host Name:")) | |
1767 | self._LocalHostTextCtrl = wx.TextCtrl(self, -1, config.Read("DebuggerHostName", DEFAULT_HOST), size = (150, -1)) | |
1768 | portNumberStaticText = wx.StaticText(self, -1, _("Port Range:")) | |
1769 | dashStaticText = wx.StaticText(self, -1, _("through to")) | |
1770 | startingPort=config.ReadInt("DebuggerStartingPort", DEFAULT_PORT) | |
1771 | self._PortNumberTextCtrl = wx.lib.intctrl.IntCtrl(self, -1, startingPort, size = (50, -1)) | |
1772 | self._PortNumberTextCtrl.SetMin(1)#What are real values? | |
1773 | self._PortNumberTextCtrl.SetMax(65514) #What are real values? | |
1774 | self.Bind(wx.lib.intctrl.EVT_INT, self.MinPortChange, self._PortNumberTextCtrl) | |
1775 | ||
1776 | self._EndPortNumberTextCtrl = wx.lib.intctrl.IntCtrl(self, -1, startingPort + PORT_COUNT, size = (50, -1)) | |
1777 | self._EndPortNumberTextCtrl.SetMin(22)#What are real values? | |
1778 | self._EndPortNumberTextCtrl.SetMax(65535)#What are real values? | |
1779 | self._EndPortNumberTextCtrl.Enable( False ) | |
1780 | debuggerPanelBorderSizer = wx.BoxSizer(wx.VERTICAL) | |
1781 | debuggerPanelSizer = wx.GridBagSizer(hgap = 5, vgap = 5) | |
1782 | debuggerPanelSizer.Add( localHostStaticText, (0,0), flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT) | |
1783 | debuggerPanelSizer.Add( self._LocalHostTextCtrl, (0,1), (1,3), flag=wx.EXPAND|wx.ALIGN_CENTER) | |
1784 | debuggerPanelSizer.Add( portNumberStaticText, (1,0), flag=wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL) | |
1785 | debuggerPanelSizer.Add( self._PortNumberTextCtrl, (1,1), flag=wx.ALIGN_CENTER) | |
1786 | debuggerPanelSizer.Add( dashStaticText, (1,2), flag=wx.ALIGN_CENTER) | |
1787 | debuggerPanelSizer.Add( self._EndPortNumberTextCtrl, (1,3), flag=wx.ALIGN_CENTER) | |
1788 | FLUSH_PORTS_ID = wx.NewId() | |
1789 | self._flushPortsButton = wx.Button(self, FLUSH_PORTS_ID, "Reset Port List") | |
1790 | wx.EVT_BUTTON(parent, FLUSH_PORTS_ID, self.FlushPorts) | |
1791 | debuggerPanelSizer.Add(self._flushPortsButton, (2,2), (1,2), flag=wx.ALIGN_RIGHT) | |
1792 | ||
1793 | debuggerPanelBorderSizer.Add(debuggerPanelSizer, 0, wx.ALL, SPACE) | |
1794 | self.SetSizer(debuggerPanelBorderSizer) | |
1795 | self.Layout() | |
1796 | parent.AddPage(self, _("Debugger")) | |
1797 | ||
1798 | def FlushPorts(self, event): | |
1799 | if self._PortNumberTextCtrl.IsInBounds(): | |
1800 | config = wx.ConfigBase_Get() | |
1801 | config.WriteInt("DebuggerStartingPort", self._PortNumberTextCtrl.GetValue()) | |
1802 | DebugCommandUI.NewPortRange() | |
1803 | else: | |
1804 | wx.MessageBox(_("The starting port is not valid. Please change the value and try again.", "Invalid Starting Port Number")) | |
1805 | ||
1806 | def MinPortChange(self, event): | |
1807 | self._EndPortNumberTextCtrl.Enable( True ) | |
1808 | self._EndPortNumberTextCtrl.SetValue( self._PortNumberTextCtrl.GetValue() + PORT_COUNT) | |
1809 | self._EndPortNumberTextCtrl.Enable( False ) | |
1810 | ||
1811 | def OnOK(self, optionsDialog): | |
1812 | config = wx.ConfigBase_Get() | |
1813 | config.Write("DebuggerHostName", self._LocalHostTextCtrl.GetValue()) | |
1814 | if self._PortNumberTextCtrl.IsInBounds(): | |
1815 | config.WriteInt("DebuggerStartingPort", self._PortNumberTextCtrl.GetValue()) | |
1816 | ||
1817 | class CommandPropertiesDialog(wx.Dialog): | |
1818 | ||
1819 | def __init__(self, parent, title, projectService, currentProjectDocument, pythonOnly=False, okButtonName="Run", debugging=False): | |
1820 | if _WINDOWS: | |
1821 | wx.Dialog.__init__(self, parent, -1, title) | |
1822 | else: | |
1823 | wx.Dialog.__init__(self, parent, -1, title, size=(390,270)) | |
1824 | self._projService = projectService | |
1825 | self._pmext = None | |
1826 | self._pyext = None | |
1827 | for template in self._projService.GetDocumentManager().GetTemplates(): | |
1828 | if not ACTIVEGRID_BASE_IDE and template.GetDocumentType() == ProcessModelEditor.ProcessModelDocument: | |
1829 | self._pmext = template.GetDefaultExtension() | |
1830 | if template.GetDocumentType() == PythonEditor.PythonDocument: | |
1831 | self._pyext = template.GetDefaultExtension() | |
1832 | self._pythonOnly = pythonOnly | |
1833 | ||
1834 | self._currentProj = currentProjectDocument | |
1835 | projStaticText = wx.StaticText(self, -1, _("Project:")) | |
1836 | fileStaticText = wx.StaticText(self, -1, _("File:")) | |
1837 | argsStaticText = wx.StaticText(self, -1, _("Arguments:")) | |
1838 | startInStaticText = wx.StaticText(self, -1, _("Start in:")) | |
1839 | pythonPathStaticText = wx.StaticText(self, -1, _("PYTHONPATH:")) | |
1840 | postpendStaticText = _("Postpend win32api path") | |
1841 | cpPanelBorderSizer = wx.BoxSizer(wx.VERTICAL) | |
1842 | self._projectNameList, self._projectDocumentList, selectedIndex = self.GetProjectList() | |
1843 | self._projList = wx.Choice(self, -1, (200,-1), choices=self._projectNameList) | |
1844 | self.Bind(wx.EVT_CHOICE, self.EvtListBox, self._projList) | |
1845 | HALF_SPACE = 5 | |
1846 | flexGridSizer = wx.FlexGridSizer(cols = 3, vgap = 10, hgap = 10) | |
1847 | ||
1848 | flexGridSizer.Add(projStaticText, 0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT) | |
1849 | flexGridSizer.Add(self._projList, 1, flag=wx.EXPAND) | |
1850 | flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0) | |
1851 | ||
1852 | flexGridSizer.Add(fileStaticText, 0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT) | |
1853 | self._fileList = wx.Choice(self, -1, (200,-1)) | |
1854 | self.Bind(wx.EVT_CHOICE, self.OnFileSelected, self._fileList) | |
1855 | flexGridSizer.Add(self._fileList, 1, flag=wx.EXPAND) | |
1856 | flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0) | |
1857 | ||
1858 | config = wx.ConfigBase_Get() | |
1859 | self._lastArguments = config.Read("LastRunArguments") | |
1860 | self._argsEntry = wx.TextCtrl(self, -1, str(self._lastArguments)) | |
1861 | self._argsEntry.SetToolTipString(str(self._lastArguments)) | |
1862 | def TextChanged(event): | |
1863 | self._argsEntry.SetToolTipString(event.GetString()) | |
1864 | self.Bind(wx.EVT_TEXT, TextChanged, self._argsEntry) | |
1865 | ||
1866 | flexGridSizer.Add(argsStaticText, 0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT) | |
1867 | flexGridSizer.Add(self._argsEntry, 1, flag=wx.EXPAND) | |
1868 | flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0) | |
1869 | ||
1870 | flexGridSizer.Add(startInStaticText, 0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT) | |
1871 | self._lastStartIn = config.Read("LastRunStartIn") | |
1872 | if not self._lastStartIn: | |
1873 | self._lastStartIn = str(os.getcwd()) | |
1874 | self._startEntry = wx.TextCtrl(self, -1, self._lastStartIn) | |
1875 | self._startEntry.SetToolTipString(self._lastStartIn) | |
1876 | def TextChanged2(event): | |
1877 | self._startEntry.SetToolTipString(event.GetString()) | |
1878 | self.Bind(wx.EVT_TEXT, TextChanged2, self._startEntry) | |
1879 | ||
1880 | flexGridSizer.Add(self._startEntry, 1, wx.EXPAND) | |
1881 | self._findDir = wx.Button(self, -1, _("Browse..."), size=(60,-1)) | |
1882 | self.Bind(wx.EVT_BUTTON, self.OnFindDirClick, self._findDir) | |
1883 | flexGridSizer.Add(self._findDir, 0, wx.RIGHT, 10) | |
1884 | ||
1885 | flexGridSizer.Add(pythonPathStaticText, 0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT) | |
1886 | if os.environ.has_key('PYTHONPATH'): | |
1887 | startval = os.environ['PYTHONPATH'] | |
1888 | else: | |
1889 | startval = "" | |
1890 | self._lastPythonPath = config.Read("LastPythonPath", startval) | |
1891 | self._pythonPathEntry = wx.TextCtrl(self, -1, self._lastPythonPath) | |
1892 | self._pythonPathEntry.SetToolTipString(self._lastPythonPath) | |
1893 | flexGridSizer.Add(self._pythonPathEntry, 1, wx.EXPAND) | |
1894 | flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0) | |
1895 | flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0) | |
1896 | if debugging: | |
1897 | self._postpendCheckBox = wx.CheckBox(self, -1, postpendStaticText) | |
1898 | checked = bool(config.ReadInt("PythonPathPostpend", 1)) | |
1899 | self._postpendCheckBox.SetValue(checked) | |
1900 | flexGridSizer.Add(self._postpendCheckBox, 1, wx.EXPAND) | |
1901 | flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0) | |
1902 | cpPanelBorderSizer.Add(flexGridSizer, 0, wx.ALL, 10) | |
1903 | ||
1904 | box = wx.BoxSizer(wx.HORIZONTAL) | |
1905 | self._okButton = wx.Button(self, wx.ID_OK, okButtonName, size=(75,-1)) | |
1906 | self._okButton.SetDefault() | |
1907 | self._okButton.SetHelpText(_("The ") + okButtonName + _(" button completes the dialog")) | |
1908 | box.Add(self._okButton, 0, wx.ALIGN_RIGHT|wx.ALL, 5) | |
1909 | self.Bind(wx.EVT_BUTTON, self.OnOKClick, self._okButton) | |
1910 | btn = wx.Button(self, wx.ID_CANCEL, _("Cancel"), size=(75,-1)) | |
1911 | btn.SetHelpText(_("The Cancel button cancels the dialog.")) | |
1912 | box.Add(btn, 0, wx.ALIGN_RIGHT|wx.ALL, 5) | |
1913 | cpPanelBorderSizer.Add(box, 0, wx.ALIGN_RIGHT|wx.BOTTOM, 5) | |
1914 | ||
1915 | self.SetSizer(cpPanelBorderSizer) | |
1916 | if _WINDOWS: | |
1917 | self.GetSizer().Fit(self) | |
1918 | ||
1919 | self.Layout() | |
1920 | ||
1921 | # Set up selections based on last values used. | |
1922 | self._fileNameList = None | |
1923 | self._selectedFileIndex = 0 | |
1924 | lastProject = config.Read("LastRunProject") | |
1925 | lastFile = config.Read("LastRunFile") | |
1926 | ||
1927 | if lastProject in self._projectNameList: | |
1928 | selectedIndex = self._projectNameList.index(lastProject) | |
1929 | elif selectedIndex < 0: | |
1930 | selectedIndex = 0 | |
1931 | self._projList.Select(selectedIndex) | |
1932 | self._selectedProjectIndex = selectedIndex | |
1933 | self._selectedProjectDocument = self._projectDocumentList[selectedIndex] | |
1934 | self.PopulateFileList(self._selectedProjectDocument, lastFile) | |
1935 | ||
1936 | def OnOKClick(self, event): | |
1937 | startIn = self._startEntry.GetValue() | |
1938 | fileToRun = self._fileList.GetStringSelection() | |
1939 | if not fileToRun: | |
1940 | wx.MessageBox(_("You must select a file to proceed. Note that not all projects have files that can be run or debugged.")) | |
1941 | return | |
1942 | isPython = fileToRun.endswith(self._pyext) | |
1943 | if isPython and not os.path.exists(startIn): | |
1944 | wx.MessageBox(_("Starting directory does not exist. Please change this value.")) | |
1945 | return | |
1946 | config = wx.ConfigBase_Get() | |
1947 | config.Write("LastRunProject", self._projectNameList[self._selectedProjectIndex]) | |
1948 | config.Write("LastRunFile", fileToRun) | |
1949 | # Don't update the arguments or starting directory unless we're runing python. | |
1950 | if isPython: | |
1951 | config.Write("LastRunArguments", self._argsEntry.GetValue()) | |
1952 | config.Write("LastRunStartIn", self._startEntry.GetValue()) | |
1953 | config.Write("LastPythonPath",self._pythonPathEntry.GetValue()) | |
1954 | if hasattr(self, "_postpendCheckBox"): | |
1955 | config.WriteInt("PythonPathPostpend", int(self._postpendCheckBox.GetValue())) | |
1956 | ||
1957 | self.EndModal(wx.ID_OK) | |
1958 | ||
1959 | def GetSettings(self): | |
1960 | filename = self._fileNameList[self._selectedFileIndex] | |
1961 | args = self._argsEntry.GetValue() | |
1962 | startIn = self._startEntry.GetValue() | |
1963 | isPython = filename.endswith(self._pyext) | |
1964 | env = os.environ | |
1965 | if hasattr(self, "_postpendCheckBox"): | |
1966 | postpend = self._postpendCheckBox.GetValue() | |
1967 | else: | |
1968 | postpend = False | |
1969 | if postpend: | |
1970 | env['PYTHONPATH'] = self._pythonPathEntry.GetValue() + os.pathsep + os.path.join(os.getcwd(), "3rdparty", "pywin32") | |
1971 | else: | |
1972 | env['PYTHONPATH'] = self._pythonPathEntry.GetValue() | |
1973 | ||
1974 | return filename, args, startIn, isPython, env | |
1975 | ||
1976 | def OnFileSelected(self, event): | |
1977 | self._selectedFileIndex = self._fileList.GetSelection() | |
1978 | self.EnableForFileType(event.GetString()) | |
1979 | ||
1980 | def EnableForFileType(self, fileName): | |
1981 | show = fileName.endswith(self._pyext) | |
1982 | self._startEntry.Enable(show) | |
1983 | self._findDir.Enable(show) | |
1984 | self._argsEntry.Enable(show) | |
1985 | ||
1986 | if not show: | |
1987 | self._lastStartIn = self._startEntry.GetValue() | |
1988 | self._startEntry.SetValue("") | |
1989 | self._lastArguments = self._argsEntry.GetValue() | |
1990 | self._argsEntry.SetValue("") | |
1991 | else: | |
1992 | self._startEntry.SetValue(self._lastStartIn) | |
1993 | self._argsEntry.SetValue(self._lastArguments) | |
1994 | ||
1995 | ||
1996 | ||
1997 | def OnFindDirClick(self, event): | |
1998 | dlg = wx.DirDialog(self, "Choose a starting directory:", self._startEntry.GetValue(), | |
1999 | style=wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON) | |
2000 | ||
2001 | if dlg.ShowModal() == wx.ID_OK: | |
2002 | self._startEntry.SetValue(dlg.GetPath()) | |
2003 | ||
2004 | dlg.Destroy() | |
2005 | ||
2006 | def EvtListBox(self, event): | |
2007 | if event.GetString(): | |
2008 | index = self._projectNameList.index(event.GetString()) | |
2009 | self._selectedProjectDocument = self._projectDocumentList[index] | |
2010 | self._selectedProjectIndex = index | |
2011 | self.PopulateFileList(self._selectedProjectDocument) | |
2012 | ||
2013 | def FilterFileList(self, list): | |
2014 | if self._pythonOnly: | |
2015 | files = filter(lambda f: f.endswith(self._pyext), list) | |
2016 | else: | |
2017 | files = filter(lambda f: (self._pmext and f.endswith(self._pmext)) or f.endswith(self._pyext), list) | |
2018 | return files | |
2019 | ||
2020 | def PopulateFileList(self, project, shortNameToSelect=None): | |
2021 | self._fileNameList = self.FilterFileList(project.GetFiles()[:]) | |
2022 | self._fileList.Clear() | |
2023 | if not self._fileNameList: | |
2024 | return | |
2025 | self._fileNameList.sort(lambda a, b: cmp(os.path.basename(a).lower(), os.path.basename(b).lower())) | |
2026 | strings = map(lambda file: os.path.basename(file), self._fileNameList) | |
2027 | for index in range(0, len(strings)): | |
2028 | if shortNameToSelect == strings[index]: | |
2029 | self._selectedFileIndex = index | |
2030 | break | |
2031 | self._fileList.Hide() | |
2032 | self._fileList.AppendItems(strings) | |
2033 | self._fileList.Show() | |
2034 | if self._selectedFileIndex not in range(0, len(strings)) : self._selectedFileIndex = 0 | |
2035 | self._fileList.SetSelection(self._selectedFileIndex) | |
2036 | self.EnableForFileType(strings[self._selectedFileIndex]) | |
2037 | ||
2038 | def GetProjectList(self): | |
2039 | docList = [] | |
2040 | nameList = [] | |
2041 | found = False | |
2042 | index = -1 | |
2043 | count = 0 | |
2044 | for document in self._projService.GetDocumentManager().GetDocuments(): | |
2045 | if document.GetDocumentTemplate().GetDocumentType() == ProjectEditor.ProjectDocument and len(document.GetFiles()): | |
2046 | docList.append(document) | |
2047 | nameList.append(os.path.basename(document.GetFilename())) | |
2048 | if document == self._currentProj: | |
2049 | found = True | |
2050 | index = count | |
2051 | count += 1 | |
2052 | return nameList, docList, index | |
2053 | #---------------------------------------------------------------------- | |
2054 | from wx import ImageFromStream, BitmapFromImage | |
2055 | from wx import EmptyIcon | |
2056 | import cStringIO | |
2057 | #---------------------------------------------------------------------- | |
2058 | def getBreakData(): | |
2059 | return \ | |
2060 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x11\x08\x06\ | |
2061 | \x00\x00\x00\xd4\xaf,\xc4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
2062 | \x00\x00\x97IDAT8\x8d\xbdSA\x0e\xc3 \x0c\x8b\x13\xfe=\x1e^\xe2\x1dF\xbb\x8c\ | |
2063 | \xd2\x0c\xa9\xda,q\x88\x05\x8e\x1d\x00P\x93;\xd0[\xa7W\x04\xe8\x8d\x0f\xdfxU\ | |
2064 | c%\x02\xbd\xbd\x05HQ+Xv\xb0\xa3VN\xf9\xd4\x01\xbd\x11j\x18\x1d\x00\x10\xa8AD\ | |
2065 | \xa4\xa4\xd6_\x9b\x19\xbb\x03\xd8c|\x8f\x00\xe0\x93\xa8g>\x15 C\xee:\xe7\x8f\ | |
2066 | \x08\xdesj\xcf\xe6\xde(\xddn\xec\x18f0w\xe0m;\x8d\x9b\xe4\xb1\xd4\n\xa6\x0e2\ | |
2067 | \xc4{\x1f\xeb\xdf?\xe5\xff\t\xa8\x1a$\x0cg\xac\xaf\xb0\xf4\x992<\x01\xec\xa0\ | |
2068 | U9V\xf9\x18\xc8\x00\x00\x00\x00IEND\xaeB`\x82' | |
2069 | ||
2070 | def getBreakBitmap(): | |
2071 | return BitmapFromImage(getBreakImage()) | |
2072 | ||
2073 | def getBreakImage(): | |
2074 | stream = cStringIO.StringIO(getBreakData()) | |
2075 | return ImageFromStream(stream) | |
2076 | ||
2077 | def getBreakIcon(): | |
2078 | icon = EmptyIcon() | |
2079 | icon.CopyFromBitmap(getBreakBitmap()) | |
2080 | return icon | |
2081 | ||
2082 | #---------------------------------------------------------------------- | |
2083 | def getClearOutputData(): | |
2084 | return \ | |
2085 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
2086 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
2087 | \x00\x00\xb4IDAT8\x8d\xa5\x92\xdd\r\x03!\x0c\x83\xbf\xa0n\xd4\x9d\xda5\xb81\ | |
2088 | \xbaS\xbb\x12\xee\x03?\xe5\x08\xe5N\xba\xbc Db\xec\xd8p\xb1l\xb8\xa7\x83\xfe\ | |
2089 | \xb0\x02H\x92F\xc0_\xa3\x99$\x99\x99\xedznc\xe36\x81\x88\x98"\xb2\x02\xa2\ | |
2090 | \x1e\xc4Q\x9aUD\x161\xcd\xde\x1c\x83\x15\x084)\x8d\xc5)\x06\xab\xaaZ\x92\xee\ | |
2091 | \xce\x11W\xdbGD\x0cIT\x06\xe7\x00\xdeY\xfe\xcc\x89\x06\xf0\xf2\x99\x00\xe0\ | |
2092 | \x91\x7f\xab\x83\xed\xa4\xc8\xafK\x0c\xcf\x92\x83\x99\x8d\xe3p\xef\xe4\xa1\ | |
2093 | \x0b\xe57j\xc8:\x06\t\x08\x87.H\xb2n\xa8\xc9\xa9\x12vQ\xfeG"\xe3\xacw\x00\ | |
2094 | \x10$M\xd3\x86_\xf0\xe5\xfc\xb4\xfa\x02\xcb\x13j\x10\xc5\xd7\x92D\x00\x00\ | |
2095 | \x00\x00IEND\xaeB`\x82' | |
2096 | ||
2097 | def getClearOutputBitmap(): | |
2098 | return BitmapFromImage(getClearOutputImage()) | |
2099 | ||
2100 | def getClearOutputImage(): | |
2101 | stream = cStringIO.StringIO(getClearOutputData()) | |
2102 | return ImageFromStream(stream) | |
2103 | ||
2104 | def getClearOutputIcon(): | |
2105 | icon = EmptyIcon() | |
2106 | icon.CopyFromBitmap(getClearOutputBitmap()) | |
2107 | return icon | |
2108 | ||
2109 | #---------------------------------------------------------------------- | |
2110 | def getCloseData(): | |
2111 | return \ | |
2112 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x12\x00\x00\x00\x12\x08\x06\ | |
2113 | \x00\x00\x00V\xce\x8eW\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ | |
2114 | \x00\x86IDAT8\x8d\xed\x90\xb1\r\x80 \x10E_"c\xd80\x02-\x138\x87;8\x8f\x8d\ | |
2115 | \x8b\xb0\x02\xa5\xad\rS\x88\xcd\x11) \x82\xb6\xbe\xea\xf2\xc9\xbd\xfc\x03~\ | |
2116 | \xdeb\x81\xb9\x90\xabJ^%\x00N\x849\x0e\xf0\x85\xbc\x8a\x12YZR2\xc7\x1eIB\xcb\ | |
2117 | \xb2\xcb\x9at\x9d\x95c\xa5Y|\x92\x0c\x0f\xa2\r8e\x1e\x81\x1d8z\xdb8\xee?Ig\ | |
2118 | \xfa\xb7\x92)\xcb\xacd\x01XZ$QD\xba\xf0\xa6\x80\xd5\x18cZ\x1b\x95$?\x1f\xb9\ | |
2119 | \x00\x1d\x94\x1e*e_\x8a~\x00\x00\x00\x00IEND\xaeB`\x82' | |
2120 | ||
2121 | def getCloseBitmap(): | |
2122 | return BitmapFromImage(getCloseImage()) | |
2123 | ||
2124 | def getCloseImage(): | |
2125 | stream = cStringIO.StringIO(getCloseData()) | |
2126 | return ImageFromStream(stream) | |
2127 | ||
2128 | def getCloseIcon(): | |
2129 | icon = EmptyIcon() | |
2130 | icon.CopyFromBitmap(getCloseBitmap()) | |
2131 | return icon | |
2132 | ||
2133 | #---------------------------------------------------------------------- | |
2134 | def getContinueData(): | |
2135 | return \ | |
2136 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
2137 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
2138 | \x00\x00\x9eIDAT8\x8d\xbd\x92\xd1\r\x83@\x0cC\xed\x8a\x11X\xac\x1b\xddF,\xd6\ | |
2139 | \x11\x90\xdc\x0f\x9a\x93s)\x14Z\xa9\x91\x10\n\x97\xbc\xd89\x80?\x84\x1a\xa4\ | |
2140 | \x83\xfc\x1c$\x1e)7\xdf<Y0\xaf\x0b\xe6\xf5\x1d\xa1\xb5\x13C\x03 !\xaa\xfd\ | |
2141 | \xed\n:mr\xc0\x1d\x8f\xc9\x9a!\t$\xe5\xd3I\xe2\xe5B$\x99\x00[\x01\xe8\xc5\ | |
2142 | \xd9G\xfaN`\xd8\x81I\xed\x8c\xb19\x94\x8d\xcbL\x00;t\xcf\x9fwPh\xdb\x0e\xe8\ | |
2143 | \xd3,\x17\x8b\xc7\x9d\xbb>\x8a \xec5\x94\tc\xc4\x12\xab\x94\xeb\x7fkWr\xc9B%\ | |
2144 | \xfc\xd2\xfcM<\x01\xf6tn\x12O3c\xe6\x00\x00\x00\x00IEND\xaeB`\x82' | |
2145 | ||
2146 | def getContinueBitmap(): | |
2147 | return BitmapFromImage(getContinueImage()) | |
2148 | ||
2149 | def getContinueImage(): | |
2150 | stream = cStringIO.StringIO(getContinueData()) | |
2151 | return ImageFromStream(stream) | |
2152 | ||
2153 | def getContinueIcon(): | |
2154 | icon = EmptyIcon() | |
2155 | icon.CopyFromBitmap(getContinueBitmap()) | |
2156 | return icon | |
2157 | ||
2158 | #---------------------------------------------------------------------- | |
2159 | def getNextData(): | |
2160 | return \ | |
2161 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
2162 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
2163 | \x00\x00\x8eIDAT8\x8d\xa5SA\x12\xc4 \x08K\xb0\xff\xde\xe9\xbf\xb7\xa6\x87\ | |
2164 | \x1d:\xba\xa2tZn(\x84`"i\x05obk\x13\xd5CmN+\xcc\x00l\xd6\x0c\x00\xf5\xf8\x0e\ | |
2165 | gK\x06\x00 \xa5=k\x00\x00\xb0\xb2]\xd4?5f\xb1\xdb\xaf\xc6\xa2\xcb\xa8\xf0?\ | |
2166 | \x1c\x98\xae\x82\xbf\x81\xa4\x8eA\x16\xe1\n\xd1\xa4\x19\xb3\xe9\n\xce\xe8\ | |
2167 | \xf1\n\x9eg^\x18\x18\x90\xec<\x11\xf9#\x04XMZ\x19\xaac@+\x94\xd4\x99)SeP\xa1\ | |
2168 | )\xd6\x1dI\xe7*\xdc\xf4\x03\xdf~\xe7\x13T^Q?:X\x19d\x00\x00\x00\x00IEND\xaeB\ | |
2169 | `\x82' | |
2170 | ||
2171 | def getNextBitmap(): | |
2172 | return BitmapFromImage(getNextImage()) | |
2173 | ||
2174 | def getNextImage(): | |
2175 | stream = cStringIO.StringIO(getNextData()) | |
2176 | return ImageFromStream(stream) | |
2177 | ||
2178 | def getNextIcon(): | |
2179 | icon = EmptyIcon() | |
2180 | icon.CopyFromBitmap(getNextBitmap()) | |
2181 | return icon | |
2182 | ||
2183 | #---------------------------------------------------------------------- | |
2184 | def getStepInData(): | |
2185 | return \ | |
2186 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
2187 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
2188 | \x00\x00\x87IDAT8\x8d\xadSA\x12\x84 \x0ck\x8a\xffv\xfc\xb74{X\xeb0P@\x07s\ | |
2189 | \x84\xa4$\x01\x00M\xb2\x02]R\x8b\xc86\xda\xdc\xedd\xb4~\xe8\x86\xc6\x01-\x93\ | |
2190 | \x96\xd9#\xf6\x06\xc3;p1I\xd1\x14\x0b#|\x17aF\xec\r\xeeF\xa0eB\xd34\xca\xd0A\ | |
2191 | ]j\x84\xa6\x03\x00""\xb7\xb0tRZ\xf7x\xb7\x83\x91]\xcb\x7fa\xd9\x89\x0fC\xfd\ | |
2192 | \x94\x9d|9\x99^k\x13\xa1 \xb3\x16\x0f#\xd4\x88N~\x14\xe1-\x96\x7f\xe3\x0f\ | |
2193 | \x11\x91UC\x0cX\'\x1e\x00\x00\x00\x00IEND\xaeB`\x82' | |
2194 | ||
2195 | def getStepInBitmap(): | |
2196 | return BitmapFromImage(getStepInImage()) | |
2197 | ||
2198 | def getStepInImage(): | |
2199 | stream = cStringIO.StringIO(getStepInData()) | |
2200 | return ImageFromStream(stream) | |
2201 | ||
2202 | def getStepInIcon(): | |
2203 | icon = EmptyIcon() | |
2204 | icon.CopyFromBitmap(getStepInBitmap()) | |
2205 | return icon | |
2206 | ||
2207 | #---------------------------------------------------------------------- | |
2208 | def getStopData(): | |
2209 | return \ | |
2210 | "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
2211 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
2212 | \x00\x00FIDAT8\x8d\xed\x91\xc1\t\xc00\x0c\x03O!\x0b\xa9\xfb\xef\xa6\xfcB\xa1\ | |
2213 | N\t\xf4Wr\xa0\x8f\xb1\x0f\x81\xe1\x97\xe4-\xb6}_V%\xc8\xc2, \t\x92\xe6]\xfbZ\ | |
2214 | \xf7\x08\xa0W\xc3\xea5\xdb\rl_IX\xe5\xf0d\x00\xfa\x8d#\x7f\xc4\xf7'\xab\x00\ | |
2215 | \x00\x00\x00IEND\xaeB`\x82" | |
2216 | ||
2217 | def getStopBitmap(): | |
2218 | return BitmapFromImage(getStopImage()) | |
2219 | ||
2220 | def getStopImage(): | |
2221 | stream = cStringIO.StringIO(getStopData()) | |
2222 | return ImageFromStream(stream) | |
2223 | ||
2224 | def getStopIcon(): | |
2225 | icon = EmptyIcon() | |
2226 | icon.CopyFromBitmap(getStopBitmap()) | |
2227 | return icon | |
2228 | ||
2229 | #---------------------------------------------------------------------- | |
2230 | def getStepReturnData(): | |
2231 | return \ | |
2232 | "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
2233 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
2234 | \x00\x00\x8dIDAT8\x8d\xa5S\xd1\x0e\xc4 \x08\xa3\xb0\xff\xbe\xdc\x7fO\xba'6\ | |
2235 | \xf1\xf44\xb3O$Phk\x04\xd4d\x07\xba\xc5\x16\x91#\nza\xdb\x84\x1a\xa2\xfe\xf8\ | |
2236 | \x99\xfa_=p+\xe8\x91ED\xbc<\xa4 \xb4\x0b\x01\xb5{\x01\xf9\xbbG-\x13\x87\x16f\ | |
2237 | \x84\xbf\x16V\xb0l\x01@\no\x86\xae\x82Q\xa8=\xa4\x0c\x80\xe70\xbd\x10jh\xbd\ | |
2238 | \x07R\x06#\xc9^N\xb6\xde\x03)\x83\x18\xaeU\x90\x9c>a\xb2P\r\xb3&/Y\xa8\xd1^^\ | |
2239 | \xb6\xf0\x16\xdb\xbf\xf1\x02\x81\xa5TK\x1d\x07\xde\x92\x00\x00\x00\x00IEND\ | |
2240 | \xaeB`\x82" | |
2241 | ||
2242 | def getStepReturnBitmap(): | |
2243 | return BitmapFromImage(getStepReturnImage()) | |
2244 | ||
2245 | def getStepReturnImage(): | |
2246 | stream = cStringIO.StringIO(getStepReturnData()) | |
2247 | return ImageFromStream(stream) | |
2248 | ||
2249 | def getStepReturnIcon(): | |
2250 | icon = EmptyIcon() | |
2251 | icon.CopyFromBitmap(getStepReturnBitmap()) | |
2252 | return icon | |
2253 | ||
2254 | def getAddWatchData(): | |
2255 | return \ | |
2256 | '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ | |
2257 | \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ | |
2258 | \x00\x00\x85IDAT8\x8dc`\x18h\xc0\x88.\xd0\xc0\xf0\xff?*\x9f\x11C\rN\x80\xae\ | |
2259 | \x19\x97\x18\xd1\x9a\x896\x84\x18[p\xa9aA\xe6\xfc7f\xc0P\xc4x\x163\x9cp\x1a0\ | |
2260 | \xeb,!w\x100 \x1dK\xac\x10\r\x08\x05".yFL\x85\x8c\x18b\xa8|Ty\xa2\x13\x92\'\ | |
2261 | \xc3\xe4\xff\x9f\x18\x1e3\xb82t\xa2\x88\x13\xedg.\x06aa&\x06VV\x7f\x86\xb9\ | |
2262 | \xcfU\x19\xbc\xb0\xba\x86h\xe0\xc8\xd0\xfc\xbf\x80\xe1>q)\x94\xe6\x00\x00\ | |
2263 | \x85\x923_\xd22\xa4\xcd\x00\x00\x00\x00IEND\xaeB`\x82' | |
2264 | ||
2265 | def getAddWatchBitmap(): | |
2266 | return BitmapFromImage(getAddWatchImage()) | |
2267 | ||
2268 | def getAddWatchImage(): | |
2269 | stream = cStringIO.StringIO(getAddWatchData()) | |
2270 | return ImageFromStream(stream) | |
2271 | ||
2272 | def getAddWatchIcon(): | |
2273 | icon = EmptyIcon() | |
2274 | icon.CopyFromBitmap(getAddWatchBitmap()) | |
2275 | return icon |