b792147db7
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@33956 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2329 lines
96 KiB
Python
2329 lines
96 KiB
Python
#----------------------------------------------------------------------------
|
|
# Name: DebuggerService.py
|
|
# Purpose: Debugger Service for Python.
|
|
#
|
|
# Author: Matt Fryer
|
|
#
|
|
# Created: 12/9/04
|
|
# CVS-ID: $Id$
|
|
# Copyright: (c) 2004-2005 ActiveGrid, Inc.
|
|
# License: wxWindows License
|
|
#----------------------------------------------------------------------------
|
|
|
|
import wx
|
|
import wx.lib.intctrl
|
|
import wx.lib.docview
|
|
import wx.lib.dialogs
|
|
import wx.gizmos
|
|
import wx._core
|
|
import wx.lib.pydocview
|
|
import Service
|
|
import STCTextEditor
|
|
import CodeEditor
|
|
import PythonEditor
|
|
from IDE import ACTIVEGRID_BASE_IDE
|
|
if not ACTIVEGRID_BASE_IDE:
|
|
import ProcessModelEditor
|
|
import wx.lib.scrolledpanel as scrolled
|
|
import sys
|
|
import time
|
|
import SimpleXMLRPCServer
|
|
import xmlrpclib
|
|
import os
|
|
import threading
|
|
import Queue
|
|
import SocketServer
|
|
import ProjectEditor
|
|
import types
|
|
from xml.dom.minidom import parse, parseString
|
|
import bz2
|
|
import pickle
|
|
import DebuggerHarness
|
|
import traceback
|
|
import StringIO
|
|
if wx.Platform == '__WXMSW__':
|
|
try:
|
|
import win32api
|
|
_PYWIN32_INSTALLED = True
|
|
except ImportError:
|
|
_PYWIN32_INSTALLED = False
|
|
_WINDOWS = True
|
|
else:
|
|
_WINDOWS = False
|
|
|
|
if not _WINDOWS or _PYWIN32_INSTALLED:
|
|
import process
|
|
|
|
_ = wx.GetTranslation
|
|
|
|
_VERBOSE = False
|
|
_WATCHES_ON = False
|
|
|
|
# Class to read from stdout or stderr and write the result to a text control.
|
|
# Args: file=file-like object
|
|
# callback_function= function that takes a single argument, the line of text
|
|
# read.
|
|
class OutputReaderThread(threading.Thread):
|
|
def __init__(self, file, callback_function, callbackOnExit=None, accumulate=True):
|
|
threading.Thread.__init__(self)
|
|
self._file = file
|
|
self._callback_function = callback_function
|
|
self._keepGoing = True
|
|
self._lineCount = 0
|
|
self._accumulate = accumulate
|
|
self._callbackOnExit = callbackOnExit
|
|
|
|
def run(self):
|
|
file = self._file
|
|
start = time.time()
|
|
output = ""
|
|
while self._keepGoing:
|
|
try:
|
|
# This could block--how to handle that?
|
|
text = file.readline()
|
|
if text == '' or text == None:
|
|
self._keepGoing = False
|
|
elif not self._accumulate:
|
|
self._callback_function(text)
|
|
else:
|
|
# Should use a buffer? StringIO?
|
|
output += text
|
|
# Seems as though the read blocks if we got an error, so, to be
|
|
# sure that at least some of the exception gets printed, always
|
|
# send the first hundred lines back as they come in.
|
|
if self._lineCount < 100:
|
|
self._callback_function(output)
|
|
self._lineCount += 1
|
|
output = ""
|
|
elif time.time() - start > 0.25:
|
|
try:
|
|
self._callback_function(output)
|
|
except wx._core.PyDeadObjectError:
|
|
# GUI was killed while we were blocked.
|
|
self._keepGoing = False
|
|
start = time.time()
|
|
output = ""
|
|
except:
|
|
tp, val, tb = sys.exc_info()
|
|
print "Exception in OutputReaderThread.run():", tp, val
|
|
self._keepGoing = False
|
|
if self._callbackOnExit:
|
|
try:
|
|
self._callbackOnExit()
|
|
except wx._core.PyDeadObjectError:
|
|
pass
|
|
if _VERBOSE: print "Exiting OutputReaderThread"
|
|
|
|
def AskToStop(self):
|
|
self._keepGoing = False
|
|
|
|
import wx.lib.newevent
|
|
(UpdateTextEvent, EVT_UPDATE_STDTEXT) = wx.lib.newevent.NewEvent()
|
|
(UpdateErrorEvent, EVT_UPDATE_ERRTEXT) = wx.lib.newevent.NewEvent()
|
|
|
|
class Executor:
|
|
|
|
def GetPythonExecutablePath():
|
|
config = wx.ConfigBase_Get()
|
|
path = config.Read("ActiveGridPythonLocation")
|
|
if path:
|
|
return path
|
|
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"))
|
|
return None
|
|
GetPythonExecutablePath = staticmethod(GetPythonExecutablePath)
|
|
|
|
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):
|
|
self._fileName = fileName
|
|
self._stdOutCallback = self.OutCall
|
|
self._stdErrCallback = self.ErrCall
|
|
self._callbackOnExit = callbackOnExit
|
|
self._wxComponent = wxComponent
|
|
path = Executor.GetPythonExecutablePath()
|
|
self._cmd = '"' + path + '" -u \"' + fileName + '\"'
|
|
#Better way to do this? Quotes needed for windows file paths.
|
|
if(arg1 != None):
|
|
self._cmd += ' \"' + arg1 + '\"'
|
|
if(arg2 != None):
|
|
self._cmd += ' \"' + arg2 + '\"'
|
|
if(arg3 != None):
|
|
self._cmd += ' \"' + arg3 + '\"'
|
|
if(arg4 != None):
|
|
self._cmd += ' \"' + arg4 + '\"'
|
|
if(arg5 != None):
|
|
self._cmd += ' \"' + arg5 + '\"'
|
|
if(arg6 != None):
|
|
self._cmd += ' \"' + arg6 + '\"'
|
|
if(arg7 != None):
|
|
self._cmd += ' \"' + arg7 + '\"'
|
|
if(arg8 != None):
|
|
self._cmd += ' \"' + arg8 + '\"'
|
|
if(arg9 != None):
|
|
self._cmd += ' \"' + arg9 + '\"'
|
|
|
|
self._stdOutReader = None
|
|
self._stdErrReader = None
|
|
self._process = None
|
|
|
|
def OutCall(self, text):
|
|
evt = UpdateTextEvent(value = text)
|
|
wx.PostEvent(self._wxComponent, evt)
|
|
|
|
def ErrCall(self, text):
|
|
evt = UpdateErrorEvent(value = text)
|
|
wx.PostEvent(self._wxComponent, evt)
|
|
|
|
def Execute(self, arguments, startIn=None, environment=None):
|
|
if not startIn:
|
|
startIn = str(os.getcwd())
|
|
startIn = os.path.abspath(startIn)
|
|
command = self._cmd + ' ' + arguments
|
|
#stdinput = process.IOBuffer()
|
|
#self._process = process.ProcessProxy(command, mode='b', cwd=startIn, stdin=stdinput)
|
|
self._process = process.ProcessOpen(command, mode='b', cwd=startIn, env=environment)
|
|
# Kick off threads to read stdout and stderr and write them
|
|
# to our text control.
|
|
self._stdOutReader = OutputReaderThread(self._process.stdout, self._stdOutCallback, callbackOnExit=self._callbackOnExit)
|
|
self._stdOutReader.start()
|
|
self._stdErrReader = OutputReaderThread(self._process.stderr, self._stdErrCallback, accumulate=False)
|
|
self._stdErrReader.start()
|
|
|
|
|
|
def DoStopExecution(self):
|
|
if(self._process != None):
|
|
self._process.kill()
|
|
self._process.close()
|
|
self._process = None
|
|
if(self._stdOutReader != None):
|
|
self._stdOutReader.AskToStop()
|
|
if(self._stdErrReader != None):
|
|
self._stdErrReader.AskToStop()
|
|
|
|
class RunCommandUI(wx.Panel):
|
|
|
|
def __init__(self, parent, id, fileName):
|
|
wx.Panel.__init__(self, parent, id)
|
|
self._noteBook = parent
|
|
|
|
self.KILL_PROCESS_ID = wx.NewId()
|
|
self.CLOSE_TAB_ID = wx.NewId()
|
|
|
|
self.Bind(wx.EVT_END_PROCESS, self.OnProcessEnded)
|
|
|
|
# GUI Initialization follows
|
|
sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
self._tb = tb = wx.ToolBar(self, -1, wx.DefaultPosition, (30,1000), wx.TB_VERTICAL| wx.TB_FLAT, "Runner" )
|
|
tb.SetToolBitmapSize((16,16))
|
|
sizer.Add(tb, 0, wx.EXPAND |wx.ALIGN_LEFT|wx.ALL, 1)
|
|
|
|
close_bmp = getCloseBitmap()
|
|
tb.AddSimpleTool( self.CLOSE_TAB_ID, close_bmp, _('Close Window'))
|
|
wx.EVT_TOOL(self, self.CLOSE_TAB_ID, self.OnToolClicked)
|
|
|
|
stop_bmp = getStopBitmap()
|
|
tb.AddSimpleTool(self.KILL_PROCESS_ID, stop_bmp, _("Stop the Run."))
|
|
wx.EVT_TOOL(self, self.KILL_PROCESS_ID, self.OnToolClicked)
|
|
|
|
tb.Realize()
|
|
self._textCtrl = STCTextEditor.TextCtrl(self, wx.NewId()) #id)
|
|
sizer.Add(self._textCtrl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1)
|
|
self._textCtrl.SetViewLineNumbers(False)
|
|
self._textCtrl.SetReadOnly(True)
|
|
if wx.Platform == '__WXMSW__':
|
|
font = "Courier New"
|
|
else:
|
|
font = "Courier"
|
|
self._textCtrl.SetFont(wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = font))
|
|
self._textCtrl.SetFontColor(wx.BLACK)
|
|
self._textCtrl.StyleClearAll()
|
|
|
|
#Disabling for now...may interfere with file open. wx.stc.EVT_STC_DOUBLECLICK(self._textCtrl, self._textCtrl.GetId(), self.OnDoubleClick)
|
|
|
|
self.SetSizer(sizer)
|
|
sizer.Fit(self)
|
|
|
|
# Executor initialization
|
|
self._executor = Executor(fileName, self, callbackOnExit=self.ExecutorFinished)
|
|
self.Bind(EVT_UPDATE_STDTEXT, self.AppendText)
|
|
self.Bind(EVT_UPDATE_ERRTEXT, self.AppendErrorText)
|
|
|
|
def __del__(self):
|
|
self._executor.DoStopExecution()
|
|
|
|
def Execute(self, initialArgs, startIn, environment):
|
|
self._executor.Execute(initialArgs, startIn, environment)
|
|
|
|
def ExecutorFinished(self):
|
|
self._tb.EnableTool(self.KILL_PROCESS_ID, False)
|
|
nb = self.GetParent()
|
|
for i in range(0,nb.GetPageCount()):
|
|
if self == nb.GetPage(i):
|
|
text = nb.GetPageText(i)
|
|
newText = text.replace("Running", "Finished")
|
|
nb.SetPageText(i, newText)
|
|
break
|
|
|
|
def StopExecution(self):
|
|
self.Unbind(EVT_UPDATE_STDTEXT)
|
|
self.Unbind(EVT_UPDATE_ERRTEXT)
|
|
self._executor.DoStopExecution()
|
|
|
|
def AppendText(self, event):
|
|
self._textCtrl.SetReadOnly(False)
|
|
self._textCtrl.AddText(event.value)
|
|
self._textCtrl.ScrollToLine(self._textCtrl.GetLineCount())
|
|
self._textCtrl.SetReadOnly(True)
|
|
|
|
def AppendErrorText(self, event):
|
|
self._textCtrl.SetReadOnly(False)
|
|
self._textCtrl.SetFontColor(wx.RED)
|
|
self._textCtrl.StyleClearAll()
|
|
self._textCtrl.AddText(event.value)
|
|
self._textCtrl.ScrollToLine(self._textCtrl.GetLineCount())
|
|
self._textCtrl.SetFontColor(wx.BLACK)
|
|
self._textCtrl.StyleClearAll()
|
|
self._textCtrl.SetReadOnly(True)
|
|
|
|
#------------------------------------------------------------------------------
|
|
# Event handling
|
|
#-----------------------------------------------------------------------------
|
|
|
|
def OnToolClicked(self, event):
|
|
id = event.GetId()
|
|
|
|
if id == self.KILL_PROCESS_ID:
|
|
self._executor.DoStopExecution()
|
|
|
|
elif id == self.CLOSE_TAB_ID:
|
|
self._executor.DoStopExecution()
|
|
index = self._noteBook.GetSelection()
|
|
self._noteBook.GetPage(index).Show(False)
|
|
self._noteBook.RemovePage(index)
|
|
|
|
def OnDoubleClick(self, event):
|
|
# Looking for a stack trace line.
|
|
lineText, pos = self._textCtrl.GetCurLine()
|
|
fileBegin = lineText.find("File \"")
|
|
fileEnd = lineText.find("\", line ")
|
|
lineEnd = lineText.find(", in ")
|
|
if lineText == "\n" or fileBegin == -1 or fileEnd == -1 or lineEnd == -1:
|
|
# Check the line before the one that was clicked on
|
|
lineNumber = self._textCtrl.GetCurrentLine()
|
|
if(lineNumber == 0):
|
|
return
|
|
lineText = self._textCtrl.GetLine(lineNumber - 1)
|
|
fileBegin = lineText.find("File \"")
|
|
fileEnd = lineText.find("\", line ")
|
|
lineEnd = lineText.find(", in ")
|
|
if lineText == "\n" or fileBegin == -1 or fileEnd == -1 or lineEnd == -1:
|
|
return
|
|
|
|
filename = lineText[fileBegin + 6:fileEnd]
|
|
lineNum = int(lineText[fileEnd + 8:lineEnd])
|
|
|
|
foundView = None
|
|
openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
|
|
for openDoc in openDocs:
|
|
if openDoc.GetFilename() == filename:
|
|
foundView = openDoc.GetFirstView()
|
|
break
|
|
|
|
if not foundView:
|
|
doc = wx.GetApp().GetDocumentManager().CreateDocument(filename, wx.lib.docview.DOC_SILENT)
|
|
foundView = doc.GetFirstView()
|
|
|
|
if foundView:
|
|
foundView.GetFrame().SetFocus()
|
|
foundView.Activate()
|
|
foundView.GotoLine(lineNum)
|
|
startPos = foundView.PositionFromLine(lineNum)
|
|
|
|
# FACTOR THIS INTO DocManager
|
|
openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
|
|
for openDoc in openDocs:
|
|
if(isinstance(openDoc.GetFirstView(), CodeEditor.CodeView)):
|
|
openDoc.GetFirstView().GetCtrl().ClearCurrentLineMarkers()
|
|
|
|
foundView.GetCtrl().MarkerAdd(lineNum -1, CodeEditor.CodeCtrl.CURRENT_LINE_MARKER_NUM)
|
|
|
|
def OnProcessEnded(self, evt):
|
|
self._executor.DoStopExecution()
|
|
|
|
DEFAULT_PORT = 32032
|
|
DEFAULT_HOST = 'localhost'
|
|
PORT_COUNT = 21
|
|
|
|
class DebugCommandUI(wx.Panel):
|
|
debuggerPortList = None
|
|
debuggers = []
|
|
|
|
def NotifyDebuggersOfBreakpointChange():
|
|
for debugger in DebugCommandUI.debuggers:
|
|
debugger.BreakPointChange()
|
|
|
|
NotifyDebuggersOfBreakpointChange = staticmethod(NotifyDebuggersOfBreakpointChange)
|
|
|
|
def DebuggerRunning():
|
|
for debugger in DebugCommandUI.debuggers:
|
|
if debugger._executor:
|
|
return True
|
|
return False
|
|
DebuggerRunning = staticmethod(DebuggerRunning)
|
|
|
|
def ShutdownAllDebuggers():
|
|
for debugger in DebugCommandUI.debuggers:
|
|
debugger.StopExecution()
|
|
|
|
ShutdownAllDebuggers = staticmethod(ShutdownAllDebuggers)
|
|
|
|
def GetAvailablePort():
|
|
for index in range( 0, len(DebugCommandUI.debuggerPortList)):
|
|
port = DebugCommandUI.debuggerPortList[index]
|
|
if DebugCommandUI.PortAvailable(port):
|
|
DebugCommandUI.debuggerPortList.pop(index)
|
|
return port
|
|
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"))
|
|
assert False, "Out of ports for debugger."
|
|
|
|
GetAvailablePort = staticmethod(GetAvailablePort)
|
|
|
|
def ReturnPortToPool(port):
|
|
config = wx.ConfigBase_Get()
|
|
startingPort = config.ReadInt("DebuggerStartingPort", DEFAULT_PORT)
|
|
if port in range(startingPort, startingPort + PORT_COUNT):
|
|
DebugCommandUI.debuggerPortList.append(port)
|
|
|
|
ReturnPortToPool = staticmethod(ReturnPortToPool)
|
|
|
|
def PortAvailable(port):
|
|
config = wx.ConfigBase_Get()
|
|
hostname = config.Read("DebuggerHostName", DEFAULT_HOST)
|
|
try:
|
|
server = AGXMLRPCServer((hostname, port))
|
|
server.server_close()
|
|
if _VERBOSE: print "Port ", str(port), " available."
|
|
return True
|
|
except:
|
|
tp,val,tb = sys.exc_info()
|
|
if _VERBOSE: traceback.print_exception(tp, val, tb)
|
|
if _VERBOSE: print "Port ", str(port), " unavailable."
|
|
return False
|
|
|
|
PortAvailable = staticmethod(PortAvailable)
|
|
|
|
def NewPortRange():
|
|
config = wx.ConfigBase_Get()
|
|
startingPort = config.ReadInt("DebuggerStartingPort", DEFAULT_PORT)
|
|
DebugCommandUI.debuggerPortList = range(startingPort, startingPort + PORT_COUNT)
|
|
NewPortRange = staticmethod(NewPortRange)
|
|
|
|
def __init__(self, parent, id, command, service):
|
|
# Check for ports before creating the panel.
|
|
if not DebugCommandUI.debuggerPortList:
|
|
DebugCommandUI.NewPortRange()
|
|
self._debuggerPort = str(DebugCommandUI.GetAvailablePort())
|
|
self._guiPort = str(DebugCommandUI.GetAvailablePort())
|
|
self._debuggerBreakPort = str(DebugCommandUI.GetAvailablePort())
|
|
|
|
wx.Panel.__init__(self, parent, id)
|
|
|
|
self._parentNoteBook = parent
|
|
self._command = command
|
|
self._textCtrl = None
|
|
self._service = service
|
|
self._executor = None
|
|
self.STEP_ID = wx.NewId()
|
|
self.CONTINUE_ID = wx.NewId()
|
|
self.STEP_OUT_ID = wx.NewId()
|
|
self.NEXT_ID = wx.NewId()
|
|
self.KILL_PROCESS_ID = wx.NewId()
|
|
self.CLOSE_WINDOW_ID = wx.NewId()
|
|
self.BREAK_INTO_DEBUGGER_ID = wx.NewId()
|
|
self.CLEAR_ID = wx.NewId()
|
|
self.ADD_WATCH_ID = wx.NewId()
|
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
|
self._tb = tb = wx.ToolBar(self, -1, wx.DefaultPosition, (1000,30), wx.TB_HORIZONTAL| wx.NO_BORDER| wx.TB_FLAT| wx.TB_TEXT, "Debugger" )
|
|
sizer.Add(tb, 0, wx.EXPAND |wx.ALIGN_LEFT|wx.ALL, 1)
|
|
tb.SetToolBitmapSize((16,16))
|
|
|
|
close_bmp = getCloseBitmap()
|
|
tb.AddSimpleTool( self.CLOSE_WINDOW_ID, close_bmp, _('Close Window'))
|
|
wx.EVT_TOOL(self, self.CLOSE_WINDOW_ID, self.StopAndRemoveUI)
|
|
|
|
stop_bmp = getStopBitmap()
|
|
tb.AddSimpleTool( self.KILL_PROCESS_ID, stop_bmp, _("Stop Debugging"))
|
|
wx.EVT_TOOL(self, self.KILL_PROCESS_ID, self.StopExecution)
|
|
|
|
tb.AddSeparator()
|
|
|
|
break_bmp = getBreakBitmap()
|
|
tb.AddSimpleTool( self.BREAK_INTO_DEBUGGER_ID, break_bmp, _("Break into Debugger"))
|
|
wx.EVT_TOOL(self, self.BREAK_INTO_DEBUGGER_ID, self.BreakExecution)
|
|
|
|
tb.AddSeparator()
|
|
|
|
continue_bmp = getContinueBitmap()
|
|
tb.AddSimpleTool( self.CONTINUE_ID, continue_bmp, _("Continue Execution"))
|
|
wx.EVT_TOOL(self, self.CONTINUE_ID, self.OnContinue)
|
|
|
|
tb.AddSeparator()
|
|
|
|
next_bmp = getNextBitmap()
|
|
tb.AddSimpleTool( self.NEXT_ID, next_bmp, _("Step to next line"))
|
|
wx.EVT_TOOL(self, self.NEXT_ID, self.OnNext)
|
|
|
|
step_bmp = getStepInBitmap()
|
|
tb.AddSimpleTool( self.STEP_ID, step_bmp, _("Step in"))
|
|
wx.EVT_TOOL(self, self.STEP_ID, self.OnSingleStep)
|
|
|
|
stepOut_bmp = getStepReturnBitmap()
|
|
tb.AddSimpleTool(self.STEP_OUT_ID, stepOut_bmp, _("Stop at function return"))
|
|
wx.EVT_TOOL(self, self.STEP_OUT_ID, self.OnStepOut)
|
|
|
|
tb.AddSeparator()
|
|
if _WATCHES_ON:
|
|
watch_bmp = getAddWatchBitmap()
|
|
tb.AddSimpleTool(self.ADD_WATCH_ID, watch_bmp, _("Add a watch"))
|
|
wx.EVT_TOOL(self, self.ADD_WATCH_ID, self.OnAddWatch)
|
|
tb.AddSeparator()
|
|
|
|
clear_bmp = getClearOutputBitmap()
|
|
tb.AddSimpleTool(self.CLEAR_ID, clear_bmp, _("Clear output pane"))
|
|
wx.EVT_TOOL(self, self.CLEAR_ID, self.OnClearOutput)
|
|
|
|
tb.Realize()
|
|
self.framesTab = None
|
|
self.DisableWhileDebuggerRunning()
|
|
self._notebook = wx.Notebook(self, -1, wx.DefaultPosition, wx.DefaultSize, wx.LB_DEFAULT, "Debugger")
|
|
sizer.Add(self._notebook, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1)
|
|
self.consoleTab = self.MakeConsoleTab(self._notebook, wx.NewId(), None)
|
|
self.framesTab = self.MakeFramesTab(self._notebook, wx.NewId(), None)
|
|
self.breakPointsTab = self.MakeBreakPointsTab(self._notebook, wx.NewId(), None)
|
|
self._notebook.AddPage(self.consoleTab, "Output")
|
|
self._notebook.AddPage(self.framesTab, "Frames")
|
|
self._notebook.AddPage(self.breakPointsTab, "Break Points")
|
|
|
|
self._statusBar = wx.StatusBar( self, -1)
|
|
self._statusBar.SetFieldsCount(1)
|
|
sizer.Add(self._statusBar, 0, wx.EXPAND |wx.ALIGN_LEFT|wx.ALL, 1)
|
|
|
|
self.SetStatusText("Starting debug...")
|
|
|
|
self.SetSizer(sizer)
|
|
sizer.Fit(self)
|
|
config = wx.ConfigBase_Get()
|
|
self._debuggerHost = self._guiHost = config.Read("DebuggerHostName", DEFAULT_HOST)
|
|
url = 'http://' + self._debuggerHost + ':' + self._debuggerPort + '/'
|
|
self._breakURL = 'http://' + self._debuggerHost + ':' + self._debuggerBreakPort + '/'
|
|
self._callback = DebuggerCallback(self._guiHost, self._guiPort, url, self._breakURL, self)
|
|
if DebuggerHarness.__file__.find('library.zip') > 0:
|
|
try:
|
|
fname = DebuggerHarness.__file__
|
|
parts = fname.split('library.zip')
|
|
path = os.path.join(parts[0],'activegrid', 'tool', 'DebuggerHarness.py')
|
|
except:
|
|
tp, val, tb = sys.exc_info()
|
|
traceback.print_exception(tp, val, tb)
|
|
|
|
else:
|
|
print "Starting debugger on these ports: %s, %s, %s" % (str(self._debuggerPort) , str(self._guiPort) , str(self._debuggerBreakPort))
|
|
path = DebuggerService.ExpandPath(DebuggerHarness.__file__)
|
|
self._executor = Executor(path, self, self._debuggerHost, \
|
|
self._debuggerPort, self._debuggerBreakPort, self._guiHost, self._guiPort, self._command, callbackOnExit=self.ExecutorFinished)
|
|
|
|
self.Bind(EVT_UPDATE_STDTEXT, self.AppendText)
|
|
self.Bind(EVT_UPDATE_ERRTEXT, self.AppendErrorText)
|
|
DebugCommandUI.debuggers.append(self)
|
|
self._stopped = False
|
|
|
|
def OnSingleStep(self, event):
|
|
self._callback.SingleStep()
|
|
|
|
def OnContinue(self, event):
|
|
self._callback.Continue()
|
|
|
|
def OnStepOut(self, event):
|
|
self._callback.Return()
|
|
|
|
def OnNext(self, event):
|
|
self._callback.Next()
|
|
|
|
def BreakPointChange(self):
|
|
if not self._stopped:
|
|
self._callback.pushBreakpoints()
|
|
self.breakPointsTab.PopulateBPList()
|
|
|
|
def __del__(self):
|
|
if self in DebugCommandUI.debuggers:
|
|
DebugCommandUI.debuggers.remove(self)
|
|
|
|
def SwitchToOutputTab(self):
|
|
self._notebook.SetSelection(0)
|
|
|
|
def DisableWhileDebuggerRunning(self):
|
|
self._tb.EnableTool(self.STEP_ID, False)
|
|
self._tb.EnableTool(self.CONTINUE_ID, False)
|
|
self._tb.EnableTool(self.STEP_OUT_ID, False)
|
|
self._tb.EnableTool(self.NEXT_ID, False)
|
|
self._tb.EnableTool(self.BREAK_INTO_DEBUGGER_ID, True)
|
|
if _WATCHES_ON:
|
|
self._tb.EnableTool(self.ADD_WATCH_ID, False)
|
|
openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
|
|
for openDoc in openDocs:
|
|
if(isinstance(openDoc.GetFirstView(), CodeEditor.CodeView)):
|
|
openDoc.GetFirstView().GetCtrl().ClearCurrentLineMarkers()
|
|
if self.framesTab:
|
|
self.framesTab.ClearWhileRunning()
|
|
#wx.GetApp().ProcessPendingEvents() #Yield(True)
|
|
|
|
def EnableWhileDebuggerStopped(self):
|
|
self._tb.EnableTool(self.STEP_ID, True)
|
|
self._tb.EnableTool(self.CONTINUE_ID, True)
|
|
self._tb.EnableTool(self.STEP_OUT_ID, True)
|
|
self._tb.EnableTool(self.NEXT_ID, True)
|
|
if _WATCHES_ON:
|
|
self._tb.EnableTool(self.ADD_WATCH_ID, True)
|
|
self._tb.EnableTool(self.BREAK_INTO_DEBUGGER_ID, False)
|
|
#if _WINDOWS:
|
|
# wx.GetApp().GetTopWindow().RequestUserAttention()
|
|
|
|
def ExecutorFinished(self):
|
|
if _VERBOSE: print "In ExectorFinished"
|
|
try:
|
|
self.DisableAfterStop()
|
|
except wx._core.PyDeadObjectError:
|
|
pass
|
|
try:
|
|
nb = self.GetParent()
|
|
for i in range(0, nb.GetPageCount()):
|
|
if self == nb.GetPage(i):
|
|
text = nb.GetPageText(i)
|
|
newText = text.replace("Debugging", "Finished")
|
|
nb.SetPageText(i, newText)
|
|
if _VERBOSE: print "In ExectorFinished, changed tab title."
|
|
break
|
|
except:
|
|
if _VERBOSE: print "In ExectorFinished, got exception"
|
|
|
|
def DisableAfterStop(self):
|
|
self.DisableWhileDebuggerRunning()
|
|
self._tb.EnableTool(self.BREAK_INTO_DEBUGGER_ID, False)
|
|
self._tb.EnableTool(self.KILL_PROCESS_ID, False)
|
|
|
|
def SynchCurrentLine(self, filename, lineNum):
|
|
# FACTOR THIS INTO DocManager
|
|
self.DeleteCurrentLineMarkers()
|
|
|
|
# Filename will be <string> if we're in a bit of code that was executed from
|
|
# a string (rather than a file). I haven't been able to get the original string
|
|
# for display.
|
|
if filename == '<string>':
|
|
return
|
|
foundView = None
|
|
openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
|
|
for openDoc in openDocs:
|
|
# This ugliness to prevent comparison failing because the drive letter
|
|
# gets lowercased occasionally. Don't know why that happens or why it
|
|
# only happens occasionally.
|
|
if DebuggerService.ComparePaths(openDoc.GetFilename(),filename):
|
|
foundView = openDoc.GetFirstView()
|
|
break
|
|
|
|
if not foundView:
|
|
if _VERBOSE:
|
|
print "filename=", filename
|
|
doc = wx.GetApp().GetDocumentManager().CreateDocument(DebuggerService.ExpandPath(filename), wx.lib.docview.DOC_SILENT)
|
|
foundView = doc.GetFirstView()
|
|
|
|
if foundView:
|
|
foundView.GetFrame().SetFocus()
|
|
foundView.Activate()
|
|
foundView.GotoLine(lineNum)
|
|
startPos = foundView.PositionFromLine(lineNum)
|
|
|
|
foundView.GetCtrl().MarkerAdd(lineNum -1, CodeEditor.CodeCtrl.CURRENT_LINE_MARKER_NUM)
|
|
|
|
def DeleteCurrentLineMarkers(self):
|
|
openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
|
|
for openDoc in openDocs:
|
|
if(isinstance(openDoc.GetFirstView(), CodeEditor.CodeView)):
|
|
openDoc.GetFirstView().GetCtrl().ClearCurrentLineMarkers()
|
|
|
|
def LoadFramesListXML(self, framesXML):
|
|
self.framesTab.LoadFramesListXML(framesXML)
|
|
|
|
def SetStatusText(self, text):
|
|
self._statusBar.SetStatusText(text,0)
|
|
|
|
def Execute(self, initialArgs, startIn, environment):
|
|
self._callback.start()
|
|
self._executor.Execute(initialArgs, startIn, environment)
|
|
self._callback.waitForRPC()
|
|
|
|
def BreakExecution(self, event):
|
|
self._callback.BreakExecution()
|
|
|
|
|
|
def StopExecution(self, event):
|
|
self._stopped = True
|
|
self.DisableAfterStop()
|
|
try:
|
|
self._callback.ServerClose()
|
|
except:
|
|
pass
|
|
try:
|
|
if self._executor:
|
|
self._executor.DoStopExecution()
|
|
self._executor = None
|
|
except:
|
|
pass
|
|
self.DeleteCurrentLineMarkers()
|
|
DebugCommandUI.ReturnPortToPool(self._debuggerPort)
|
|
DebugCommandUI.ReturnPortToPool(self._guiPort)
|
|
DebugCommandUI.ReturnPortToPool(self._debuggerBreakPort)
|
|
|
|
def StopAndRemoveUI(self, event):
|
|
self.StopExecution(None)
|
|
if self in DebugCommandUI.debuggers:
|
|
DebugCommandUI.debuggers.remove(self)
|
|
index = self._parentNoteBook.GetSelection()
|
|
self._parentNoteBook.GetPage(index).Show(False)
|
|
self._parentNoteBook.RemovePage(index)
|
|
|
|
def GetConsoleTextControl(self):
|
|
return self._textCtrl
|
|
|
|
def OnClearOutput(self, event):
|
|
self._textCtrl.SetReadOnly(False)
|
|
self._textCtrl.ClearAll()
|
|
self._textCtrl.SetReadOnly(True)
|
|
|
|
def OnAddWatch(self, event):
|
|
if self.framesTab:
|
|
self.framesTab.OnWatch(event)
|
|
|
|
def MakeConsoleTab(self, parent, id, debugger):
|
|
panel = wx.Panel(parent, id)
|
|
sizer = wx.BoxSizer(wx.HORIZONTAL)
|
|
self._textCtrl = STCTextEditor.TextCtrl(panel, wx.NewId())
|
|
sizer.Add(self._textCtrl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1)
|
|
self._textCtrl.SetViewLineNumbers(False)
|
|
self._textCtrl.SetReadOnly(True)
|
|
if wx.Platform == '__WXMSW__':
|
|
font = "Courier New"
|
|
else:
|
|
font = "Courier"
|
|
self._textCtrl.SetFont(wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = font))
|
|
self._textCtrl.SetFontColor(wx.BLACK)
|
|
self._textCtrl.StyleClearAll()
|
|
panel.SetSizer(sizer)
|
|
sizer.Fit(panel)
|
|
|
|
return panel
|
|
|
|
def MakeFramesTab(self, parent, id, debugger):
|
|
panel = FramesUI(parent, id, self)
|
|
return panel
|
|
|
|
def MakeBreakPointsTab(self, parent, id, debugger):
|
|
panel = BreakpointsUI(parent, id, self)
|
|
return panel
|
|
|
|
def AppendText(self, event):
|
|
self._textCtrl.SetReadOnly(False)
|
|
self._textCtrl.AddText(event.value)
|
|
self._textCtrl.ScrollToLine(self._textCtrl.GetLineCount())
|
|
self._textCtrl.SetReadOnly(True)
|
|
|
|
def AppendErrorText(self, event):
|
|
self._textCtrl.SetReadOnly(False)
|
|
self._textCtrl.SetFontColor(wx.RED)
|
|
self._textCtrl.StyleClearAll()
|
|
self._textCtrl.AddText(event.value)
|
|
self._textCtrl.ScrollToLine(self._textCtrl.GetLineCount())
|
|
self._textCtrl.SetFontColor(wx.BLACK)
|
|
self._textCtrl.StyleClearAll()
|
|
self._textCtrl.SetReadOnly(True)
|
|
|
|
class BreakpointsUI(wx.Panel):
|
|
def __init__(self, parent, id, ui):
|
|
wx.Panel.__init__(self, parent, id)
|
|
self._ui = ui
|
|
self.currentItem = None
|
|
self.clearBPID = wx.NewId()
|
|
self.Bind(wx.EVT_MENU, self.ClearBreakPoint, id=self.clearBPID)
|
|
self.syncLineID = wx.NewId()
|
|
self.Bind(wx.EVT_MENU, self.SyncBPLine, id=self.syncLineID)
|
|
|
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
|
p1 = self
|
|
self._bpListCtrl = wx.ListCtrl(p1, -1, pos=wx.DefaultPosition, size=(1000,1000), style=wx.LC_REPORT)
|
|
sizer.Add(self._bpListCtrl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1)
|
|
self._bpListCtrl.InsertColumn(0, "File")
|
|
self._bpListCtrl.InsertColumn(1, "Line")
|
|
self._bpListCtrl.InsertColumn(2, "Path")
|
|
self._bpListCtrl.SetColumnWidth(0, 150)
|
|
self._bpListCtrl.SetColumnWidth(1, 50)
|
|
self._bpListCtrl.SetColumnWidth(2, 450)
|
|
self._bpListCtrl.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnListRightClick)
|
|
self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.ListItemSelected, self._bpListCtrl)
|
|
self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.ListItemDeselected, self._bpListCtrl)
|
|
|
|
self.PopulateBPList()
|
|
|
|
p1.SetSizer(sizer)
|
|
sizer.Fit(p1)
|
|
p1.Layout()
|
|
|
|
def PopulateBPList(self):
|
|
list = self._bpListCtrl
|
|
list.DeleteAllItems()
|
|
|
|
bps = wx.GetApp().GetService(DebuggerService).GetMasterBreakpointDict()
|
|
index = 0
|
|
for fileName in bps.keys():
|
|
shortFile = os.path.basename(fileName)
|
|
lines = bps[fileName]
|
|
if lines:
|
|
for line in lines:
|
|
list.InsertStringItem(index, shortFile)
|
|
list.SetStringItem(index, 1, str(line))
|
|
list.SetStringItem(index, 2, fileName)
|
|
|
|
def OnListRightClick(self, event):
|
|
menu = wx.Menu()
|
|
item = wx.MenuItem(menu, self.clearBPID, "Clear Breakpoint")
|
|
menu.AppendItem(item)
|
|
item = wx.MenuItem(menu, self.syncLineID, "Goto Source Line")
|
|
menu.AppendItem(item)
|
|
self.PopupMenu(menu, event.GetPosition())
|
|
menu.Destroy()
|
|
|
|
def SyncBPLine(self, event):
|
|
if self.currentItem != -1:
|
|
list = self._bpListCtrl
|
|
fileName = list.GetItem(self.currentItem, 2).GetText()
|
|
lineNumber = list.GetItem(self.currentItem, 1).GetText()
|
|
self._ui.SynchCurrentLine( fileName, int(lineNumber) )
|
|
|
|
def ClearBreakPoint(self, event):
|
|
if self.currentItem >= 0:
|
|
list = self._bpListCtrl
|
|
fileName = list.GetItem(self.currentItem, 2).GetText()
|
|
lineNumber = list.GetItem(self.currentItem, 1).GetText()
|
|
wx.GetApp().GetService(DebuggerService).OnToggleBreakpoint(None, line=int(lineNumber) -1, fileName=fileName )
|
|
|
|
def ListItemSelected(self, event):
|
|
self.currentItem = event.m_itemIndex
|
|
|
|
def ListItemDeselected(self, event):
|
|
self.currentItem = -1
|
|
|
|
class Watch:
|
|
CODE_ALL_FRAMES = 1
|
|
CODE_THIS_BLOCK = 2
|
|
CODE_THIS_LINE = 4
|
|
CODE_RUN_ONCE = 8
|
|
|
|
def __init__(self, name, command, show_code=CODE_ALL_FRAMES):
|
|
self._name = name
|
|
self._command = command
|
|
self._show_code = show_code
|
|
|
|
class WatchDialog(wx.Dialog):
|
|
WATCH_ALL_FRAMES = "Watch in all frames"
|
|
WATCH_THIS_FRAME = "Watch in this frame only"
|
|
WATCH_ONCE = "Watch once and delete"
|
|
def __init__(self, parent, title, chain):
|
|
wx.Dialog.__init__(self, parent, -1, title, style=wx.DEFAULT_DIALOG_STYLE)
|
|
self._chain = chain
|
|
self.label_2 = wx.StaticText(self, -1, "Watch Name:")
|
|
self._watchNameTextCtrl = wx.TextCtrl(self, -1, "")
|
|
self.label_3 = wx.StaticText(self, -1, "eval(", style=wx.ALIGN_RIGHT)
|
|
self._watchValueTextCtrl = wx.TextCtrl(self, -1, "")
|
|
self.label_4 = wx.StaticText(self, -1, ",frame.f_globals, frame.f_locals)")
|
|
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)
|
|
|
|
self._okButton = wx.Button(self, wx.ID_OK, "OK", size=(75,-1))
|
|
self._okButton.SetDefault()
|
|
self._okButton.SetHelpText(_("The OK button completes the dialog"))
|
|
def OnOkClick(event):
|
|
if self._watchNameTextCtrl.GetValue() == "":
|
|
wx.MessageBox(_("You must enter a name for the watch."), _("Add Watch"))
|
|
return
|
|
if self._watchValueTextCtrl.GetValue() == "":
|
|
wx.MessageBox(_("You must enter some code to run for the watch."), _("Add Watch"))
|
|
return
|
|
self.EndModal(wx.ID_OK)
|
|
self.Bind(wx.EVT_BUTTON, OnOkClick, self._okButton)
|
|
|
|
self._cancelButton = wx.Button(self, wx.ID_CANCEL, _("Cancel"), size=(75,-1))
|
|
self._cancelButton.SetHelpText(_("The Cancel button cancels the dialog."))
|
|
|
|
self.__set_properties()
|
|
self.__do_layout()
|
|
|
|
def GetSettings(self):
|
|
return self._watchNameTextCtrl.GetValue(), self._watchValueTextCtrl.GetValue(), self.GetSendFrame(), self.GetRunOnce()
|
|
|
|
def GetSendFrame(self):
|
|
return (WatchDialog.WATCH_ALL_FRAMES != self.radio_box_1.GetStringSelection())
|
|
|
|
def GetRunOnce(self):
|
|
return (WatchDialog.WATCH_ONCE == self.radio_box_1.GetStringSelection())
|
|
|
|
def __set_properties(self):
|
|
self.SetTitle("Add a Watch")
|
|
#self.SetSize((400, 250))
|
|
self.radio_box_1.SetSelection(0)
|
|
|
|
def __do_layout(self):
|
|
sizer_1 = wx.BoxSizer(wx.VERTICAL)
|
|
grid_sizer_4 = wx.FlexGridSizer(1, 3, 5, 5)
|
|
grid_sizer_2 = wx.FlexGridSizer(1, 2, 5, 5)
|
|
grid_sizer_2.Add(self.label_2, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
|
|
grid_sizer_2.Add(self._watchNameTextCtrl, 0, wx.EXPAND, 0)
|
|
grid_sizer_2.AddGrowableCol(1)
|
|
sizer_1.Add(grid_sizer_2, 1, wx.EXPAND, 0)
|
|
grid_sizer_4.Add(self.label_3, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
|
|
grid_sizer_4.Add(self._watchValueTextCtrl, 0, wx.EXPAND, 0)
|
|
grid_sizer_4.AddGrowableCol(1)
|
|
grid_sizer_4.Add(self.label_4, 0, wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 0)
|
|
sizer_1.Add(grid_sizer_4, 0, wx.EXPAND, 0)
|
|
sizer_1.Add(self.radio_box_1, 0, wx.EXPAND, 0)
|
|
|
|
box = wx.BoxSizer(wx.HORIZONTAL)
|
|
box.Add(self._okButton, 0, wx.ALIGN_RIGHT|wx.ALL, 5)
|
|
box.Add(self._cancelButton, 0, wx.ALIGN_RIGHT|wx.ALL, 5)
|
|
sizer_1.Add(box, 1, wx.EXPAND, 0)
|
|
self.SetAutoLayout(True)
|
|
self.SetSizer(sizer_1)
|
|
self.Layout()
|
|
|
|
class FramesUI(wx.SplitterWindow):
|
|
def __init__(self, parent, id, ui):
|
|
wx.SplitterWindow.__init__(self, parent, id, style = wx.SP_3D)
|
|
self._ui = ui
|
|
sizer = wx.BoxSizer(wx.VERTICAL)
|
|
self._p1 = p1 = wx.ScrolledWindow(self, -1)
|
|
p1.Bind(wx.EVT_SIZE, self.OnSize)
|
|
|
|
self._framesListCtrl = wx.ListCtrl(p1, -1, pos=wx.DefaultPosition, size=(250,150), style=wx.LC_REPORT)
|
|
sizer.Add(self._framesListCtrl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1)
|
|
self._framesListCtrl.InsertColumn(0, "Frame")
|
|
self._framesListCtrl.SetColumnWidth(0, 250)
|
|
self._framesListCtrl.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnListRightClick)
|
|
self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.ListItemSelected, self._framesListCtrl)
|
|
self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.ListItemDeselected, self._framesListCtrl)
|
|
|
|
sizer2 = wx.BoxSizer(wx.VERTICAL)
|
|
self._p2 = p2 = wx.ScrolledWindow(self, -1)
|
|
p2.Bind(wx.EVT_SIZE, self.OnSize)
|
|
|
|
self._treeCtrl = wx.gizmos.TreeListCtrl(p2, -1, size=(530,250), style=wx.TR_DEFAULT_STYLE| wx.TR_FULL_ROW_HIGHLIGHT)
|
|
self._treeCtrl.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnRightClick)
|
|
sizer2.Add(self._framesListCtrl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1)
|
|
tree = self._treeCtrl
|
|
tree.AddColumn("Thing")
|
|
tree.AddColumn("Value")
|
|
tree.SetMainColumn(0) # the one with the tree in it...
|
|
tree.SetColumnWidth(0, 175)
|
|
tree.SetColumnWidth(1, 355)
|
|
self._root = tree.AddRoot("Frame")
|
|
tree.SetItemText(self._root, "", 1)
|
|
|
|
self.SetMinimumPaneSize(20)
|
|
self.SplitVertically(p1, p2, 250)
|
|
self.currentItem = None
|
|
self.Layout()
|
|
|
|
def OnRightClick(self, event):
|
|
#Refactor this...
|
|
self._introspectItem = event.GetItem()
|
|
self._parentChain = self.GetItemChain(event.GetItem())
|
|
watchOnly = len(self._parentChain) < 1
|
|
if not _WATCHES_ON and watchOnly:
|
|
return
|
|
menu = wx.Menu()
|
|
if not watchOnly:
|
|
if not hasattr(self, "introspectID"):
|
|
self.introspectID = wx.NewId()
|
|
self.Bind(wx.EVT_MENU, self.OnIntrospect, id=self.introspectID)
|
|
item = wx.MenuItem(menu, self.introspectID, "Attempt Introspection")
|
|
menu.AppendItem(item)
|
|
menu.AppendSeparator()
|
|
if _WATCHES_ON:
|
|
if not hasattr(self, "watchID"):
|
|
self.watchID = wx.NewId()
|
|
self.Bind(wx.EVT_MENU, self.OnWatch, id=self.watchID)
|
|
item = wx.MenuItem(menu, self.watchID, "Create a Watch")
|
|
menu.AppendItem(item)
|
|
menu.AppendSeparator()
|
|
if not watchOnly:
|
|
if not hasattr(self, "viewID"):
|
|
self.viewID = wx.NewId()
|
|
self.Bind(wx.EVT_MENU, self.OnView, id=self.viewID)
|
|
item = wx.MenuItem(menu, self.viewID, "View in Dialog")
|
|
menu.AppendItem(item)
|
|
offset = wx.Point(x=0, y=20)
|
|
menuSpot = event.GetPoint() + offset
|
|
self._treeCtrl.PopupMenu(menu, menuSpot)
|
|
menu.Destroy()
|
|
self._parentChain = None
|
|
self._introspectItem = None
|
|
|
|
def GetItemChain(self, item):
|
|
parentChain = []
|
|
if item:
|
|
if _VERBOSE: print 'Exploding: %s' % self._treeCtrl.GetItemText(item, 0)
|
|
while item != self._root:
|
|
text = self._treeCtrl.GetItemText(item, 0)
|
|
if _VERBOSE: print "Appending ", text
|
|
parentChain.append(text)
|
|
item = self._treeCtrl.GetItemParent(item)
|
|
parentChain.reverse()
|
|
return parentChain
|
|
|
|
def OnView(self, event):
|
|
title = self._treeCtrl.GetItemText(self._introspectItem,0)
|
|
value = self._treeCtrl.GetItemText(self._introspectItem,1)
|
|
dlg = wx.lib.dialogs.ScrolledMessageDialog(self, value, title, style=wx.DD_DEFAULT_STYLE | wx.RESIZE_BORDER)
|
|
dlg.Show()
|
|
|
|
def OnWatch(self, event):
|
|
try:
|
|
if hasattr(self, '_parentChain'):
|
|
wd = WatchDialog(wx.GetApp().GetTopWindow(), "Add a Watch", self._parentChain)
|
|
else:
|
|
wd = WatchDialog(wx.GetApp().GetTopWindow(), "Add a Watch", None)
|
|
if wd.ShowModal() == wx.ID_OK:
|
|
name, text, send_frame, run_once = wd.GetSettings()
|
|
if send_frame:
|
|
frameNode = self._stack[int(self.currentItem)]
|
|
message = frameNode.getAttribute("message")
|
|
else:
|
|
message = ""
|
|
binType = self._ui._callback._debuggerServer.add_watch(name, text, message, run_once)
|
|
xmldoc = bz2.decompress(binType.data)
|
|
domDoc = parseString(xmldoc)
|
|
nodeList = domDoc.getElementsByTagName('watch')
|
|
if len(nodeList) == 1:
|
|
watchValue = nodeList.item(0).getAttribute("message")
|
|
except:
|
|
tp, val, tb = sys.exc_info()
|
|
traceback.print_exception(tp, val, tb)
|
|
|
|
def OnIntrospect(self, event):
|
|
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
|
|
|
|
try:
|
|
list = self._framesListCtrl
|
|
frameNode = self._stack[int(self.currentItem)]
|
|
message = frameNode.getAttribute("message")
|
|
binType = self._ui._callback._debuggerServer.attempt_introspection(message, self._parentChain)
|
|
xmldoc = bz2.decompress(binType.data)
|
|
|
|
domDoc = parseString(xmldoc)
|
|
nodeList = domDoc.getElementsByTagName('replacement')
|
|
replacementNode = nodeList.item(0)
|
|
if len(replacementNode.childNodes):
|
|
thingToWalk = replacementNode.childNodes.item(0)
|
|
tree = self._treeCtrl
|
|
parent = tree.GetItemParent(self._introspectItem)
|
|
treeNode = self.AppendSubTreeFromNode(thingToWalk, thingToWalk.getAttribute('name'), parent, insertBefore=self._introspectItem)
|
|
tree.Delete(self._introspectItem)
|
|
except:
|
|
tp,val,tb = sys.exc_info()
|
|
traceback.print_exception(tp, val, tb)
|
|
|
|
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
|
|
|
|
def OnSize(self, event):
|
|
self._treeCtrl.SetSize(self._p2.GetSize())
|
|
w,h = self._p1.GetClientSizeTuple()
|
|
self._framesListCtrl.SetDimensions(0, 0, w, h)
|
|
|
|
def ClearWhileRunning(self):
|
|
list = self._framesListCtrl
|
|
list.DeleteAllItems()
|
|
tree = self._treeCtrl
|
|
tree.Hide()
|
|
|
|
def OnListRightClick(self, event):
|
|
if not hasattr(self, "syncFrameID"):
|
|
self.syncFrameID = wx.NewId()
|
|
self.Bind(wx.EVT_MENU, self.OnSyncFrame, id=self.syncFrameID)
|
|
menu = wx.Menu()
|
|
item = wx.MenuItem(menu, self.syncFrameID, "Goto Source Line")
|
|
menu.AppendItem(item)
|
|
self.PopupMenu(menu, event.GetPosition())
|
|
menu.Destroy()
|
|
|
|
def OnSyncFrame(self, event):
|
|
list = self._framesListCtrl
|
|
frameNode = self._stack[int(self.currentItem)]
|
|
file = frameNode.getAttribute("file")
|
|
line = frameNode.getAttribute("line")
|
|
self._ui.SynchCurrentLine( file, int(line) )
|
|
|
|
def LoadFramesListXML(self, framesXML):
|
|
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
|
|
try:
|
|
domDoc = parseString(framesXML)
|
|
list = self._framesListCtrl
|
|
list.DeleteAllItems()
|
|
self._stack = []
|
|
nodeList = domDoc.getElementsByTagName('frame')
|
|
frame_count = -1
|
|
for index in range(0, nodeList.length):
|
|
frameNode = nodeList.item(index)
|
|
message = frameNode.getAttribute("message")
|
|
list.InsertStringItem(index, message)
|
|
self._stack.append(frameNode)
|
|
frame_count += 1
|
|
list.Select(frame_count)
|
|
self._p1.FitInside()
|
|
frameNode = nodeList.item(index)
|
|
file = frameNode.getAttribute("file")
|
|
line = frameNode.getAttribute("line")
|
|
self._ui.SynchCurrentLine( file, int(line) )
|
|
except:
|
|
tp,val,tb=sys.exc_info()
|
|
traceback.print_exception(tp, val, tb)
|
|
|
|
wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
|
|
|
|
def ListItemDeselected(self, event):
|
|
pass
|
|
|
|
def ListItemSelected(self, event):
|
|
self.currentItem = event.m_itemIndex
|
|
frameNode = self._stack[int(self.currentItem)]
|
|
self.PopulateTreeFromFrameNode(frameNode)
|
|
# Temporarily doing this to test out automatically swicting to source line.
|
|
self.OnSyncFrame(None)
|
|
|
|
def PopulateTreeFromFrameNode(self, frameNode):
|
|
tree = self._treeCtrl
|
|
tree.Show(True)
|
|
root = self._root
|
|
tree.DeleteChildren(root)
|
|
children = frameNode.childNodes
|
|
firstChild = None
|
|
for index in range(0, children.length):
|
|
subNode = children.item(index)
|
|
treeNode = self.AppendSubTreeFromNode(subNode, subNode.getAttribute('name'), root)
|
|
if not firstChild:
|
|
firstChild = treeNode
|
|
tree.Expand(root)
|
|
tree.Expand(firstChild)
|
|
self._p2.FitInside()
|
|
|
|
def AppendSubTreeFromNode(self, node, name, parent, insertBefore=None):
|
|
tree = self._treeCtrl
|
|
if insertBefore != None:
|
|
treeNode = tree.InsertItem(parent, insertBefore, name)
|
|
else:
|
|
treeNode = tree.AppendItem(parent, name)
|
|
children = node.childNodes
|
|
if children.length == 0:
|
|
tree.SetItemText(treeNode, self.StripOuterSingleQuotes(node.getAttribute("value")), 1)
|
|
for index in range(0, children.length):
|
|
subNode = children.item(index)
|
|
if self.HasChildren(subNode):
|
|
self.AppendSubTreeFromNode(subNode, subNode.getAttribute("name"), treeNode)
|
|
else:
|
|
name = subNode.getAttribute("name")
|
|
value = self.StripOuterSingleQuotes(subNode.getAttribute("value"))
|
|
n = tree.AppendItem(treeNode, name)
|
|
tree.SetItemText(n, value, 1)
|
|
return treeNode
|
|
|
|
def StripOuterSingleQuotes(self, string):
|
|
if string.startswith("'") and string.endswith("'"):
|
|
return string[1:-1]
|
|
elif type(string) == types.UnicodeType:
|
|
return string[1:-1]
|
|
else:
|
|
return string
|
|
|
|
def HasChildren(self, node):
|
|
try:
|
|
return node.childNodes.length > 0
|
|
except:
|
|
tp,val,tb=sys.exc_info()
|
|
return False
|
|
|
|
class DebuggerView(Service.ServiceView):
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Overridden methods
|
|
#----------------------------------------------------------------------------
|
|
|
|
def __init__(self, service):
|
|
Service.ServiceView.__init__(self, service)
|
|
|
|
def _CreateControl(self, parent, id):
|
|
return None
|
|
|
|
#------------------------------------------------------------------------------
|
|
# Event handling
|
|
#-----------------------------------------------------------------------------
|
|
|
|
def OnToolClicked(self, event):
|
|
self.GetFrame().ProcessEvent(event)
|
|
|
|
#------------------------------------------------------------------------------
|
|
# Class methods
|
|
#-----------------------------------------------------------------------------
|
|
|
|
class Interaction:
|
|
def __init__(self, message, framesXML, info=None, quit=False):
|
|
self._framesXML = framesXML
|
|
self._message = message
|
|
self._info = info
|
|
self._quit = quit
|
|
|
|
def getFramesXML(self):
|
|
return self._framesXML
|
|
|
|
def getMessage(self):
|
|
return self._message
|
|
|
|
def getInfo(self):
|
|
return self._info
|
|
|
|
def getQuit(self):
|
|
return self._quit
|
|
|
|
class AGXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
|
|
def __init__(self, address, logRequests=0):
|
|
SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, address, logRequests=logRequests)
|
|
|
|
class RequestHandlerThread(threading.Thread):
|
|
def __init__(self, queue, address):
|
|
threading.Thread.__init__(self)
|
|
self._keepGoing = True
|
|
self._queue = queue
|
|
self._address = address
|
|
self._server = AGXMLRPCServer(self._address,logRequests=0)
|
|
self._server.register_function(self.interaction)
|
|
self._server.register_function(self.quit)
|
|
self._server.register_function(self.dummyOperation)
|
|
if _VERBOSE: print "RequestHandlerThread on fileno %s" % str(self._server.fileno())
|
|
|
|
def run(self):
|
|
while self._keepGoing:
|
|
try:
|
|
self._server.handle_request()
|
|
except:
|
|
tp, val, tb = sys.exc_info()
|
|
traceback.print_exception(tp, val, tb)
|
|
self._keepGoing = False
|
|
if _VERBOSE: print "Exiting Request Handler Thread."
|
|
|
|
def interaction(self, message, frameXML, info):
|
|
if _VERBOSE: print "In RequestHandlerThread.interaction -- adding to queue"
|
|
interaction = Interaction(message, frameXML, info)
|
|
self._queue.put(interaction)
|
|
return ""
|
|
|
|
def quit(self):
|
|
interaction = Interaction(None, None, info=None, quit=True)
|
|
self._queue.put(interaction)
|
|
return ""
|
|
|
|
def dummyOperation(self):
|
|
return ""
|
|
|
|
def AskToStop(self):
|
|
self._keepGoing = False
|
|
if type(self._server) is not types.NoneType:
|
|
try:
|
|
# This is a really ugly way to make sure this thread isn't blocked in
|
|
# handle_request.
|
|
url = 'http://' + self._address[0] + ':' + str(self._address[1]) + '/'
|
|
tempServer = xmlrpclib.ServerProxy(url, allow_none=1)
|
|
tempServer.dummyOperation()
|
|
except:
|
|
tp, val, tb = sys.exc_info()
|
|
traceback.print_exception(tp, val, tb)
|
|
self._server.server_close()
|
|
|
|
|
|
class RequestBreakThread(threading.Thread):
|
|
def __init__(self, server, interrupt=False, pushBreakpoints=False, breakDict=None, kill=False):
|
|
threading.Thread.__init__(self)
|
|
self._server = server
|
|
|
|
self._interrupt = interrupt
|
|
self._pushBreakpoints = pushBreakpoints
|
|
self._breakDict = breakDict
|
|
self._kill = kill
|
|
|
|
def run(self):
|
|
try:
|
|
if _VERBOSE: print "RequestBreakThread, before call"
|
|
if self._interrupt:
|
|
self._server.break_requested()
|
|
if self._pushBreakpoints:
|
|
self._server.update_breakpoints(xmlrpclib.Binary(pickle.dumps(self._breakDict)))
|
|
if self._kill:
|
|
try:
|
|
self._server.die()
|
|
except:
|
|
pass
|
|
if _VERBOSE: print "RequestBreakThread, after call"
|
|
except:
|
|
tp,val,tb = sys.exc_info()
|
|
traceback.print_exception(tp, val, tb)
|
|
|
|
class DebuggerOperationThread(threading.Thread):
|
|
def __init__(self, function):
|
|
threading.Thread.__init__(self)
|
|
self._function = function
|
|
|
|
def run(self):
|
|
if _VERBOSE: print "In DOT, before call"
|
|
try:
|
|
self._function()
|
|
except:
|
|
tp,val,tb = sys.exc_info()
|
|
traceback.print_exception(tp, val, tb)
|
|
if _VERBOSE: print "In DOT, after call"
|
|
|
|
class DebuggerCallback:
|
|
|
|
def __init__(self, host, port, debugger_url, break_url, debuggerUI):
|
|
if _VERBOSE: print "+++++++ Creating server on port, ", str(port)
|
|
|
|
self._queue = Queue.Queue(50)
|
|
self._host = host
|
|
self._port = int(port)
|
|
threading._VERBOSE = _VERBOSE
|
|
self._serverHandlerThread = RequestHandlerThread(self._queue, (self._host, self._port))
|
|
|
|
self._debugger_url = debugger_url
|
|
self._debuggerServer = None
|
|
self._waiting = False
|
|
self._service = wx.GetApp().GetService(DebuggerService)
|
|
self._debuggerUI = debuggerUI
|
|
self._break_url = break_url
|
|
self._breakServer = None
|
|
self._firstInteraction = True
|
|
self._pendingBreak = False
|
|
|
|
def start(self):
|
|
self._serverHandlerThread.start()
|
|
|
|
def ServerClose(self):
|
|
rbt = RequestBreakThread(self._breakServer, kill=True)
|
|
rbt.start()
|
|
self.setWaiting(False)
|
|
if self._serverHandlerThread:
|
|
self._serverHandlerThread.AskToStop()
|
|
self._serverHandlerThread = None
|
|
|
|
def BreakExecution(self):
|
|
rbt = RequestBreakThread(self._breakServer, interrupt=True)
|
|
rbt.start()
|
|
|
|
def SingleStep(self):
|
|
self._debuggerUI.DisableWhileDebuggerRunning()
|
|
#dot = DebuggerOperationThread(self._debuggerServer.set_step)
|
|
#dot.start()
|
|
self._debuggerServer.set_step() # Figure out where to set allowNone
|
|
self.waitForRPC()
|
|
|
|
def Next(self):
|
|
self._debuggerUI.DisableWhileDebuggerRunning()
|
|
#dot = DebuggerOperationThread(self._debuggerServer.set_next)
|
|
#dot.start()
|
|
self._debuggerServer.set_next()
|
|
self.waitForRPC()
|
|
|
|
def Continue(self):
|
|
self._debuggerUI.DisableWhileDebuggerRunning()
|
|
#dot = DebuggerOperationThread(self._debuggerServer.set_continue)
|
|
#dot.start()
|
|
self._debuggerServer.set_continue()
|
|
self.waitForRPC()
|
|
|
|
def Return(self):
|
|
self._debuggerUI.DisableWhileDebuggerRunning()
|
|
#dot = DebuggerOperationThread(self._debuggerServer.set_return)
|
|
#dot.start()
|
|
self._debuggerServer.set_return()
|
|
self.waitForRPC()
|
|
|
|
def setWaiting(self, value):
|
|
self._waiting = value
|
|
|
|
def getWaiting(self):
|
|
return self._waiting
|
|
|
|
def readQueue(self):
|
|
if self._queue.qsize():
|
|
try:
|
|
item = self._queue.get_nowait()
|
|
if item.getQuit():
|
|
self.interaction(None, None, None, True)
|
|
else:
|
|
data = bz2.decompress(item.getFramesXML().data)
|
|
self.interaction(item.getMessage().data, data, item.getInfo(), False)
|
|
except Queue.Empty:
|
|
pass
|
|
|
|
def pushBreakpoints(self):
|
|
rbt = RequestBreakThread(self._breakServer, pushBreakpoints=True, breakDict=self._service.GetMasterBreakpointDict())
|
|
rbt.start()
|
|
|
|
|
|
def waitForRPC(self):
|
|
self.setWaiting(True)
|
|
while self.getWaiting():
|
|
try:
|
|
self.readQueue()
|
|
import time
|
|
time.sleep(0.02)
|
|
except:
|
|
tp, val, tb = sys.exc_info()
|
|
traceback.print_exception(tp, val, tb)
|
|
wx.GetApp().Yield(True)
|
|
if _VERBOSE: print "Exiting waitForRPC."
|
|
|
|
def interaction(self, message, frameXML, info, quit):
|
|
|
|
#This method should be hit as the debugger starts.
|
|
if self._firstInteraction:
|
|
self._firstInteraction = False
|
|
self._debuggerServer = xmlrpclib.ServerProxy(self._debugger_url, allow_none=1)
|
|
self._breakServer = xmlrpclib.ServerProxy(self._break_url, allow_none=1)
|
|
self.pushBreakpoints()
|
|
self.setWaiting(False)
|
|
if _VERBOSE: print "+"*40
|
|
if(quit):
|
|
self._debuggerUI.StopExecution(None)
|
|
return ""
|
|
if(info != ""):
|
|
if _VERBOSE: print "Hit interaction with exception"
|
|
#self._debuggerUI.StopExecution(None)
|
|
#self._debuggerUI.SetStatusText("Got exception: " + str(info))
|
|
self._debuggerUI.SwitchToOutputTab()
|
|
else:
|
|
if _VERBOSE: print "Hit interaction no exception"
|
|
self._debuggerUI.SetStatusText(message)
|
|
self._debuggerUI.LoadFramesListXML(frameXML)
|
|
self._debuggerUI.EnableWhileDebuggerStopped()
|
|
if _VERBOSE: print "+"*40
|
|
|
|
class DebuggerService(Service.Service):
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Constants
|
|
#----------------------------------------------------------------------------
|
|
TOGGLE_BREAKPOINT_ID = wx.NewId()
|
|
CLEAR_ALL_BREAKPOINTS = wx.NewId()
|
|
RUN_ID = wx.NewId()
|
|
DEBUG_ID = wx.NewId()
|
|
DEBUG_WEBSERVER_ID = wx.NewId()
|
|
|
|
def ComparePaths(first, second):
|
|
one = DebuggerService.ExpandPath(first)
|
|
two = DebuggerService.ExpandPath(second)
|
|
if _WINDOWS:
|
|
return one.lower() == two.lower()
|
|
else:
|
|
return one == two
|
|
ComparePaths = staticmethod(ComparePaths)
|
|
|
|
# Make sure we're using an expanded path on windows.
|
|
def ExpandPath(path):
|
|
if _WINDOWS:
|
|
try:
|
|
return win32api.GetLongPathName(path)
|
|
except:
|
|
print "Cannot get long path for %s" % path
|
|
|
|
return path
|
|
|
|
ExpandPath = staticmethod(ExpandPath)
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Overridden methods
|
|
#----------------------------------------------------------------------------
|
|
|
|
def __init__(self, serviceName, embeddedWindowLocation = wx.lib.pydocview.EMBEDDED_WINDOW_LEFT):
|
|
Service.Service.__init__(self, serviceName, embeddedWindowLocation)
|
|
self.BREAKPOINT_DICT_STRING = "MasterBreakpointDict"
|
|
config = wx.ConfigBase_Get()
|
|
pickledbps = config.Read(self.BREAKPOINT_DICT_STRING)
|
|
if pickledbps:
|
|
try:
|
|
self._masterBPDict = pickle.loads(pickledbps.encode('ascii'))
|
|
except:
|
|
tp, val, tb = sys.exc_info()
|
|
traceback.print_exception(tp,val,tb)
|
|
self._masterBPDict = {}
|
|
else:
|
|
self._masterBPDict = {}
|
|
|
|
def OnCloseFrame(self, event):
|
|
# IS THIS THE RIGHT PLACE?
|
|
try:
|
|
config = wx.ConfigBase_Get()
|
|
config.Write(self.BREAKPOINT_DICT_STRING, pickle.dumps(self._masterBPDict))
|
|
except:
|
|
tp,val,tb = sys.exc_info()
|
|
traceback.print_exception(tp, val, tb)
|
|
return True
|
|
|
|
def _CreateView(self):
|
|
return DebuggerView(self)
|
|
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Service specific methods
|
|
#----------------------------------------------------------------------------
|
|
|
|
def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None):
|
|
#Service.Service.InstallControls(self, frame, menuBar, toolBar, statusBar, document)
|
|
|
|
config = wx.ConfigBase_Get()
|
|
|
|
debuggerMenu = wx.Menu()
|
|
if not menuBar.FindItemById(DebuggerService.CLEAR_ALL_BREAKPOINTS):
|
|
|
|
debuggerMenu.Append(DebuggerService.RUN_ID, _("&Run...\tCtrl+R"), _("Runs a file"))
|
|
wx.EVT_MENU(frame, DebuggerService.RUN_ID, frame.ProcessEvent)
|
|
wx.EVT_UPDATE_UI(frame, DebuggerService.RUN_ID, frame.ProcessUpdateUIEvent)
|
|
|
|
debuggerMenu.Append(DebuggerService.DEBUG_ID, _("&Debug...\tCtrl+D"), _("Debugs a file"))
|
|
wx.EVT_MENU(frame, DebuggerService.DEBUG_ID, frame.ProcessEvent)
|
|
wx.EVT_UPDATE_UI(frame, DebuggerService.DEBUG_ID, frame.ProcessUpdateUIEvent)
|
|
|
|
if not ACTIVEGRID_BASE_IDE:
|
|
debuggerMenu.AppendSeparator()
|
|
debuggerMenu.Append(DebuggerService.DEBUG_WEBSERVER_ID, _("Debug Internal Web Server"), _("Debugs the internal webservier"))
|
|
wx.EVT_MENU(frame, DebuggerService.DEBUG_WEBSERVER_ID, frame.ProcessEvent)
|
|
wx.EVT_UPDATE_UI(frame, DebuggerService.DEBUG_WEBSERVER_ID, frame.ProcessUpdateUIEvent)
|
|
|
|
debuggerMenu.AppendSeparator()
|
|
|
|
debuggerMenu.Append(DebuggerService.TOGGLE_BREAKPOINT_ID, _("&Toggle Breakpoint...\tCtrl+B"), _("Toggle a breakpoint"))
|
|
wx.EVT_MENU(frame, DebuggerService.TOGGLE_BREAKPOINT_ID, self.ProcessEvent)
|
|
wx.EVT_UPDATE_UI(frame, DebuggerService.TOGGLE_BREAKPOINT_ID, self.ProcessUpdateUIEvent)
|
|
|
|
debuggerMenu.Append(DebuggerService.CLEAR_ALL_BREAKPOINTS, _("&Clear All Breakpoints"), _("Clear All Breakpoints"))
|
|
wx.EVT_MENU(frame, DebuggerService.CLEAR_ALL_BREAKPOINTS, self.ProcessEvent)
|
|
wx.EVT_UPDATE_UI(frame, DebuggerService.CLEAR_ALL_BREAKPOINTS, self.ProcessUpdateUIEvent)
|
|
|
|
|
|
viewMenuIndex = menuBar.FindMenu(_("&Project"))
|
|
menuBar.Insert(viewMenuIndex + 1, debuggerMenu, _("&Run"))
|
|
|
|
return True
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Event Processing Methods
|
|
#----------------------------------------------------------------------------
|
|
|
|
def ProcessEventBeforeWindows(self, event):
|
|
return False
|
|
|
|
|
|
def ProcessEvent(self, event):
|
|
if Service.Service.ProcessEvent(self, event):
|
|
return True
|
|
|
|
an_id = event.GetId()
|
|
if an_id == DebuggerService.TOGGLE_BREAKPOINT_ID:
|
|
self.OnToggleBreakpoint(event)
|
|
return True
|
|
elif an_id == DebuggerService.CLEAR_ALL_BREAKPOINTS:
|
|
self.ClearAllBreakpoints()
|
|
return True
|
|
elif an_id == DebuggerService.RUN_ID:
|
|
self.OnRunProject(event)
|
|
return True
|
|
elif an_id == DebuggerService.DEBUG_ID:
|
|
self.OnDebugProject(event)
|
|
return True
|
|
elif an_id == DebuggerService.DEBUG_WEBSERVER_ID:
|
|
self.OnDebugWebServer(event)
|
|
return True
|
|
return False
|
|
|
|
def ProcessUpdateUIEvent(self, event):
|
|
if Service.Service.ProcessUpdateUIEvent(self, event):
|
|
return True
|
|
|
|
an_id = event.GetId()
|
|
if an_id == DebuggerService.TOGGLE_BREAKPOINT_ID:
|
|
currentView = self.GetDocumentManager().GetCurrentView()
|
|
event.Enable(isinstance(currentView, PythonEditor.PythonView))
|
|
return True
|
|
elif an_id == DebuggerService.CLEAR_ALL_BREAKPOINTS:
|
|
event.Enable(self.HasBreakpointsSet())
|
|
return True
|
|
elif (an_id == DebuggerService.RUN_ID
|
|
or an_id == DebuggerService.DEBUG_ID):
|
|
event.Enable(self.HasAnyFiles())
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Class Methods
|
|
#----------------------------------------------------------------------------
|
|
|
|
def OnDebugProject(self, event):
|
|
if _WINDOWS and not _PYWIN32_INSTALLED:
|
|
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."))
|
|
return
|
|
if not Executor.GetPythonExecutablePath():
|
|
return
|
|
if DebugCommandUI.DebuggerRunning():
|
|
wx.MessageBox(_("A debugger is already running. Please shut down the other debugger first."), _("Debugger Running"))
|
|
return
|
|
self.ShowWindow(True)
|
|
projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
|
|
project = projectService.GetView().GetDocument()
|
|
try:
|
|
dlg = CommandPropertiesDialog(self.GetView().GetFrame(), 'Debug Python File', projectService, None, pythonOnly=True, okButtonName="Debug", debugging=True)
|
|
except:
|
|
return
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
fileToDebug, initialArgs, startIn, isPython, environment = dlg.GetSettings()
|
|
dlg.Destroy()
|
|
else:
|
|
dlg.Destroy()
|
|
return
|
|
self.PromptToSaveFiles()
|
|
|
|
shortFile = os.path.basename(fileToDebug)
|
|
fileToDebug = DebuggerService.ExpandPath(fileToDebug)
|
|
try:
|
|
page = DebugCommandUI(Service.ServiceView.bottomTab, -1, str(fileToDebug), self)
|
|
count = Service.ServiceView.bottomTab.GetPageCount()
|
|
Service.ServiceView.bottomTab.AddPage(page, _("Debugging: ") + shortFile)
|
|
Service.ServiceView.bottomTab.SetSelection(count)
|
|
page.Execute(initialArgs, startIn, environment)
|
|
except:
|
|
pass
|
|
|
|
def OnDebugWebServer(self, event):
|
|
import WebServerService
|
|
wsService = wx.GetApp().GetService(WebServerService.WebServerService)
|
|
fileName, args = wsService.StopAndPrepareToDebug()
|
|
try:
|
|
page = DebugCommandUI(Service.ServiceView.bottomTab, -1, str(fileName), self)
|
|
count = Service.ServiceView.bottomTab.GetPageCount()
|
|
Service.ServiceView.bottomTab.AddPage(page, _("Debugging: Internal WebServer"))
|
|
Service.ServiceView.bottomTab.SetSelection(count)
|
|
page.Execute(args, startIn=os.getcwd(), environment=os.environ)
|
|
except:
|
|
pass
|
|
|
|
|
|
def HasAnyFiles(self):
|
|
docs = wx.GetApp().GetDocumentManager().GetDocuments()
|
|
return len(docs) > 0
|
|
|
|
def PromptToSaveFiles(self, running=True):
|
|
filesModified = False
|
|
docs = wx.GetApp().GetDocumentManager().GetDocuments()
|
|
for doc in docs:
|
|
if doc.IsModified():
|
|
filesModified = True
|
|
break
|
|
if filesModified:
|
|
frame = self.GetView().GetFrame()
|
|
if running:
|
|
yesNoMsg = wx.MessageDialog(frame,
|
|
_("Files have been modified.\nWould you like to save all files before running?"),
|
|
_("Run"),
|
|
wx.YES_NO|wx.ICON_QUESTION
|
|
)
|
|
else:
|
|
yesNoMsg = wx.MessageDialog(frame,
|
|
_("Files have been modified.\nWould you like to save all files before debugging?"),
|
|
_("Debug"),
|
|
wx.YES_NO|wx.ICON_QUESTION
|
|
)
|
|
if yesNoMsg.ShowModal() == wx.ID_YES:
|
|
docs = wx.GetApp().GetDocumentManager().GetDocuments()
|
|
for doc in docs:
|
|
doc.Save()
|
|
|
|
def OnExit(self):
|
|
DebugCommandUI.ShutdownAllDebuggers()
|
|
|
|
def OnRunProject(self, event):
|
|
if _WINDOWS and not _PYWIN32_INSTALLED:
|
|
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."))
|
|
return
|
|
if not Executor.GetPythonExecutablePath():
|
|
return
|
|
projectService = wx.GetApp().GetService(ProjectEditor.ProjectService)
|
|
project = projectService.GetView().GetDocument()
|
|
try:
|
|
dlg = CommandPropertiesDialog(self.GetView().GetFrame(), 'Run', projectService, None)
|
|
except:
|
|
return
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
fileToRun, initialArgs, startIn, isPython, environment = dlg.GetSettings()
|
|
|
|
|
|
dlg.Destroy()
|
|
else:
|
|
dlg.Destroy()
|
|
return
|
|
self.PromptToSaveFiles()
|
|
# This will need to change when we can run more than .py and .bpel files.
|
|
if not isPython:
|
|
projectService.RunProcessModel(fileToRun)
|
|
return
|
|
|
|
self.ShowWindow(True)
|
|
shortFile = os.path.basename(fileToRun)
|
|
page = RunCommandUI(Service.ServiceView.bottomTab, -1, str(fileToRun))
|
|
count = Service.ServiceView.bottomTab.GetPageCount()
|
|
Service.ServiceView.bottomTab.AddPage(page, "Running: " + shortFile)
|
|
Service.ServiceView.bottomTab.SetSelection(count)
|
|
page.Execute(initialArgs, startIn, environment)
|
|
|
|
def OnToggleBreakpoint(self, event, line=-1, fileName=None):
|
|
if not fileName:
|
|
view = wx.GetApp().GetDocumentManager().GetCurrentView()
|
|
# Test to make sure we aren't the project view.
|
|
if not hasattr(view, 'MarkerExists'):
|
|
return
|
|
fileName = wx.GetApp().GetDocumentManager().GetCurrentDocument().GetFilename()
|
|
if line < 0:
|
|
line = view.GetCtrl().GetCurrentLine()
|
|
if self.BreakpointSet(fileName, line + 1):
|
|
self.ClearBreak(fileName, line + 1)
|
|
else:
|
|
self.SetBreak(fileName, line + 1)
|
|
# Now refresh all the markers icons in all the open views.
|
|
self.ClearAllBreakpointMarkers()
|
|
self.SetAllBreakpointMarkers()
|
|
|
|
def SilentToggleBreakpoint(self, fileName, line):
|
|
found = False
|
|
for lineNumber in self.GetBreakpointList(fileName):
|
|
if int(lineNumber) == int(line):
|
|
found = True
|
|
break
|
|
if found:
|
|
self.SetBreak(fileName, line)
|
|
else:
|
|
self.ClearBreak(fileName, line)
|
|
|
|
def SetBreak(self, fileName, line):
|
|
expandedName = DebuggerService.ExpandPath(fileName)
|
|
if not self._masterBPDict.has_key(expandedName):
|
|
self._masterBPDict[expandedName] = [line]
|
|
else:
|
|
self._masterBPDict[expandedName] += [line]
|
|
# If we're already debugging, pass this bp off to the DebuggerCallback
|
|
self.NotifyDebuggersOfBreakpointChange()
|
|
|
|
def NotifyDebuggersOfBreakpointChange(self):
|
|
DebugCommandUI.NotifyDebuggersOfBreakpointChange()
|
|
|
|
def GetBreakpointList(self, fileName):
|
|
expandedName = DebuggerService.ExpandPath(fileName)
|
|
if not self._masterBPDict.has_key(expandedName):
|
|
return []
|
|
else:
|
|
return self._masterBPDict[expandedName]
|
|
|
|
def BreakpointSet(self, fileName, line):
|
|
expandedName = DebuggerService.ExpandPath(fileName)
|
|
if not self._masterBPDict.has_key(expandedName):
|
|
return False
|
|
else:
|
|
newList = []
|
|
for number in self._masterBPDict[expandedName]:
|
|
if(int(number) == int(line)):
|
|
return True
|
|
return False
|
|
|
|
def ClearBreak(self, fileName, line):
|
|
expandedName = DebuggerService.ExpandPath(fileName)
|
|
if not self._masterBPDict.has_key(expandedName):
|
|
print "In ClearBreak: no key"
|
|
return
|
|
else:
|
|
newList = []
|
|
for number in self._masterBPDict[expandedName]:
|
|
if(int(number) != int(line)):
|
|
newList.append(number)
|
|
self._masterBPDict[expandedName] = newList
|
|
self.NotifyDebuggersOfBreakpointChange()
|
|
|
|
def HasBreakpointsSet(self):
|
|
for key, value in self._masterBPDict.items():
|
|
if len(value) > 0:
|
|
return True
|
|
return False
|
|
|
|
def ClearAllBreakpoints(self):
|
|
self._masterBPDict = {}
|
|
self.NotifyDebuggersOfBreakpointChange()
|
|
self.ClearAllBreakpointMarkers()
|
|
|
|
def ClearAllBreakpointMarkers(self):
|
|
openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
|
|
for openDoc in openDocs:
|
|
if(isinstance(openDoc.GetFirstView(), CodeEditor.CodeView)):
|
|
openDoc.GetFirstView().MarkerDeleteAll(CodeEditor.CodeCtrl.BREAKPOINT_MARKER_NUM)
|
|
|
|
def GetMasterBreakpointDict(self):
|
|
return self._masterBPDict
|
|
|
|
def SetAllBreakpointMarkers(self):
|
|
openDocs = wx.GetApp().GetDocumentManager().GetDocuments()
|
|
for openDoc in openDocs:
|
|
if(isinstance(openDoc.GetFirstView(), CodeEditor.CodeView)):
|
|
self.SetCurrentBreakpointMarkers(openDoc.GetFirstView())
|
|
|
|
def SetCurrentBreakpointMarkers(self, view):
|
|
if isinstance(view, CodeEditor.CodeView) and hasattr(view, 'GetDocument'):
|
|
view.MarkerDeleteAll(CodeEditor.CodeCtrl.BREAKPOINT_MARKER_NUM)
|
|
for linenum in self.GetBreakpointList(view.GetDocument().GetFilename()):
|
|
view.MarkerAdd(lineNum=int(linenum) - 1, marker_index=CodeEditor.CodeCtrl.BREAKPOINT_MARKER_NUM)
|
|
|
|
class DebuggerOptionsPanel(wx.Panel):
|
|
|
|
|
|
def __init__(self, parent, id):
|
|
wx.Panel.__init__(self, parent, id)
|
|
SPACE = 10
|
|
config = wx.ConfigBase_Get()
|
|
localHostStaticText = wx.StaticText(self, -1, _("Local Host Name:"))
|
|
self._LocalHostTextCtrl = wx.TextCtrl(self, -1, config.Read("DebuggerHostName", DEFAULT_HOST), size = (150, -1))
|
|
portNumberStaticText = wx.StaticText(self, -1, _("Port Range:"))
|
|
dashStaticText = wx.StaticText(self, -1, _("through to"))
|
|
startingPort=config.ReadInt("DebuggerStartingPort", DEFAULT_PORT)
|
|
self._PortNumberTextCtrl = wx.lib.intctrl.IntCtrl(self, -1, startingPort, size = (50, -1))
|
|
self._PortNumberTextCtrl.SetMin(1)#What are real values?
|
|
self._PortNumberTextCtrl.SetMax(65514) #What are real values?
|
|
self.Bind(wx.lib.intctrl.EVT_INT, self.MinPortChange, self._PortNumberTextCtrl)
|
|
|
|
self._EndPortNumberTextCtrl = wx.lib.intctrl.IntCtrl(self, -1, startingPort + PORT_COUNT, size = (50, -1))
|
|
self._EndPortNumberTextCtrl.SetMin(22)#What are real values?
|
|
self._EndPortNumberTextCtrl.SetMax(65535)#What are real values?
|
|
self._EndPortNumberTextCtrl.Enable( False )
|
|
debuggerPanelBorderSizer = wx.BoxSizer(wx.VERTICAL)
|
|
debuggerPanelSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
|
|
debuggerPanelSizer.Add( localHostStaticText, (0,0), flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
|
debuggerPanelSizer.Add( self._LocalHostTextCtrl, (0,1), (1,3), flag=wx.EXPAND|wx.ALIGN_CENTER)
|
|
debuggerPanelSizer.Add( portNumberStaticText, (1,0), flag=wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)
|
|
debuggerPanelSizer.Add( self._PortNumberTextCtrl, (1,1), flag=wx.ALIGN_CENTER)
|
|
debuggerPanelSizer.Add( dashStaticText, (1,2), flag=wx.ALIGN_CENTER)
|
|
debuggerPanelSizer.Add( self._EndPortNumberTextCtrl, (1,3), flag=wx.ALIGN_CENTER)
|
|
FLUSH_PORTS_ID = wx.NewId()
|
|
self._flushPortsButton = wx.Button(self, FLUSH_PORTS_ID, "Reset Port List")
|
|
wx.EVT_BUTTON(parent, FLUSH_PORTS_ID, self.FlushPorts)
|
|
debuggerPanelSizer.Add(self._flushPortsButton, (2,2), (1,2), flag=wx.ALIGN_RIGHT)
|
|
|
|
debuggerPanelBorderSizer.Add(debuggerPanelSizer, 0, wx.ALL, SPACE)
|
|
self.SetSizer(debuggerPanelBorderSizer)
|
|
self.Layout()
|
|
parent.AddPage(self, _("Debugger"))
|
|
|
|
def FlushPorts(self, event):
|
|
if self._PortNumberTextCtrl.IsInBounds():
|
|
config = wx.ConfigBase_Get()
|
|
config.WriteInt("DebuggerStartingPort", self._PortNumberTextCtrl.GetValue())
|
|
DebugCommandUI.NewPortRange()
|
|
else:
|
|
wx.MessageBox(_("The starting port is not valid. Please change the value and try again.", "Invalid Starting Port Number"))
|
|
|
|
def MinPortChange(self, event):
|
|
self._EndPortNumberTextCtrl.Enable( True )
|
|
self._EndPortNumberTextCtrl.SetValue( self._PortNumberTextCtrl.GetValue() + PORT_COUNT)
|
|
self._EndPortNumberTextCtrl.Enable( False )
|
|
|
|
def OnOK(self, optionsDialog):
|
|
config = wx.ConfigBase_Get()
|
|
config.Write("DebuggerHostName", self._LocalHostTextCtrl.GetValue())
|
|
if self._PortNumberTextCtrl.IsInBounds():
|
|
config.WriteInt("DebuggerStartingPort", self._PortNumberTextCtrl.GetValue())
|
|
|
|
class CommandPropertiesDialog(wx.Dialog):
|
|
|
|
def __init__(self, parent, title, projectService, currentProjectDocument, pythonOnly=False, okButtonName="Run", debugging=False):
|
|
self._projService = projectService
|
|
self._pmext = None
|
|
self._pyext = None
|
|
for template in self._projService.GetDocumentManager().GetTemplates():
|
|
if not ACTIVEGRID_BASE_IDE and template.GetDocumentType() == ProcessModelEditor.ProcessModelDocument:
|
|
self._pmext = template.GetDefaultExtension()
|
|
if template.GetDocumentType() == PythonEditor.PythonDocument:
|
|
self._pyext = template.GetDefaultExtension()
|
|
self._pythonOnly = pythonOnly
|
|
self._currentProj = currentProjectDocument
|
|
self._projectNameList, self._projectDocumentList, selectedIndex = self.GetProjectList()
|
|
if not self._projectNameList:
|
|
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"))
|
|
raise BadBadBad
|
|
if _WINDOWS:
|
|
wx.Dialog.__init__(self, parent, -1, title)
|
|
else:
|
|
wx.Dialog.__init__(self, parent, -1, title, size=(390,270))
|
|
|
|
projStaticText = wx.StaticText(self, -1, _("Project:"))
|
|
fileStaticText = wx.StaticText(self, -1, _("File:"))
|
|
argsStaticText = wx.StaticText(self, -1, _("Arguments:"))
|
|
startInStaticText = wx.StaticText(self, -1, _("Start in:"))
|
|
pythonPathStaticText = wx.StaticText(self, -1, _("PYTHONPATH:"))
|
|
postpendStaticText = _("Postpend win32api path")
|
|
cpPanelBorderSizer = wx.BoxSizer(wx.VERTICAL)
|
|
self._projList = wx.Choice(self, -1, (200,-1), choices=self._projectNameList)
|
|
self.Bind(wx.EVT_CHOICE, self.EvtListBox, self._projList)
|
|
HALF_SPACE = 5
|
|
flexGridSizer = wx.FlexGridSizer(cols = 3, vgap = 10, hgap = 10)
|
|
|
|
flexGridSizer.Add(projStaticText, 0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
|
flexGridSizer.Add(self._projList, 1, flag=wx.EXPAND)
|
|
flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0)
|
|
|
|
flexGridSizer.Add(fileStaticText, 0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
|
self._fileList = wx.Choice(self, -1, (200,-1))
|
|
self.Bind(wx.EVT_CHOICE, self.OnFileSelected, self._fileList)
|
|
flexGridSizer.Add(self._fileList, 1, flag=wx.EXPAND)
|
|
flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0)
|
|
|
|
config = wx.ConfigBase_Get()
|
|
self._lastArguments = config.Read("LastRunArguments")
|
|
self._argsEntry = wx.TextCtrl(self, -1, str(self._lastArguments))
|
|
self._argsEntry.SetToolTipString(str(self._lastArguments))
|
|
|
|
flexGridSizer.Add(argsStaticText, 0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
|
flexGridSizer.Add(self._argsEntry, 1, flag=wx.EXPAND)
|
|
flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0)
|
|
|
|
flexGridSizer.Add(startInStaticText, 0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
|
self._lastStartIn = config.Read("LastRunStartIn")
|
|
if not self._lastStartIn:
|
|
self._lastStartIn = str(os.getcwd())
|
|
self._startEntry = wx.TextCtrl(self, -1, self._lastStartIn)
|
|
self._startEntry.SetToolTipString(self._lastStartIn)
|
|
def TextChanged2(event):
|
|
self._startEntry.SetToolTipString(event.GetString())
|
|
self.Bind(wx.EVT_TEXT, TextChanged2, self._startEntry)
|
|
|
|
flexGridSizer.Add(self._startEntry, 1, wx.EXPAND)
|
|
self._findDir = wx.Button(self, -1, _("Browse..."))
|
|
self.Bind(wx.EVT_BUTTON, self.OnFindDirClick, self._findDir)
|
|
flexGridSizer.Add(self._findDir, 0, wx.RIGHT, 10)
|
|
|
|
flexGridSizer.Add(pythonPathStaticText, 0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT)
|
|
if os.environ.has_key('PYTHONPATH'):
|
|
startval = os.environ['PYTHONPATH']
|
|
else:
|
|
startval = ""
|
|
self._lastPythonPath = config.Read("LastPythonPath", startval)
|
|
self._pythonPathEntry = wx.TextCtrl(self, -1, self._lastPythonPath)
|
|
self._pythonPathEntry.SetToolTipString(self._lastPythonPath)
|
|
flexGridSizer.Add(self._pythonPathEntry, 1, wx.EXPAND)
|
|
flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0)
|
|
flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0)
|
|
if debugging:
|
|
self._postpendCheckBox = wx.CheckBox(self, -1, postpendStaticText)
|
|
checked = bool(config.ReadInt("PythonPathPostpend", 1))
|
|
self._postpendCheckBox.SetValue(checked)
|
|
flexGridSizer.Add(self._postpendCheckBox, 1, wx.EXPAND)
|
|
flexGridSizer.Add(wx.StaticText(parent, -1, ""), 0)
|
|
cpPanelBorderSizer.Add(flexGridSizer, 0, wx.ALL, 10)
|
|
|
|
box = wx.BoxSizer(wx.HORIZONTAL)
|
|
self._okButton = wx.Button(self, wx.ID_OK, okButtonName)
|
|
self._okButton.SetDefault()
|
|
self._okButton.SetHelpText(_("The ") + okButtonName + _(" button completes the dialog"))
|
|
box.Add(self._okButton, 0, wx.ALIGN_RIGHT|wx.ALL, 5)
|
|
self.Bind(wx.EVT_BUTTON, self.OnOKClick, self._okButton)
|
|
btn = wx.Button(self, wx.ID_CANCEL, _("Cancel"))
|
|
btn.SetHelpText(_("The Cancel button cancels the dialog."))
|
|
box.Add(btn, 0, wx.ALIGN_RIGHT|wx.ALL, 5)
|
|
cpPanelBorderSizer.Add(box, 0, wx.ALIGN_RIGHT|wx.BOTTOM, 5)
|
|
|
|
self.SetSizer(cpPanelBorderSizer)
|
|
if _WINDOWS:
|
|
self.GetSizer().Fit(self)
|
|
|
|
self.Layout()
|
|
|
|
# Set up selections based on last values used.
|
|
self._fileNameList = None
|
|
self._selectedFileIndex = 0
|
|
lastProject = config.Read("LastRunProject")
|
|
lastFile = config.Read("LastRunFile")
|
|
|
|
if lastProject in self._projectNameList:
|
|
selectedIndex = self._projectNameList.index(lastProject)
|
|
elif selectedIndex < 0:
|
|
selectedIndex = 0
|
|
self._projList.Select(selectedIndex)
|
|
self._selectedProjectIndex = selectedIndex
|
|
self._selectedProjectDocument = self._projectDocumentList[selectedIndex]
|
|
self.PopulateFileList(self._selectedProjectDocument, lastFile)
|
|
|
|
def OnOKClick(self, event):
|
|
startIn = self._startEntry.GetValue()
|
|
fileToRun = self._fileList.GetStringSelection()
|
|
if not fileToRun:
|
|
wx.MessageBox(_("You must select a file to proceed. Note that not all projects have files that can be run or debugged."))
|
|
return
|
|
isPython = fileToRun.endswith(self._pyext)
|
|
if isPython and not os.path.exists(startIn):
|
|
wx.MessageBox(_("Starting directory does not exist. Please change this value."))
|
|
return
|
|
config = wx.ConfigBase_Get()
|
|
config.Write("LastRunProject", self._projectNameList[self._selectedProjectIndex])
|
|
config.Write("LastRunFile", fileToRun)
|
|
# Don't update the arguments or starting directory unless we're runing python.
|
|
if isPython:
|
|
config.Write("LastRunArguments", self._argsEntry.GetValue())
|
|
config.Write("LastRunStartIn", self._startEntry.GetValue())
|
|
config.Write("LastPythonPath",self._pythonPathEntry.GetValue())
|
|
if hasattr(self, "_postpendCheckBox"):
|
|
config.WriteInt("PythonPathPostpend", int(self._postpendCheckBox.GetValue()))
|
|
|
|
self.EndModal(wx.ID_OK)
|
|
|
|
def GetSettings(self):
|
|
filename = self._fileNameList[self._selectedFileIndex]
|
|
args = self._argsEntry.GetValue()
|
|
startIn = self._startEntry.GetValue()
|
|
isPython = filename.endswith(self._pyext)
|
|
env = os.environ
|
|
if hasattr(self, "_postpendCheckBox"):
|
|
postpend = self._postpendCheckBox.GetValue()
|
|
else:
|
|
postpend = False
|
|
if postpend:
|
|
env['PYTHONPATH'] = self._pythonPathEntry.GetValue() + os.pathsep + os.path.join(os.getcwd(), "3rdparty", "pywin32")
|
|
else:
|
|
env['PYTHONPATH'] = self._pythonPathEntry.GetValue()
|
|
|
|
return filename, args, startIn, isPython, env
|
|
|
|
def OnFileSelected(self, event):
|
|
self._selectedFileIndex = self._fileList.GetSelection()
|
|
self.EnableForFileType(event.GetString())
|
|
|
|
def EnableForFileType(self, fileName):
|
|
show = fileName.endswith(self._pyext)
|
|
self._startEntry.Enable(show)
|
|
self._findDir.Enable(show)
|
|
self._argsEntry.Enable(show)
|
|
|
|
if not show:
|
|
self._lastStartIn = self._startEntry.GetValue()
|
|
self._startEntry.SetValue("")
|
|
self._lastArguments = self._argsEntry.GetValue()
|
|
self._argsEntry.SetValue("")
|
|
else:
|
|
self._startEntry.SetValue(self._lastStartIn)
|
|
self._argsEntry.SetValue(self._lastArguments)
|
|
|
|
|
|
|
|
def OnFindDirClick(self, event):
|
|
dlg = wx.DirDialog(self, "Choose a starting directory:", self._startEntry.GetValue(),
|
|
style=wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON)
|
|
|
|
if dlg.ShowModal() == wx.ID_OK:
|
|
self._startEntry.SetValue(dlg.GetPath())
|
|
|
|
dlg.Destroy()
|
|
|
|
def EvtListBox(self, event):
|
|
if event.GetString():
|
|
index = self._projectNameList.index(event.GetString())
|
|
self._selectedProjectDocument = self._projectDocumentList[index]
|
|
self._selectedProjectIndex = index
|
|
self.PopulateFileList(self._selectedProjectDocument)
|
|
|
|
def FilterFileList(self, list):
|
|
if self._pythonOnly:
|
|
files = filter(lambda f: f.endswith(self._pyext), list)
|
|
else:
|
|
files = filter(lambda f: (self._pmext and f.endswith(self._pmext)) or f.endswith(self._pyext), list)
|
|
return files
|
|
|
|
def PopulateFileList(self, project, shortNameToSelect=None):
|
|
self._fileNameList = self.FilterFileList(project.GetFiles()[:])
|
|
self._fileList.Clear()
|
|
if not self._fileNameList:
|
|
return
|
|
self._fileNameList.sort(lambda a, b: cmp(os.path.basename(a).lower(), os.path.basename(b).lower()))
|
|
strings = map(lambda file: os.path.basename(file), self._fileNameList)
|
|
for index in range(0, len(strings)):
|
|
if shortNameToSelect == strings[index]:
|
|
self._selectedFileIndex = index
|
|
break
|
|
self._fileList.Hide()
|
|
self._fileList.AppendItems(strings)
|
|
self._fileList.Show()
|
|
if self._selectedFileIndex not in range(0, len(strings)) : self._selectedFileIndex = 0
|
|
self._fileList.SetSelection(self._selectedFileIndex)
|
|
self.EnableForFileType(strings[self._selectedFileIndex])
|
|
|
|
def GetProjectList(self):
|
|
docList = []
|
|
nameList = []
|
|
found = False
|
|
index = -1
|
|
count = 0
|
|
for document in self._projService.GetDocumentManager().GetDocuments():
|
|
if document.GetDocumentTemplate().GetDocumentType() == ProjectEditor.ProjectDocument and len(document.GetFiles()):
|
|
docList.append(document)
|
|
nameList.append(os.path.basename(document.GetFilename()))
|
|
if document == self._currentProj:
|
|
found = True
|
|
index = count
|
|
count += 1
|
|
#Check for open files not in any of these projects and add them to a default project
|
|
def AlreadyInProject(fileName):
|
|
for projectDocument in docList:
|
|
if projectDocument.IsFileInProject(fileName):
|
|
return True
|
|
return False
|
|
|
|
unprojectedFiles = []
|
|
for document in self._projService.GetDocumentManager().GetDocuments():
|
|
if not ACTIVEGRID_BASE_IDE and type(document) == ProcessModelEditor.ProcessModelDocument:
|
|
if not AlreadyInProject(document.GetFilename()):
|
|
unprojectedFiles.append(document.GetFilename())
|
|
if type(document) == PythonEditor.PythonDocument:
|
|
if not AlreadyInProject(document.GetFilename()):
|
|
unprojectedFiles.append(document.GetFilename())
|
|
|
|
if unprojectedFiles:
|
|
unprojProj = ProjectEditor.ProjectDocument()
|
|
unprojProj.SetFilename(_("Not in any Project"))
|
|
unprojProj.AddFiles(unprojectedFiles)
|
|
docList.append(unprojProj)
|
|
nameList.append(_("Not in any Project"))
|
|
|
|
return nameList, docList, index
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
from wx import ImageFromStream, BitmapFromImage
|
|
import cStringIO
|
|
|
|
#----------------------------------------------------------------------
|
|
def getBreakData():
|
|
return \
|
|
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x02\
|
|
\x00\x00\x00\x90\x91h6\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\
|
|
\x00\x85IDAT(\x91\xbd\x92A\x16\x03!\x08CI\xdf\xdc\x0b\x8e\xe6\xd1\xe0d\xe9\
|
|
\x82\xd6\xc7(\x9di7\xfd\xab<\x14\x13Q\xb8\xbb\xfc\xc2\xe3\xd3\x82\x99\xb9\
|
|
\xe9\xaeq\xe1`f)HF\xc4\x8dC2\x06\xbf\x8a4\xcf\x1e\x03K\xe5h\x1bH\x02\x98\xc7\
|
|
\x03\x98\xa9z\x07\x00%\xd6\xa9\xd27\x90\xac\xbbk\xe5\x15I\xcdD$\xdc\xa7\xceT\
|
|
5a\xce\xf3\xe4\xa0\xaa\x8bO\x12\x11\xabC\xcb\x9c}\xd57\xef\xb0\xf3\xb7\x86p\
|
|
\x97\xf7\xb5\xaa\xde\xb9\xfa|-O\xbdjN\x9b\xf8\x06A\xcb\x00\x00\x00\x00IEND\
|
|
\xaeB`\x82'
|
|
|
|
def getBreakBitmap():
|
|
return BitmapFromImage(getBreakImage())
|
|
|
|
def getBreakImage():
|
|
stream = cStringIO.StringIO(getBreakData())
|
|
return ImageFromStream(stream)
|
|
|
|
def getBreakIcon():
|
|
return wx.IconFromBitmap(getBreakBitmap())
|
|
|
|
#----------------------------------------------------------------------
|
|
def getClearOutputData():
|
|
return \
|
|
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
|
|
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
|
|
\x00\x00\xb4IDAT8\x8d\xa5\x92\xdd\r\x03!\x0c\x83\xbf\xa0n\xd4\x9d\xda5\xb81\
|
|
\xbaS\xbb\x12\xee\x03?\xe5\x08\xe5N\xba\xbc Db\xec\xd8p\xb1l\xb8\xa7\x83\xfe\
|
|
\xb0\x02H\x92F\xc0_\xa3\x99$\x99\x99\xedznc\xe36\x81\x88\x98"\xb2\x02\xa2\
|
|
\x1e\xc4Q\x9aUD\x161\xcd\xde\x1c\x83\x15\x084)\x8d\xc5)\x06\xab\xaaZ\x92\xee\
|
|
\xce\x11W\xdbGD\x0cIT\x06\xe7\x00\xdeY\xfe\xcc\x89\x06\xf0\xf2\x99\x00\xe0\
|
|
\x91\x7f\xab\x83\xed\xa4\xc8\xafK\x0c\xcf\x92\x83\x99\x8d\xe3p\xef\xe4\xa1\
|
|
\x0b\xe57j\xc8:\x06\t\x08\x87.H\xb2n\xa8\xc9\xa9\x12vQ\xfeG"\xe3\xacw\x00\
|
|
\x10$M\xd3\x86_\xf0\xe5\xfc\xb4\xfa\x02\xcb\x13j\x10\xc5\xd7\x92D\x00\x00\
|
|
\x00\x00IEND\xaeB`\x82'
|
|
|
|
def getClearOutputBitmap():
|
|
return BitmapFromImage(getClearOutputImage())
|
|
|
|
def getClearOutputImage():
|
|
stream = cStringIO.StringIO(getClearOutputData())
|
|
return ImageFromStream(stream)
|
|
|
|
def getClearOutputIcon():
|
|
return wx.IconFromBitmap(getClearOutputBitmap())
|
|
|
|
#----------------------------------------------------------------------
|
|
def getCloseData():
|
|
return \
|
|
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x02\
|
|
\x00\x00\x00\x90\x91h6\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\
|
|
\x00\xedIDAT(\x91\xa5\x90!\xae\x840\x10\x86g_\xd6"*kz\x82j\xb0h\x1c\t\' x\
|
|
\x92Z\xc2\x05\x10\x95\x18\x0e\x00\x02M\x82 \xe1\nMF#jz\x80\xea&+\x9a\x10\x96\
|
|
\xdd}\xfb\xc8\x1b\xd7?\xdf\x97\xfe3\xb7u]\xe1\xca\xfc\\\xa2\xff- \xe24M\xc7\
|
|
\xc49wJ\xee\xc7G]\xd7\x8c1\xc6\x18\xe7\xdc\'B\x08k\xed1y\xfaa\x1cG\xad\xb5\
|
|
\x94\x12\x11\x9dsy\x9e+\xa5\x84\x10;\r\x00\xb7\xd3\x95\x8c1UU\x05A\x00\x00\
|
|
\xd6\xda,\xcb\x92$\xf9\xb8\x03\x00PJ\x85\x10Zk\xa5\xd4+\xfdF\x00\x80\xae\xeb\
|
|
\x08!\x84\x90y\x9e\x11\xf1\x8bP\x96\xa5\xef\xdd\xb6\xad\xb5VJ\xf9\x9b\xe0\
|
|
\xe9\xa6i8\xe7\xbe\xdb\xb6mi\x9a\x0e\xc3\xf0F\x88\xe3\x18\x00\xfa\xbe\x0f\
|
|
\xc3\xd0\'\x9c\xf3eY\xa2(*\x8ab\xc7\x9e\xaed\x8c\xa1\x94\xben\xf5\xb1\xd2W\
|
|
\xfa,\xfce.\x0b\x0f\xb8\x96e\x90gS\xe0v\x00\x00\x00\x00IEND\xaeB`\x82'
|
|
|
|
def getCloseBitmap():
|
|
return BitmapFromImage(getCloseImage())
|
|
|
|
def getCloseImage():
|
|
stream = cStringIO.StringIO(getCloseData())
|
|
return ImageFromStream(stream)
|
|
|
|
def getCloseIcon():
|
|
return wx.IconFromBitmap(getCloseBitmap())
|
|
|
|
#----------------------------------------------------------------------
|
|
def getContinueData():
|
|
return \
|
|
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
|
|
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
|
|
\x00\x00\x9eIDAT8\x8d\xbd\x92\xd1\r\x83@\x0cC\xed\x8a\x11X\xac\x1b\xddF,\xd6\
|
|
\x11\x90\xdc\x0f\x9a\x93s)\x14Z\xa9\x91\x10\n\x97\xbc\xd89\x80?\x84\x1a\xa4\
|
|
\x83\xfc\x1c$\x1e)7\xdf<Y0\xaf\x0b\xe6\xf5\x1d\xa1\xb5\x13C\x03 !\xaa\xfd\
|
|
\xed\n:mr\xc0\x1d\x8f\xc9\x9a!\t$\xe5\xd3I\xe2\xe5B$\x99\x00[\x01\xe8\xc5\
|
|
\xd9G\xfaN`\xd8\x81I\xed\x8c\xb19\x94\x8d\xcbL\x00;t\xcf\x9fwPh\xdb\x0e\xe8\
|
|
\xd3,\x17\x8b\xc7\x9d\xbb>\x8a \xec5\x94\tc\xc4\x12\xab\x94\xeb\x7fkWr\xc9B%\
|
|
\xfc\xd2\xfcM<\x01\xf6tn\x12O3c\xe6\x00\x00\x00\x00IEND\xaeB`\x82'
|
|
|
|
def getContinueBitmap():
|
|
return BitmapFromImage(getContinueImage())
|
|
|
|
def getContinueImage():
|
|
stream = cStringIO.StringIO(getContinueData())
|
|
return ImageFromStream(stream)
|
|
|
|
def getContinueIcon():
|
|
return wx.IconFromBitmap(getContinueBitmap())
|
|
|
|
#----------------------------------------------------------------------
|
|
def getNextData():
|
|
return \
|
|
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
|
|
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
|
|
\x00\x00\x8eIDAT8\x8d\xa5SA\x12\xc4 \x08K\xb0\xff\xde\xe9\xbf\xb7\xa6\x87\
|
|
\x1d:\xba\xa2tZn(\x84`"i\x05obk\x13\xd5CmN+\xcc\x00l\xd6\x0c\x00\xf5\xf8\x0e\
|
|
gK\x06\x00 \xa5=k\x00\x00\xb0\xb2]\xd4?5f\xb1\xdb\xaf\xc6\xa2\xcb\xa8\xf0?\
|
|
\x1c\x98\xae\x82\xbf\x81\xa4\x8eA\x16\xe1\n\xd1\xa4\x19\xb3\xe9\n\xce\xe8\
|
|
\xf1\n\x9eg^\x18\x18\x90\xec<\x11\xf9#\x04XMZ\x19\xaac@+\x94\xd4\x99)SeP\xa1\
|
|
)\xd6\x1dI\xe7*\xdc\xf4\x03\xdf~\xe7\x13T^Q?:X\x19d\x00\x00\x00\x00IEND\xaeB\
|
|
`\x82'
|
|
|
|
def getNextBitmap():
|
|
return BitmapFromImage(getNextImage())
|
|
|
|
def getNextImage():
|
|
stream = cStringIO.StringIO(getNextData())
|
|
return ImageFromStream(stream)
|
|
|
|
def getNextIcon():
|
|
return wx.IconFromBitmap(getNextBitmap())
|
|
|
|
#----------------------------------------------------------------------
|
|
def getStepInData():
|
|
return \
|
|
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
|
|
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
|
|
\x00\x00\x87IDAT8\x8d\xadSA\x12\x84 \x0ck\x8a\xffv\xfc\xb74{X\xeb0P@\x07s\
|
|
\x84\xa4$\x01\x00M\xb2\x02]R\x8b\xc86\xda\xdc\xedd\xb4~\xe8\x86\xc6\x01-\x93\
|
|
\x96\xd9#\xf6\x06\xc3;p1I\xd1\x14\x0b#|\x17aF\xec\r\xeeF\xa0eB\xd34\xca\xd0A\
|
|
]j\x84\xa6\x03\x00""\xb7\xb0tRZ\xf7x\xb7\x83\x91]\xcb\x7fa\xd9\x89\x0fC\xfd\
|
|
\x94\x9d|9\x99^k\x13\xa1 \xb3\x16\x0f#\xd4\x88N~\x14\xe1-\x96\x7f\xe3\x0f\
|
|
\x11\x91UC\x0cX\'\x1e\x00\x00\x00\x00IEND\xaeB`\x82'
|
|
|
|
def getStepInBitmap():
|
|
return BitmapFromImage(getStepInImage())
|
|
|
|
def getStepInImage():
|
|
stream = cStringIO.StringIO(getStepInData())
|
|
return ImageFromStream(stream)
|
|
|
|
def getStepInIcon():
|
|
return wx.IconFromBitmap(getStepInBitmap())
|
|
|
|
#----------------------------------------------------------------------
|
|
def getStopData():
|
|
return \
|
|
"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
|
|
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
|
|
\x00\x00FIDAT8\x8d\xed\x91\xc1\t\xc00\x0c\x03O!\x0b\xa9\xfb\xef\xa6\xfcB\xa1\
|
|
N\t\xf4Wr\xa0\x8f\xb1\x0f\x81\xe1\x97\xe4-\xb6}_V%\xc8\xc2, \t\x92\xe6]\xfbZ\
|
|
\xf7\x08\xa0W\xc3\xea5\xdb\rl_IX\xe5\xf0d\x00\xfa\x8d#\x7f\xc4\xf7'\xab\x00\
|
|
\x00\x00\x00IEND\xaeB`\x82"
|
|
|
|
def getStopBitmap():
|
|
return BitmapFromImage(getStopImage())
|
|
|
|
def getStopImage():
|
|
stream = cStringIO.StringIO(getStopData())
|
|
return ImageFromStream(stream)
|
|
|
|
def getStopIcon():
|
|
return wx.IconFromBitmap(getStopBitmap())
|
|
|
|
#----------------------------------------------------------------------
|
|
def getStepReturnData():
|
|
return \
|
|
"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
|
|
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
|
|
\x00\x00\x8dIDAT8\x8d\xa5S\xd1\x0e\xc4 \x08\xa3\xb0\xff\xbe\xdc\x7fO\xba'6\
|
|
\xf1\xf44\xb3O$Phk\x04\xd4d\x07\xba\xc5\x16\x91#\nza\xdb\x84\x1a\xa2\xfe\xf8\
|
|
\x99\xfa_=p+\xe8\x91ED\xbc<\xa4 \xb4\x0b\x01\xb5{\x01\xf9\xbbG-\x13\x87\x16f\
|
|
\x84\xbf\x16V\xb0l\x01@\no\x86\xae\x82Q\xa8=\xa4\x0c\x80\xe70\xbd\x10jh\xbd\
|
|
\x07R\x06#\xc9^N\xb6\xde\x03)\x83\x18\xaeU\x90\x9c>a\xb2P\r\xb3&/Y\xa8\xd1^^\
|
|
\xb6\xf0\x16\xdb\xbf\xf1\x02\x81\xa5TK\x1d\x07\xde\x92\x00\x00\x00\x00IEND\
|
|
\xaeB`\x82"
|
|
|
|
def getStepReturnBitmap():
|
|
return BitmapFromImage(getStepReturnImage())
|
|
|
|
def getStepReturnImage():
|
|
stream = cStringIO.StringIO(getStepReturnData())
|
|
return ImageFromStream(stream)
|
|
|
|
def getStepReturnIcon():
|
|
return wx.IconFromBitmap(getStepReturnBitmap())
|
|
|
|
#----------------------------------------------------------------------
|
|
def getAddWatchData():
|
|
return \
|
|
'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
|
|
\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
|
|
\x00\x00\x85IDAT8\x8dc`\x18h\xc0\x88.\xd0\xc0\xf0\xff?*\x9f\x11C\rN\x80\xae\
|
|
\x19\x97\x18\xd1\x9a\x896\x84\x18[p\xa9aA\xe6\xfc7f\xc0P\xc4x\x163\x9cp\x1a0\
|
|
\xeb,!w\x100 \x1dK\xac\x10\r\x08\x05".yFL\x85\x8c\x18b\xa8|Ty\xa2\x13\x92\'\
|
|
\xc3\xe4\xff\x9f\x18\x1e3\xb82t\xa2\x88\x13\xedg.\x06aa&\x06VV\x7f\x86\xb9\
|
|
\xcfU\x19\xbc\xb0\xba\x86h\xe0\xc8\xd0\xfc\xbf\x80\xe1>q)\x94\xe6\x00\x00\
|
|
\x85\x923_\xd22\xa4\xcd\x00\x00\x00\x00IEND\xaeB`\x82'
|
|
|
|
def getAddWatchBitmap():
|
|
return BitmapFromImage(getAddWatchImage())
|
|
|
|
def getAddWatchImage():
|
|
stream = cStringIO.StringIO(getAddWatchData())
|
|
return ImageFromStream(stream)
|
|
|
|
def getAddWatchIcon():
|
|
return wx.IconFromBitmap(getAddWatchBitmap())
|