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