text: //////////////////////////////////////////////////////////////////////////
  //
  // 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);
  		}
  		else
  		{
  			strStatus =
  			    wxString::Format(
  			        _("Waiting for another session to invoke the target - \"%s\""), strTarget);
  		}
  	}
  	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();
  }
  