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