mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 06:05:49 -06:00
1024 lines
29 KiB
C++
1024 lines
29 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin III - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
// frmDebugger.cpp - debugger
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "pgAdmin3.h"
|
|
|
|
// wxWindows headers
|
|
#include <wx/wx.h>
|
|
#include <wx/event.h>
|
|
|
|
#include <stdexcept>
|
|
|
|
// App headers
|
|
#include "ctl/ctlMenuToolbar.h"
|
|
#include "ctl/ctlSQLBox.h"
|
|
#include "ctl/ctlAuiNotebook.h"
|
|
#include "ctl/ctlProgressStatusBar.h"
|
|
#include "debugger/dbgController.h"
|
|
#include "debugger/ctlTabWindow.h"
|
|
#include "debugger/frmDebugger.h"
|
|
#include "frm/frmMain.h"
|
|
#include "debugger/dbgConst.h"
|
|
|
|
#include "images/debugger.pngc"
|
|
#include "images/clearAll.pngc"
|
|
#include "images/continue.pngc"
|
|
#include "images/setBreak.pngc"
|
|
#include "images/stepOver.pngc"
|
|
#include "images/stepInto.pngc"
|
|
#include "images/stop.pngc"
|
|
|
|
IMPLEMENT_CLASS(frmDebugger, pgFrame)
|
|
|
|
BEGIN_EVENT_TABLE(frmDebugger, pgFrame)
|
|
EVT_CLOSE(frmDebugger::OnClose)
|
|
EVT_SIZE(frmDebugger::OnSize)
|
|
EVT_ERASE_BACKGROUND(frmDebugger::OnEraseBackground)
|
|
EVT_AUI_PANE_CLOSE(frmDebugger::OnAuiUpdate)
|
|
|
|
EVT_MENU_RANGE(MENU_ID_TOGGLE_BREAK, MENU_ID_STOP, frmDebugger::OnDebugCommand)
|
|
|
|
EVT_STC_MARGINCLICK(wxID_ANY, frmDebugger::OnMarginClick)
|
|
EVT_STC_UPDATEUI(wxID_ANY, frmDebugger::OnPositionStc)
|
|
EVT_LISTBOX(wxID_ANY, frmDebugger::OnSelectFrame)
|
|
EVT_GRID_CELL_CHANGED( frmDebugger::OnVarChange)
|
|
EVT_MENU(MNU_EXIT, frmDebugger ::OnExit)
|
|
EVT_MENU(MENU_ID_VIEW_TOOLBAR, frmDebugger::OnToggleToolBar)
|
|
EVT_MENU(MENU_ID_VIEW_STACKPANE, frmDebugger::OnToggleStackPane)
|
|
EVT_MENU(MENU_ID_VIEW_OUTPUTPANE, frmDebugger::OnToggleOutputPane)
|
|
EVT_MENU(MENU_ID_VIEW_DEFAULTVIEW, frmDebugger::OnDefaultView)
|
|
|
|
EVT_MENU(MNU_CONTENTS, frmDebugger::OnContents)
|
|
EVT_MENU(MNU_HELP, frmDebugger::OnHelp)
|
|
END_EVENT_TABLE()
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// frmDebugger constructor
|
|
//
|
|
// frmDebugger manages the user interface for the workstation. This class
|
|
// manages the toolbar, menu, status bar, and top-level windows.
|
|
|
|
frmDebugger::frmDebugger(frmMain *_parent, dbgController *_controller,
|
|
const wxString &_title) : pgFrame(_parent, _title), m_menuBar(NULL),
|
|
m_toolBar(NULL), m_viewMenu(NULL), m_debugMenu(NULL), m_statusBar(NULL),
|
|
m_parent(_parent), m_controller(_controller), m_stackWindow(NULL),
|
|
m_tabWindow(NULL), m_codeViewer(NULL)
|
|
{
|
|
dlgName = wxT("frmDebugger");
|
|
RestorePosition(100, 100, 600, 500, 450, 300);
|
|
|
|
SetFont(settings->GetSystemFont());
|
|
|
|
m_manager.SetManagedWindow(this);
|
|
m_manager.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_TRANSPARENT_DRAG);
|
|
|
|
// Define the icon for this window
|
|
SetIcon(*debugger_png_ico);
|
|
|
|
// Create (and configure) the menu bar, toolbar, and status bar
|
|
m_menuBar = SetupMenuBar();
|
|
m_toolBar = SetupToolBar();
|
|
m_statusBar = SetupStatusBar();
|
|
|
|
m_manager.AddPane(
|
|
m_toolBar,
|
|
wxAuiPaneInfo().Name(wxT("toolBar")).Caption(wxT("Toolbar"))
|
|
.ToolbarPane().Top().Row(1).Position(1).LeftDockable(false)
|
|
.RightDockable(false));
|
|
|
|
// Now load the layout
|
|
wxString perspective;
|
|
settings->Read(
|
|
wxT("Debugger/frmDebugger/Perspective-")
|
|
+ wxString(FRMDEBUGGER_PERSPECTIVE_VER),
|
|
&perspective, FRMDEBUGGER_DEFAULT_PERSPECTIVE);
|
|
|
|
m_manager.LoadPerspective(perspective, true);
|
|
|
|
// and reset the captions for the current language
|
|
m_manager.GetPane(wxT("toolBar")).Caption(_("Toolbar"));
|
|
|
|
// Sync the View menu options
|
|
m_viewMenu->Check(MENU_ID_VIEW_TOOLBAR, m_manager.GetPane(wxT("toolBar")).IsShown());
|
|
|
|
SetupDebugger();
|
|
|
|
m_manager.Update();
|
|
}
|
|
|
|
|
|
frmDebugger::~frmDebugger()
|
|
{
|
|
// Only save the settings if the window was completely setup
|
|
// This may not be the case if the params dialog was displayed,
|
|
// and the user hit cancel before the main form opened.
|
|
wxAuiPaneInfo &pane = m_manager.GetPane(wxT("sourcePane"));
|
|
if (pane.IsOk())
|
|
settings->Write(wxT("Debugger/frmDebugger/Perspective-") + wxString(FRMDEBUGGER_PERSPECTIVE_VER), m_manager.SavePerspective());
|
|
|
|
m_manager.UnInit();
|
|
|
|
if (m_parent)
|
|
m_parent->RemoveFrame(this);
|
|
|
|
if (m_controller)
|
|
{
|
|
PopEventHandler();
|
|
delete m_controller;
|
|
m_controller = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnContents()
|
|
// OnHelp()
|
|
//
|
|
// Help menu options
|
|
void frmDebugger::OnContents(wxCommandEvent &event)
|
|
{
|
|
DisplayHelp(wxT("debugger"), HELP_PGADMIN);
|
|
}
|
|
|
|
|
|
void frmDebugger::OnHelp(wxCommandEvent &event)
|
|
{
|
|
DisplayHelp(wxT("plpgsql"), HELP_POSTGRESQL);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// SetupDebugger()
|
|
//
|
|
// This function creates the debugger views...
|
|
//
|
|
void frmDebugger::SetupDebugger()
|
|
{
|
|
SetFont(settings->GetSystemFont());
|
|
|
|
// Initializing Stack Frame Window
|
|
if (m_stackWindow == NULL)
|
|
{
|
|
m_stackWindow = new ctlStackWindow(this, WINDOW_ID_STACK, wxDefaultPosition,
|
|
wxDefaultSize, 0);
|
|
|
|
m_manager.AddPane(m_stackWindow,
|
|
wxAuiPaneInfo().Name(wxT("stackPane")).Caption(_("Stack pane")).Right()
|
|
.MinSize(wxSize(100, 100)).BestSize(wxSize(250, 200)));
|
|
}
|
|
// Initializing Tab Window
|
|
if (m_tabWindow == NULL)
|
|
{
|
|
m_tabWindow = new ctlTabWindow(this, WINDOW_ID_TABS, wxDefaultPosition,
|
|
wxDefaultSize, wxAUI_NB_BOTTOM | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | wxAUI_NB_SCROLL_BUTTONS | wxAUI_NB_WINDOWLIST_BUTTON);
|
|
|
|
m_manager.AddPane(m_tabWindow,
|
|
wxAuiPaneInfo().Name(wxT("outputPane")).Caption(_("Output pane")).Bottom()
|
|
.MinSize(wxSize(200, 100)).BestSize(wxSize(550, 300)));
|
|
}
|
|
// Initialing Code viewer Window
|
|
if (m_codeViewer == NULL)
|
|
{
|
|
m_codeViewer = new ctlSQLBox(this, -1);
|
|
|
|
// Set up the markers that we use to indicate the current line and
|
|
// the break-point
|
|
m_codeViewer->MarkerDefine(MARKER_CURRENT, wxSTC_MARK_ARROW, *wxGREEN,
|
|
*wxGREEN);
|
|
m_codeViewer->MarkerDefine(MARKER_CURRENT_BG, wxSTC_MARK_BACKGROUND, *wxGREEN,
|
|
*wxGREEN);
|
|
m_codeViewer->MarkerDefine(MARKER_BREAKPOINT, wxSTC_MARK_CIRCLEPLUS, *wxRED,
|
|
*wxRED);
|
|
|
|
m_codeViewer->SetMarginWidth(1, 16);
|
|
m_codeViewer->SetMarginType(1, wxSTC_MARGIN_SYMBOL);
|
|
|
|
// Make sure that the text control tells us when the user clicks in the
|
|
// left margin
|
|
m_codeViewer->SetMarginSensitive(0, true);
|
|
m_codeViewer->SetMarginSensitive(1, true);
|
|
m_codeViewer->SetMarginSensitive(2, true);
|
|
|
|
m_manager.AddPane(m_codeViewer,
|
|
wxAuiPaneInfo().Name(wxT("sourcePane")).Caption(_("Source pane")).Center()
|
|
.CaptionVisible(false).CloseButton(false).MinSize(wxSize(200, 100))
|
|
.BestSize(wxSize(350, 200)));
|
|
}
|
|
|
|
// Make sure the user can't edit the source code for this function
|
|
m_codeViewer->SetReadOnly(true);
|
|
|
|
// Now (re)load the layout
|
|
wxString perspective;
|
|
settings->Read(
|
|
wxT("Debugger/frmDebugger/Perspective-") +
|
|
wxString(FRMDEBUGGER_PERSPECTIVE_VER), &perspective,
|
|
FRMDEBUGGER_DEFAULT_PERSPECTIVE);
|
|
m_manager.LoadPerspective(perspective, true);
|
|
|
|
// And reset the captions
|
|
m_manager.GetPane(wxT("sourcePane")).Caption(_("Source pane"));
|
|
m_manager.GetPane(wxT("stackPane")).Caption(_("Stack pane"));
|
|
m_manager.GetPane(wxT("outputPane")).Caption(_("Output pane"));
|
|
|
|
// Sync the View menu options
|
|
m_viewMenu->Check(MENU_ID_VIEW_STACKPANE,
|
|
m_manager.GetPane(wxT("stackPane")).IsShown());
|
|
m_viewMenu->Check(MENU_ID_VIEW_OUTPUTPANE,
|
|
m_manager.GetPane(wxT("outputPane")).IsShown());
|
|
|
|
// Enable the options for these controls
|
|
m_viewMenu->Enable(MENU_ID_VIEW_OUTPUTPANE, true);
|
|
m_viewMenu->Enable(MENU_ID_VIEW_STACKPANE, true);
|
|
|
|
m_manager.Update();
|
|
|
|
// force
|
|
EnableToolsAndMenus(false);
|
|
|
|
PushEventHandler(m_controller);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// EnableToolsAndMenus
|
|
//
|
|
// Enable or disable the debugging tools and menus
|
|
//
|
|
// Parameters:
|
|
// - enable/disable (boolean)
|
|
//
|
|
void frmDebugger::EnableToolsAndMenus(bool enable)
|
|
{
|
|
if (m_toolBar)
|
|
{
|
|
m_toolBar->EnableTool(MENU_ID_STEP_INTO, enable);
|
|
m_toolBar->EnableTool(MENU_ID_STEP_OVER, enable);
|
|
m_toolBar->EnableTool(MENU_ID_CONTINUE,
|
|
(enable ||
|
|
(m_controller && m_controller->CanRestart())));
|
|
m_toolBar->EnableTool(MENU_ID_TOGGLE_BREAK, enable);
|
|
m_toolBar->EnableTool(MENU_ID_CLEAR_ALL_BREAK, enable);
|
|
m_toolBar->EnableTool(MENU_ID_STOP, enable);
|
|
}
|
|
|
|
if (m_debugMenu)
|
|
{
|
|
m_debugMenu->Enable(MENU_ID_STEP_INTO, enable);
|
|
m_debugMenu->Enable(MENU_ID_STEP_OVER, enable);
|
|
m_debugMenu->Enable(MENU_ID_CONTINUE,
|
|
(enable ||
|
|
(m_controller && m_controller->CanRestart())));
|
|
m_debugMenu->Enable(MENU_ID_TOGGLE_BREAK, enable);
|
|
m_debugMenu->Enable(MENU_ID_CLEAR_ALL_BREAK, enable);
|
|
m_debugMenu->Enable(MENU_ID_STOP, enable);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// GetLineNo
|
|
//
|
|
// This function returns the current line-number, where the execution flow
|
|
// has been stopped
|
|
//
|
|
// Returns:
|
|
// Current line-number
|
|
//
|
|
int frmDebugger::GetLineNo()
|
|
{
|
|
if (m_codeViewer)
|
|
{
|
|
return (m_codeViewer->LineFromPosition(m_codeViewer->GetCurrentPos()));
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// IsBreakpoint(int)
|
|
//
|
|
// This function helps checking if break-point is set on the particular line
|
|
//
|
|
// Parameters:
|
|
// - line-number
|
|
//
|
|
// Returns:
|
|
// - True if a break-point is set on the line-no, otherwise false
|
|
//
|
|
bool frmDebugger::IsBreakpoint(int _lineNo)
|
|
{
|
|
if (m_codeViewer)
|
|
return (m_codeViewer->MarkerGet(_lineNo) &
|
|
MARKERINDEX_TO_MARKERMASK(MARKER_BREAKPOINT) ? true : false);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// ClearAllBreakpoints
|
|
//
|
|
// This function clears all the break-points
|
|
//
|
|
void frmDebugger::ClearAllBreakpoints()
|
|
{
|
|
int lineNo = -1;
|
|
bool updateBreakpoints = false;
|
|
|
|
if (m_codeViewer)
|
|
{
|
|
while((lineNo = m_codeViewer->MarkerNext(lineNo + 1,
|
|
MARKERINDEX_TO_MARKERMASK(MARKER_BREAKPOINT))) != -1)
|
|
{
|
|
// Clear the break-point at particular location
|
|
m_controller->ClearBreakpoint(lineNo);
|
|
updateBreakpoints = true;
|
|
}
|
|
|
|
// Update break-points only if required
|
|
if (updateBreakpoints)
|
|
m_controller->UpdateBreakpoints();
|
|
}
|
|
}
|
|
|
|
|
|
void frmDebugger::ClearBreakpointMarkers()
|
|
{
|
|
int lineNo = 0;
|
|
if (m_codeViewer)
|
|
{
|
|
while((lineNo = m_codeViewer->MarkerNext(lineNo,
|
|
MARKERINDEX_TO_MARKERMASK(MARKER_BREAKPOINT))) != -1)
|
|
{
|
|
m_codeViewer->MarkerDelete(lineNo++, MARKER_BREAKPOINT);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void frmDebugger::MarkBreakpoint(int _line)
|
|
{
|
|
if (m_codeViewer)
|
|
{
|
|
m_codeViewer->MarkerAdd(_line, MARKER_BREAKPOINT);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// UnhilightCurrentLine
|
|
//
|
|
// This function removes the hilight from the current line
|
|
//
|
|
void frmDebugger::UnhilightCurrentLine()
|
|
{
|
|
if (m_codeViewer)
|
|
{
|
|
int lineNo
|
|
= m_codeViewer->MarkerNext(0, MARKERINDEX_TO_MARKERMASK(MARKER_CURRENT));
|
|
|
|
if(lineNo != -1)
|
|
{
|
|
m_codeViewer->MarkerDelete(lineNo, MARKER_CURRENT);
|
|
m_codeViewer->MarkerDelete(lineNo, MARKER_CURRENT_BG);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnDebugCommand(wxCommandEvent)
|
|
//
|
|
// This function handles the user clicks one of the debugger tools and menus
|
|
// and take care of actions requires. These events are toggle break-point,
|
|
// clear all break-points, debugging continue, step-in, step-over and stop
|
|
// debugging.
|
|
//
|
|
// Parameters
|
|
// - event object
|
|
//
|
|
void frmDebugger::OnDebugCommand(wxCommandEvent &_event)
|
|
{
|
|
switch(_event.GetId())
|
|
{
|
|
case MENU_ID_TOGGLE_BREAK:
|
|
{
|
|
int lineNo = GetLineNo();
|
|
|
|
// This event should have not been called
|
|
if (lineNo == -1)
|
|
return;
|
|
|
|
// The user wants to set or clear a breakpoint at the line that
|
|
// contains the insertion point (the caret)
|
|
if (IsBreakpoint(lineNo))
|
|
{
|
|
m_controller->ClearBreakpoint(lineNo);
|
|
}
|
|
else
|
|
{
|
|
m_controller->SetBreakpoint(lineNo);
|
|
}
|
|
m_controller->UpdateBreakpoints();
|
|
}
|
|
break;
|
|
|
|
case MENU_ID_CLEAR_ALL_BREAK:
|
|
// The user wants to clear all the breakpoint
|
|
ClearAllBreakpoints();
|
|
|
|
break;
|
|
|
|
case MENU_ID_CONTINUE:
|
|
// The user wants to continue execution (as opposed to
|
|
// single-stepping through the code). Unhilite all
|
|
// variables and tell the debugger server to continue.
|
|
if (m_controller)
|
|
{
|
|
if (m_controller->CanRestart())
|
|
{
|
|
m_controller->Start();
|
|
}
|
|
else
|
|
{
|
|
EnableToolsAndMenus(false);
|
|
LaunchWaitingDialog(_("Waiting for target (continue)..."));
|
|
m_controller->Countinue();
|
|
UnhilightCurrentLine();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MENU_ID_STEP_OVER:
|
|
// The user wants to step-over a function invocation (or
|
|
// just single-step). Unhilite all variables and tell the
|
|
// debugger server to step-over
|
|
EnableToolsAndMenus(false);
|
|
LaunchWaitingDialog(_("Waiting for target (step over)..."));
|
|
m_controller->StepOver();
|
|
UnhilightCurrentLine();
|
|
|
|
break;
|
|
|
|
case MENU_ID_STEP_INTO:
|
|
// The user wants to step-into a function invocation (or
|
|
// just single-step). Unhilite all variables and tell the
|
|
// debugger server to step-into
|
|
EnableToolsAndMenus(false);
|
|
LaunchWaitingDialog(_("Waiting for target (step into)..."));
|
|
m_controller->StepInto();
|
|
UnhilightCurrentLine();
|
|
|
|
break;
|
|
|
|
case MENU_ID_STOP:
|
|
EnableToolsAndMenus(false);
|
|
LaunchWaitingDialog(_("Waiting for target to stop execution..."));
|
|
m_controller->Stop();
|
|
UnhilightCurrentLine();
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnSelectFrame()
|
|
//
|
|
// This function handles the user click on one of the stack-frames, and
|
|
// asks the debugger server to switch to that frame, update the breakpoint
|
|
// markers, and send a list of variables that are in-scope in the selected
|
|
// frame
|
|
//
|
|
// Parametes:
|
|
// Selection Event Object
|
|
//
|
|
void frmDebugger::OnSelectFrame(wxCommandEvent &_ev)
|
|
{
|
|
if(_ev.GetSelection() != -1)
|
|
{
|
|
if (!m_controller->SelectFrame(_ev.GetSelection()))
|
|
{
|
|
// Reset to previous selection
|
|
dbgModel *model = m_controller->GetModel();
|
|
m_stackWindow->SelectFrame(model->GetDisplayedPackage(),
|
|
model->GetDisplayedFunction());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnMarginClick()
|
|
//
|
|
// This function handles the user clicks in the margin to the left of a
|
|
// line of source code. We use the margin to display breakpoint indicators
|
|
// so it makes sense that if you click on an breakpoint indicator, we will
|
|
// clear that breakpoint. If you click on a spot that does not contain a
|
|
// breakpoint indicator (but it's still in the margin), we create a new
|
|
// breakpoint at that line
|
|
//
|
|
// Parametes:
|
|
// Selection Event Object
|
|
//
|
|
void frmDebugger::OnMarginClick(wxStyledTextEvent &event)
|
|
{
|
|
int lineNo;
|
|
|
|
// Check that the user clicked on the line number or breakpoint margin
|
|
// We don't want to set a breakpoint when the user folds/unfolds code
|
|
if (!(event.GetMargin() == 0 || event.GetMargin() == 1))
|
|
return;
|
|
|
|
lineNo = m_codeViewer->LineFromPosition(event.GetPosition());
|
|
|
|
if (lineNo <= 0)
|
|
return;
|
|
|
|
// If we already have a breakpoint at the clickpoint, disable it, otherwise
|
|
// create a new breakpoint
|
|
if(m_codeViewer->MarkerGet(lineNo) &
|
|
MARKERINDEX_TO_MARKERMASK(MARKER_BREAKPOINT))
|
|
{
|
|
m_controller->ClearBreakpoint(lineNo);
|
|
}
|
|
else
|
|
{
|
|
m_controller->SetBreakpoint(lineNo);
|
|
}
|
|
m_controller->UpdateBreakpoints();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnPositionStc()
|
|
//
|
|
// This function handles the event called when the user positions the cursor
|
|
// in the code viewer. We will update the current line number etc in the
|
|
// status bar.
|
|
//
|
|
// Parametes:
|
|
// wxStyledTextEvent Object
|
|
//
|
|
void frmDebugger::OnPositionStc(wxStyledTextEvent &event)
|
|
{
|
|
if (m_codeViewer)
|
|
{
|
|
wxString strPos;
|
|
|
|
int pos = m_codeViewer->GetCurrentPos();
|
|
|
|
strPos.Printf(_("Ln %d Col %d Ch %d"), m_codeViewer->LineFromPosition(pos) + 1,
|
|
m_codeViewer->GetColumn(pos) + 1, pos + 1);
|
|
|
|
GetStatusBar()->SetStatusText(strPos, 3);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnVarChange()
|
|
//
|
|
// This functions handles the event occurred when the user edits a variable
|
|
// value. Submit the changed value to the debugger server
|
|
//
|
|
void frmDebugger::OnVarChange(wxGridEvent &_ev)
|
|
{
|
|
ctlVarWindow *varWin = NULL;
|
|
wxString varName, varValue;
|
|
|
|
if(_ev.GetId() == ID_PARAMGRID)
|
|
{
|
|
varWin = GetParamWindow(false);
|
|
varName = varWin->GetVarName(_ev.GetRow());
|
|
varValue = varWin->GetVarValue(_ev.GetRow());
|
|
}
|
|
else if (_ev.GetId() == ID_VARGRID)
|
|
{
|
|
varWin = GetVarWindow(false);
|
|
varName = varWin->GetVarName(_ev.GetRow());
|
|
varValue = varWin->GetVarValue(_ev.GetRow());
|
|
}
|
|
else if (_ev.GetId() == ID_PKGVARGRID)
|
|
{
|
|
varWin = GetPkgVarWindow(false);
|
|
varName = wxT("@") + varWin->GetVarName(_ev.GetRow());
|
|
varValue = varWin->GetVarValue(_ev.GetRow());
|
|
}
|
|
else
|
|
{
|
|
// Theorically - the execution flow must not reach at this point.
|
|
return;
|
|
}
|
|
|
|
m_controller->DepositValue(varName, varValue);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnSize()
|
|
//
|
|
// This event handler is called when a resize event occurs (that is, when
|
|
// wxWidgets needs to size the application window)
|
|
//
|
|
void frmDebugger::OnSize(wxSizeEvent &event)
|
|
{
|
|
event.Skip();
|
|
}
|
|
|
|
|
|
void frmDebugger::OnEraseBackground(wxEraseEvent &event)
|
|
{
|
|
event.Skip();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// setupToolBar()
|
|
//
|
|
// This function creates the standard toolbar
|
|
//
|
|
ctlMenuToolbar *frmDebugger::SetupToolBar(void)
|
|
{
|
|
m_toolBar = new ctlMenuToolbar(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTB_FLAT | wxTB_NODIVIDER);
|
|
|
|
m_toolBar->SetToolBitmapSize(wxSize(16, 16));
|
|
|
|
m_toolBar->AddTool(MENU_ID_STEP_INTO, wxEmptyString, *stepInto_png_bmp,
|
|
_("Step into"));
|
|
m_toolBar->AddTool(MENU_ID_STEP_OVER, wxEmptyString, *stepOver_png_bmp,
|
|
_("Step over"));
|
|
m_toolBar->AddTool(MENU_ID_CONTINUE, wxEmptyString, *continue_png_bmp,
|
|
_("Continue/Start"));
|
|
m_toolBar->AddSeparator();
|
|
m_toolBar->AddTool(MENU_ID_TOGGLE_BREAK, wxEmptyString, *setBreak_png_bmp,
|
|
_("Toggle breakpoint"));
|
|
m_toolBar->AddTool(MENU_ID_CLEAR_ALL_BREAK, wxEmptyString, *clearAll_png_bmp,
|
|
_("Clear all breakpoints"));
|
|
m_toolBar->AddSeparator();
|
|
m_toolBar->AddTool(MENU_ID_STOP, wxEmptyString, *stop_png_bmp,
|
|
_("Stop debugging"));
|
|
|
|
m_toolBar->EnableTool(MENU_ID_STEP_INTO, false);
|
|
m_toolBar->EnableTool(MENU_ID_STEP_OVER, false);
|
|
m_toolBar->EnableTool(MENU_ID_CONTINUE, false);
|
|
m_toolBar->EnableTool(MENU_ID_TOGGLE_BREAK, false);
|
|
m_toolBar->EnableTool(MENU_ID_CLEAR_ALL_BREAK, false);
|
|
m_toolBar->EnableTool(MENU_ID_STOP, false);
|
|
|
|
m_toolBar->Realize();
|
|
|
|
return(m_toolBar);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// SetupStatusBar()
|
|
//
|
|
// This function initializes the status bar (we don't have one at the moment
|
|
// so this function simply returns)
|
|
//
|
|
ctlProgressStatusBar *frmDebugger::SetupStatusBar(void)
|
|
{
|
|
ctlProgressStatusBar *bar = new ctlProgressStatusBar(this, false);
|
|
int widths[] = { -1, ctlProgressStatusBar::ms_progressbar_width, ctlProgressStatusBar::ms_progressstatus_width, 190};
|
|
|
|
bar->SetFieldsCount(4);
|
|
bar->SetStatusWidths(4, widths);
|
|
this->SetStatusBar(bar);
|
|
|
|
return(bar);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// SetupMenuBar()
|
|
//
|
|
// This function creates the standard menu bar
|
|
//
|
|
wxMenuBar *frmDebugger::SetupMenuBar(void)
|
|
{
|
|
m_menuBar = new wxMenuBar;
|
|
|
|
// Don't append the File menu on Mac, as the Exit option
|
|
// will be moved to the application menu, leaving File empty.
|
|
#ifndef __WXMAC__
|
|
wxMenu *fileMenu = new wxMenu;
|
|
fileMenu->Append(MNU_EXIT, _("E&xit\tAlt-F4"), _("Exit debugger window"));
|
|
|
|
m_menuBar->Append(fileMenu, _("&File"));
|
|
#endif
|
|
|
|
m_debugMenu = new wxMenu;
|
|
#ifdef __WXGTK__
|
|
//
|
|
// F10 is treated as a System menu under GTK. Hence, we will use Ctrl+F10 for
|
|
// "step over" operation under GTK, instead of F10.
|
|
//
|
|
// To make the behavior consitent, we will also use Ctrl+ for all the operations
|
|
// under GTK. (i.e. Step into, Step over, Continue, Toggle breakpoint, Stop
|
|
// debugging)
|
|
//
|
|
// Please follow this link for more details:
|
|
// http://trac.wxwidgets.org/ticket/2404
|
|
//
|
|
m_debugMenu->Append(MENU_ID_STEP_INTO, _("Step into\tCtrl+F11"));
|
|
m_debugMenu->Append(MENU_ID_STEP_OVER, _("Step over\tCtrl+F10"));
|
|
m_debugMenu->Append(MENU_ID_CONTINUE, _("Continue/Start\tCtrl+F5"));
|
|
m_debugMenu->AppendSeparator();
|
|
m_debugMenu->Append(MENU_ID_TOGGLE_BREAK, _("Toggle breakpoint\tCtrl+F9"));
|
|
m_debugMenu->Append(MENU_ID_CLEAR_ALL_BREAK, _("Clear all breakpoints\tCtrl+Shift+F9"));
|
|
m_debugMenu->AppendSeparator();
|
|
m_debugMenu->Append(MENU_ID_STOP, _("Stop debugging\tCtrl+F8"));
|
|
#else
|
|
m_debugMenu->Append(MENU_ID_STEP_INTO, _("Step into\tF11"));
|
|
m_debugMenu->Append(MENU_ID_STEP_OVER, _("Step over\tF10"));
|
|
m_debugMenu->Append(MENU_ID_CONTINUE, _("Continue/Start\tF5"));
|
|
m_debugMenu->AppendSeparator();
|
|
m_debugMenu->Append(MENU_ID_TOGGLE_BREAK, _("Toggle breakpoint\tF9"));
|
|
m_debugMenu->Append(MENU_ID_CLEAR_ALL_BREAK, _("Clear all breakpoints\tCtrl+Shift+F9"));
|
|
m_debugMenu->AppendSeparator();
|
|
m_debugMenu->Append(MENU_ID_STOP, _("Stop debugging\tF8"));
|
|
#endif //__WXGTK__
|
|
m_debugMenu->Enable(MENU_ID_STEP_INTO, false);
|
|
m_debugMenu->Enable(MENU_ID_STEP_OVER, false);
|
|
m_debugMenu->Enable(MENU_ID_CONTINUE, false);
|
|
m_debugMenu->Enable(MENU_ID_TOGGLE_BREAK, false);
|
|
m_debugMenu->Enable(MENU_ID_CLEAR_ALL_BREAK, false);
|
|
m_debugMenu->Enable(MENU_ID_STOP, false);
|
|
m_menuBar->Append(m_debugMenu, _("&Debug"));
|
|
|
|
m_viewMenu = new wxMenu;
|
|
m_viewMenu->Append(MENU_ID_VIEW_OUTPUTPANE, _("&Output pane\tCtrl-Alt-O"), _("Show or hide the output pane."), wxITEM_CHECK);
|
|
m_viewMenu->Append(MENU_ID_VIEW_STACKPANE, _("&Stack pane\tCtrl-Alt-S"), _("Show or hide the stack pane."), wxITEM_CHECK);
|
|
m_viewMenu->Append(MENU_ID_VIEW_TOOLBAR, _("&Tool bar\tCtrl-Alt-T"), _("Show or hide the tool bar."), wxITEM_CHECK);
|
|
m_viewMenu->AppendSeparator();
|
|
m_viewMenu->Append(MENU_ID_VIEW_DEFAULTVIEW, _("&Default view\tCtrl-Alt-V"), _("Restore the default view."));
|
|
m_viewMenu->Enable(MENU_ID_VIEW_OUTPUTPANE, false);
|
|
m_viewMenu->Enable(MENU_ID_VIEW_STACKPANE, false);
|
|
m_menuBar->Append(m_viewMenu, _("&View"));
|
|
|
|
wxMenu *helpMenu = new wxMenu();
|
|
helpMenu->Append(MNU_CONTENTS, _("&Help"), _("Open the helpfile."));
|
|
helpMenu->Append(MNU_HELP, _("&SQL Help\tF1"), _("Display help on SQL commands."));
|
|
m_menuBar->Append(helpMenu, _("&Help"));
|
|
|
|
SetMenuBar(m_menuBar);
|
|
|
|
return(m_menuBar);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnClose()
|
|
//
|
|
// wxWidgets invokes this event handler when the user closes the main window
|
|
|
|
void frmDebugger::OnClose(wxCloseEvent &_ev)
|
|
{
|
|
if (!m_controller->CanRestart() && _ev.CanVeto())
|
|
{
|
|
if (wxMessageBox(
|
|
_("Are you sure you wish to abort the debugging session?\nThis will abort the function currently being debugged."),
|
|
_("Close debugger"), wxICON_QUESTION | wxYES_NO) != wxYES)
|
|
{
|
|
_ev.Veto();
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!m_controller->CloseDebugger() && _ev.CanVeto())
|
|
{
|
|
_ev.Veto();
|
|
|
|
return;
|
|
}
|
|
|
|
_ev.Skip();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnExit()
|
|
//
|
|
// Close the debugger
|
|
|
|
void frmDebugger::OnExit(wxCommandEvent &event)
|
|
{
|
|
Close();
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnToggleToolBar()
|
|
//
|
|
// Turn the tool bar on or off
|
|
void frmDebugger::OnToggleToolBar(wxCommandEvent &event)
|
|
{
|
|
if (m_viewMenu->IsChecked(MENU_ID_VIEW_TOOLBAR))
|
|
m_manager.GetPane(wxT("toolBar")).Show(true);
|
|
else
|
|
m_manager.GetPane(wxT("toolBar")).Show(false);
|
|
|
|
m_manager.Update();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnToggleStackPane()
|
|
//
|
|
// Turn the tool bar on or off
|
|
void frmDebugger::OnToggleStackPane(wxCommandEvent &event)
|
|
{
|
|
if (m_viewMenu->IsChecked(MENU_ID_VIEW_STACKPANE))
|
|
m_manager.GetPane(wxT("stackPane")).Show(true);
|
|
else
|
|
m_manager.GetPane(wxT("stackPane")).Show(false);
|
|
|
|
m_manager.Update();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnToggleOutputPane()
|
|
//
|
|
// Turn the tool bar on or off
|
|
void frmDebugger::OnToggleOutputPane(wxCommandEvent &event)
|
|
{
|
|
if (m_viewMenu->IsChecked(MENU_ID_VIEW_OUTPUTPANE))
|
|
m_manager.GetPane(wxT("outputPane")).Show(true);
|
|
else
|
|
m_manager.GetPane(wxT("outputPane")).Show(false);
|
|
|
|
m_manager.Update();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnAuiUpdate()
|
|
//
|
|
// Update the view menu to reflect AUI changes
|
|
void frmDebugger::OnAuiUpdate(wxAuiManagerEvent &event)
|
|
{
|
|
if(event.pane->name == wxT("toolBar"))
|
|
{
|
|
m_viewMenu->Check(MENU_ID_VIEW_TOOLBAR, false);
|
|
}
|
|
else if(event.pane->name == wxT("stackPane"))
|
|
{
|
|
m_viewMenu->Check(MENU_ID_VIEW_STACKPANE, false);
|
|
}
|
|
else if(event.pane->name == wxT("outputPane"))
|
|
{
|
|
m_viewMenu->Check(MENU_ID_VIEW_OUTPUTPANE, false);
|
|
}
|
|
event.Skip();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// OnDefaultView()
|
|
//
|
|
// Reset the AUI view to the default
|
|
void frmDebugger::OnDefaultView(wxCommandEvent &event)
|
|
{
|
|
m_manager.LoadPerspective(FRMDEBUGGER_DEFAULT_PERSPECTIVE, true);
|
|
|
|
// Reset the captions for the current language
|
|
m_manager.GetPane(wxT("toolBar")).Caption(_("Toolbar"));
|
|
m_manager.GetPane(wxT("stackPane")).Caption(_("Stack pane"));
|
|
m_manager.GetPane(wxT("outputPane")).Caption(_("Output pane"));
|
|
|
|
// tell the m_manager to "commit" all the changes just made
|
|
m_manager.Update();
|
|
|
|
// Sync the View menu options
|
|
m_viewMenu->Check(MENU_ID_VIEW_TOOLBAR, m_manager.GetPane(wxT("toolBar")).IsShown());
|
|
m_viewMenu->Check(MENU_ID_VIEW_STACKPANE, m_manager.GetPane(wxT("stackPane")).IsShown());
|
|
m_viewMenu->Check(MENU_ID_VIEW_OUTPUTPANE, m_manager.GetPane(wxT("outputPane")).IsShown());
|
|
}
|
|
|
|
|
|
void frmDebugger::HighlightLine(int _lineNo)
|
|
{
|
|
int lineNo = m_codeViewer->MarkerNext(
|
|
0, MARKERINDEX_TO_MARKERMASK( MARKER_CURRENT));
|
|
|
|
if (lineNo != -1)
|
|
{
|
|
m_codeViewer->MarkerDelete(lineNo, MARKER_CURRENT);
|
|
m_codeViewer->MarkerDelete(lineNo, MARKER_CURRENT_BG);
|
|
}
|
|
|
|
// Add the current-line indicator to the current line of code
|
|
m_codeViewer->MarkerAdd(_lineNo, MARKER_CURRENT);
|
|
m_codeViewer->MarkerAdd(_lineNo, MARKER_CURRENT_BG);
|
|
|
|
// Scroll the source code listing (if required) to make sure
|
|
// that this line of code is visible
|
|
//
|
|
// (NOTE: we set the anchor and the caret to the same position to avoid
|
|
// creating a selection region)
|
|
int pos = m_codeViewer->PositionFromLine(_lineNo);
|
|
|
|
m_codeViewer->SetAnchor(pos);
|
|
m_codeViewer->SetCurrentPos(pos);
|
|
|
|
m_codeViewer->EnsureCaretVisible();
|
|
}
|
|
|
|
void frmDebugger::DisplaySource(dbgCachedStack &_cached)
|
|
{
|
|
dbgModel *model = m_controller->GetModel();
|
|
|
|
m_codeViewer->SetFocus();
|
|
|
|
if (model->RequireDisplayUpdate())
|
|
{
|
|
ctlVarWindow *varWin = NULL;
|
|
if ((varWin = GetVarWindow(false)) != NULL)
|
|
{
|
|
varWin->DelVar();
|
|
}
|
|
if ((varWin = GetParamWindow(false)) != NULL)
|
|
{
|
|
varWin->DelVar();
|
|
}
|
|
if ((varWin = GetPkgVarWindow(false)) != NULL)
|
|
{
|
|
varWin->DelVar();
|
|
}
|
|
|
|
model->GetDisplayedFunction() = _cached.m_func;
|
|
model->GetDisplayedPackage() = _cached.m_pkg;
|
|
|
|
// Now erase any old code and write out the new listing
|
|
m_codeViewer->SetReadOnly(false);
|
|
|
|
m_codeViewer->SetText(_cached.m_source);
|
|
m_codeViewer->Colourise(0, _cached.m_source.Length());
|
|
|
|
m_codeViewer->SetReadOnly(true);
|
|
}
|
|
HighlightLine(model->GetCurrLineNo());
|
|
}
|
|
|
|
|
|
void frmDebugger::SetStatusText(const wxString &_status)
|
|
{
|
|
m_statusBar->SetStatusText(_status, 0);
|
|
}
|
|
|
|
|
|
void frmDebugger::LaunchWaitingDialog(const wxString &msg)
|
|
{
|
|
dbgModel *model = m_controller->GetModel();
|
|
wxString strStatus,
|
|
strTargetPid = model->GetTargetPid(),
|
|
strTarget = model->GetTarget()->GetQualifiedName();
|
|
|
|
if (msg.IsEmpty())
|
|
{
|
|
if (strTargetPid != wxT("NULL"))
|
|
{
|
|
strStatus =
|
|
wxString::Format(
|
|
_("Waiting for the session (pid:%s) to invoke the specified targets."),
|
|
strTargetPid.c_str());
|
|
}
|
|
else
|
|
{
|
|
strStatus =
|
|
wxString::Format(
|
|
_("Waiting for another session to invoke the target - \"%s\""), strTarget.c_str());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strStatus = msg;
|
|
}
|
|
m_statusTxt = strStatus;
|
|
|
|
SetStatusText(strStatus);
|
|
m_statusBar->ShowProgress();
|
|
}
|
|
|
|
|
|
void frmDebugger::CloseProgressBar()
|
|
{
|
|
if (!m_statusTxt.IsEmpty())
|
|
{
|
|
SetStatusText(m_statusTxt + wxT(" Done"));
|
|
m_statusTxt = wxT("");
|
|
}
|
|
m_statusBar->StopProgress();
|
|
}
|