pgadmin3/debugger/frmDebugger.cpp
2019-01-09 07:25:44 +05:00

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();
}