+ 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) , noArrow=True)
+
+ 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")
+ 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"))
+ 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.SetSizer(sizer_1)
+ self.Layout()
+
+class BaseFramesUI(wx.SplitterWindow):
+ def __init__(self, parent, id, ui):
+ wx.SplitterWindow.__init__(self, parent, id, style = wx.SP_3D)
+ self._ui = ui
+ self._p1 = p1 = wx.ScrolledWindow(self, -1)
+
+ sizer = wx.BoxSizer(wx.HORIZONTAL)
+ framesLabel = wx.StaticText(self, -1, "Stack Frame:")
+ sizer.Add(framesLabel, 0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT|wx.LEFT, border=2)
+
+ self._framesChoiceCtrl = wx.Choice(p1, -1, choices=[" "])
+ sizer.Add(self._framesChoiceCtrl, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1)
+ self._framesChoiceCtrl.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnListRightClick)
+ self.Bind(wx.EVT_CHOICE, self.ListItemSelected, self._framesChoiceCtrl)
+
+ sizer2 = wx.BoxSizer(wx.VERTICAL)
+ p1.SetSizer(sizer2)
+ self._treeCtrl = wx.gizmos.TreeListCtrl(p1, -1, style=wx.TR_DEFAULT_STYLE| wx.TR_FULL_ROW_HIGHLIGHT)
+ self._treeCtrl.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnRightClick)
+ sizer2.Add(sizer, 0, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1)
+ sizer2.Add(self._treeCtrl,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.SetPyData(self._root, "root")
+ tree.SetItemText(self._root, "", 1)
+ tree.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.IntrospectCallback)
+ self._p2 = p2 = wx.Window(self, -1)
+ sizer3 = wx.BoxSizer(wx.HORIZONTAL)
+ p2.SetSizer(sizer3)
+ p2.Bind(wx.EVT_SIZE, self.OnSize)
+ self._notebook = wx.Notebook(p2, -1, size=(20,20))
+ self._notebook.Hide()
+ sizer3.Add(self._notebook, 1, wx.ALIGN_LEFT|wx.ALL|wx.EXPAND, 1)
+ self.consoleTab = self.MakeConsoleTab(self._notebook, wx.NewId())
+ self.inspectConsoleTab = self.MakeInspectConsoleTab(self._notebook, wx.NewId())
+ self.breakPointsTab = self.MakeBreakPointsTab(self._notebook, wx.NewId())
+ self._notebook.AddPage(self.consoleTab, "Output")
+ self._notebook.AddPage(self.inspectConsoleTab, "Interact")
+ self._notebook.AddPage(self.breakPointsTab, "Break Points")
+ self.SetMinimumPaneSize(20)
+ self.SplitVertically(p1, p2, 550)
+ self.currentItem = None
+ self._notebook.Show(True)
+
+ def PopulateBPList(self):
+ self.breakPointsTab.PopulateBPList()
+
+ def OnSize(self, event):
+ self._notebook.SetSize(self._p2.GetSize())
+
+ 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)
+ lineText = foundView.GetCtrl().GetLine(lineNum - 1)
+ foundView.SetSelection(startPos, startPos + len(lineText.rstrip("\n")))
+ import OutlineService
+ wx.GetApp().GetService(OutlineService.OutlineService).LoadOutline(foundView, position=startPos)
+
+ def MakeConsoleTab(self, parent, id):
+ 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, 2)
+ 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()
+ wx.stc.EVT_STC_DOUBLECLICK(self._textCtrl, self._textCtrl.GetId(), self.OnDoubleClick)
+
+ panel.SetSizer(sizer)
+ #sizer.Fit(panel)
+
+ return panel
+ def ExecuteCommand(self, command):
+ assert False, "ExecuteCommand not overridden"
+
+ def MakeInspectConsoleTab(self, parent, id):
+ def handleCommand():
+ cmdStr = self._cmdInput.GetValue()
+ if cmdStr:
+ self._cmdList.append(cmdStr)
+ self._cmdIndex = len(self._cmdList)
+ self._cmdInput.Clear()
+ self._cmdOutput.SetDefaultStyle(style=self._cmdOutputTextStyle)
+ self._cmdOutput.AppendText(">>> " + cmdStr + "\n")
+ self._cmdOutput.SetDefaultStyle(style=self._defaultOutputTextStyle)
+ self.ExecuteCommand(cmdStr)
+ return
+
+ def OnCmdButtonPressed(event):
+ handleCommand()
+ return
+
+ def OnKeyPressed(event):
+ key = event.KeyCode()
+ if key == wx.WXK_RETURN:
+ handleCommand()
+ elif key == wx.WXK_UP:
+ if len(self._cmdList) < 1 or self._cmdIndex < 1:
+ return
+
+ self._cmdInput.Clear()
+ self._cmdInput.AppendText(self._cmdList[self._cmdIndex - 1])
+ self._cmdIndex = self._cmdIndex - 1
+ elif key == wx.WXK_DOWN:
+ if len(self._cmdList) < 1 or self._cmdIndex >= len(self._cmdList):
+ return
+
+ self._cmdInput.Clear()
+ self._cmdInput.AppendText(self._cmdList[self._cmdIndex - 1])
+ self._cmdIndex = self._cmdIndex + 1
+ else:
+ event.Skip()
+ return
+
+ def OnClrButtonPressed(event):
+ self._cmdOutput.Clear()
+
+ panel = wx.Panel(parent, id)
+
+ cmdLabel = wx.StaticText(panel, -1, "Cmd: ")
+ self._cmdInput = wx.TextCtrl(panel)
+ cmdButton = wx.Button(panel, label="Execute")
+ clrButton = wx.Button(panel, label="Clear")
+ self._cmdOutput = wx.TextCtrl(panel, style=wx.TE_MULTILINE | wx.HSCROLL | wx.TE_READONLY | wx.TE_RICH2)
+
+ hbox = wx.BoxSizer()
+ hbox.Add(cmdLabel, proportion=0, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
+ hbox.Add(self._cmdInput, proportion=1, flag=wx.EXPAND)
+ hbox.Add(cmdButton, proportion=0, flag=wx.RIGHT)
+ hbox.Add(clrButton, proportion=0, flag=wx.RIGHT)
+
+ vbox = wx.BoxSizer(wx.VERTICAL)
+ vbox.Add(hbox, proportion=0, flag=wx.EXPAND | wx.ALL, border=2)
+ vbox.Add(self._cmdOutput, proportion=1, flag=wx.EXPAND | wx.LEFT, border=2)
+
+ panel.SetSizer(vbox)
+ cmdButton.Bind(wx.EVT_BUTTON, OnCmdButtonPressed)
+ clrButton.Bind(wx.EVT_BUTTON, OnClrButtonPressed)
+ wx.EVT_KEY_DOWN(self._cmdInput, OnKeyPressed)
+
+ fixedFont = wx.Font(self._cmdInput.GetFont().GetPointSize(), family=wx.TELETYPE, style=wx.NORMAL, weight=wx.NORMAL)
+ self._defaultOutputTextStyle = wx.TextAttr("BLACK", wx.NullColour, fixedFont)
+ self._cmdOutputTextStyle = wx.TextAttr("RED", wx.NullColour, fixedFont)
+ self._cmdOutput.SetDefaultStyle(style=self._defaultOutputTextStyle)
+ self._cmdList = []
+ self._cmdIndex = 0
+
+ panel.Show()
+ return panel
+
+ def MakeBreakPointsTab(self, parent, id):
+ panel = BreakpointsUI(parent, id, self._ui)
+ return panel
+
+ def OnRightClick(self, event):
+ assert False, "OnRightClick not overridden"
+
+ def ClearWhileRunning(self):
+ list = self._framesChoiceCtrl
+ list.Clear()
+ list.Enable(False)
+ tree = self._treeCtrl
+ root = self._root
+ tree.DeleteChildren(root)
+ self._cmdInput.Enable(False)
+ self._cmdOutput.Enable(False)
+
+ 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):
+ assert False, "OnSyncFrame not overridden"
+
+ def LoadFramesList(self, framesXML):
+ assert False, "LoadFramesList not overridden"
+
+ def ListItemSelected(self, event):
+ assert False, "ListItemSelected not overridden"
+
+ def PopulateTreeFromFrameMessage(self, message):
+ assert False, "PopulateTreeFromFrameMessage not overridden"
+
+ def IntrospectCallback(self, event):
+ assert False, "IntrospectCallback not overridden"
+
+ def AppendText(self, text):
+ self._textCtrl.SetReadOnly(False)
+ self._textCtrl.AddText(text)
+ self._textCtrl.ScrollToLine(self._textCtrl.GetLineCount())
+ self._textCtrl.SetReadOnly(True)
+
+ def AppendErrorText(self, text):
+ self._textCtrl.SetReadOnly(False)
+ self._textCtrl.SetFontColor(wx.RED)
+ self._textCtrl.StyleClearAll()
+ self._textCtrl.AddText(text)
+ self._textCtrl.ScrollToLine(self._textCtrl.GetLineCount())
+ self._textCtrl.SetFontColor(wx.BLACK)
+ self._textCtrl.StyleClearAll()
+ self._textCtrl.SetReadOnly(True)
+
+ def ClearOutput(self, event):
+ self._textCtrl.SetReadOnly(False)
+ self._textCtrl.ClearAll()
+ self._textCtrl.SetReadOnly(True)
+
+ def SwitchToOutputTab(self):
+ self._notebook.SetSelection(0)
+
+class PHPFramesUI(BaseFramesUI):
+ def __init__(self, parent, id, ui):
+ BaseFramesUI.__init__(self, parent, id, ui)
+
+ def LoadFramesList(self, stackList):
+ wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_WAIT))
+
+ self._cmdInput.Enable(True)
+ self._cmdOutput.Enable(True)
+ index = 0
+ self._stack = stackList
+ list = self._framesChoiceCtrl
+ list.Clear()
+
+ if len(stackList) > 0:
+ self._displayVariableTreeRootNode()
+
+ for stackFrame in stackList:
+ message = stackFrame.getDisplayStr(stackList)
+ list.Append(message)
+
+ self.currentItem = index
+ list.SetSelection(index)
+ list.Enable(True)
+ self.OnSyncFrame(None)
+ self._p1.FitInside()
+
+ wx.GetApp().GetTopWindow().SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
+
+ def PopulateTreeFromStackFrame(self, frameNode):
+ vars = frameNode.getVariables()
+ tree = self._treeCtrl
+ rootTreeNode = self._root
+
+ #
+ # Build a new sub variable tree from the root node.
+ #
+ tree.DeleteChildren(rootTreeNode)
+ for var in vars:
+ aTreeNode = self.AppendSubTreeFromAVariable(tree, var, rootTreeNode)
+
+ #
+ # No need to expand the node here, as the IntrospectCallback() has
+ # already called it.
+ #
+ self._p2.FitInside()
+
+ def AppendSubTreeFromAVariable(self, tree, var, parentTreeNode, previousOne = None):
+ varName = var.getName()
+ varValueStr = var.getValueString()
+
+ #
+ # If previously we already have this item in the tree, replace it.
+ # Otherwise, insert a new one.
+ #
+ if previousOne:
+ newNode = tree.InsertItem(parentTreeNode, previousOne, varName)
+ else:
+ newNode = tree.AppendItem(parentTreeNode, varName)
+
+ #
+ # Associate this variable object with this newNode.
+ #
+ tree.SetPyData(newNode, var)
+
+ #
+ # Set this variable's value string (for displaying).
+ #
+ if varValueStr and len(varValueStr) > 0:
+ tree.SetItemText(newNode, varValueStr, 1)
+
+ #
+ # If this variable has child variables, recursively build the sub
+ # variable tree.
+ #
+ if var.hasChildren():
+ childrenVarList = var.getChildrenVariables()
+ for childVar in childrenVarList:
+ self.AppendSubTreeFromAVariable(tree, childVar, newNode)
+
+ #
+ # If its child variables are sortable, sort it.
+ #
+ if var.childrenIsSortable():
+ tree.SortChildren(newNode)
+
+ return newNode
+
+ def IntrospectCallback(self, event):
+ tree = self._treeCtrl
+ item = event.GetItem()
+
+ #
+ # Only when the introspection happens to root, we get the whole
+ # variable tree. For all the individual nodes, we have populated
+ # the subtree already, so don't need to do anything.
+ #
+ if tree.GetPyData(item) == "root" and self._stack and self._stack[self.currentItem]:
+ stackFrame = self._stack[self.currentItem]
+ self.PopulateTreeFromStackFrame(stackFrame)
+
+ event.Skip()
+
+ def OnSyncFrame(self, event):
+ stackFrame = self._stack[self.currentItem]
+ fileName = stackFrame.getFileName()
+ lineNo = stackFrame.getLineNo()
+ if _VERBOSE:
+ print "OnSyncFrame(): about to sync: fileName: %s, lineNo: %d" % (fileName, lineNo)
+ self._ui.SynchCurrentLine(fileName, lineNo)
+ if _VERBOSE:
+ print "OnSyncFrame(): sync done"