mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 06:05:49 -06:00
Падение приложения при перемещении по дереву объектов, если включено отображение имени БД.
1338 lines
34 KiB
C++
1338 lines
34 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin III - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
// events.cpp - Event handlers for frmMain
|
|
//
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "pgAdmin3.h"
|
|
|
|
// wxWindows headers
|
|
#include <wx/wx.h>
|
|
#include <wx/settings.h>
|
|
#include <wx/treectrl.h>
|
|
#include <wx/listctrl.h>
|
|
#include <wx/imaglist.h>
|
|
#include <wx/stc/stc.h>
|
|
#include <wx/busyinfo.h>
|
|
#include <wx/aui/aui.h>
|
|
|
|
// App headers
|
|
#include "utils/misc.h"
|
|
#include "frm/menu.h"
|
|
#include "frm/frmMain.h"
|
|
#include "frm/frmOptions.h"
|
|
#include "ctl/ctlSQLBox.h"
|
|
#include "ctl/ctlMenuToolbar.h"
|
|
#include "db/pgConn.h"
|
|
#include "schema/pgDatabase.h"
|
|
#include "db/pgSet.h"
|
|
#include "schema/pgServer.h"
|
|
#include "schema/pgObject.h"
|
|
#include "schema/pgCollection.h"
|
|
#include "schema/pgTable.h"
|
|
#include "schema/edbPrivateSynonym.h"
|
|
#include "dlg/dlgProperty.h"
|
|
#include "ctl/ctlShortCut.h"
|
|
|
|
// Mutex to protect the "currentObject" from race conditions.
|
|
//
|
|
static wxMutex s_currentObjectMutex;
|
|
|
|
// Event table
|
|
BEGIN_EVENT_TABLE(frmMain, pgFrame)
|
|
EVT_CHILD_FOCUS( frmMain::OnChildFocus)
|
|
EVT_ERASE_BACKGROUND( frmMain::OnEraseBackground)
|
|
EVT_SIZE( frmMain::OnSize)
|
|
EVT_MENU(MNU_ACTION, frmMain::OnAction)
|
|
|
|
EVT_MENU(MNU_COPY, frmMain::OnCopy)
|
|
EVT_MENU(MNU_DELETE, frmMain::OnDelete)
|
|
EVT_MENU(MNU_SAVEDEFINITION, frmMain::OnSaveDefinition)
|
|
EVT_MENU(MNU_SQLPANE, frmMain::OnToggleSqlPane)
|
|
EVT_MENU(MNU_OBJECTBROWSER, frmMain::OnToggleObjectBrowser)
|
|
EVT_MENU(MNU_TOOLBAR, frmMain::OnToggleToolBar)
|
|
EVT_MENU(MNU_DEFAULTVIEW, frmMain::OnDefaultView)
|
|
EVT_MENU(MNU_CHECKALIVE, frmMain::OnCheckAlive)
|
|
EVT_MENU(MNU_CONTEXTMENU, frmMain::OnContextMenu)
|
|
EVT_MENU(MNU_SHORTCUT, frmMain::OnShortCut)
|
|
|
|
EVT_AUINOTEBOOK_PAGE_CHANGED(wxID_ANY, frmMain::OnPageChange)
|
|
EVT_LIST_ITEM_SELECTED(CTL_PROPVIEW, frmMain::OnPropSelChanged)
|
|
EVT_LIST_ITEM_ACTIVATED(CTL_PROPVIEW, frmMain::OnPropSelActivated)
|
|
EVT_LIST_ITEM_RIGHT_CLICK(CTL_PROPVIEW, frmMain::OnPropRightClick)
|
|
EVT_LIST_ITEM_SELECTED(CTL_STATVIEW, frmMain::OnStatSelChanged)
|
|
EVT_LIST_ITEM_RIGHT_CLICK(CTL_STATVIEW, frmMain::OnStatRightClick)
|
|
// EVT_LIST_ITEM_SELECTED(CTL_STATVIEW, frmMain::OnSelectItem)
|
|
EVT_LIST_ITEM_SELECTED(CTL_DEPVIEW, frmMain::OnSelectItem)
|
|
EVT_LIST_ITEM_SELECTED(CTL_REFVIEW, frmMain::OnSelectItem)
|
|
EVT_TREE_SEL_CHANGED(CTL_BROWSER, frmMain::OnTreeSelChanged)
|
|
EVT_TREE_ITEM_EXPANDING(CTL_BROWSER, frmMain::OnExpand)
|
|
EVT_TREE_ITEM_COLLAPSING(CTL_BROWSER, frmMain::OnCollapse)
|
|
EVT_TREE_ITEM_ACTIVATED(CTL_BROWSER, frmMain::OnSelActivated)
|
|
EVT_TREE_ITEM_RIGHT_CLICK(CTL_BROWSER, frmMain::OnSelRightClick)
|
|
EVT_TREE_ITEM_GETTOOLTIP(CTL_BROWSER, frmMain::OnBrowserToolTip)
|
|
EVT_STC_UPDATEUI(CTL_SQLPANE, frmMain::OnPositionStc)
|
|
EVT_CLOSE( frmMain::OnClose)
|
|
|
|
EVT_AUI_PANE_CLOSE( frmMain::OnAuiUpdate)
|
|
EVT_AUINOTEBOOK_PAGE_CLOSE(wxID_ANY, frmMain::OnAuiNotebookPageClose)
|
|
|
|
#ifdef __WXGTK__
|
|
EVT_TREE_KEY_DOWN(CTL_BROWSER, frmMain::OnTreeKeyDown)
|
|
#endif
|
|
|
|
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
|
|
EVT_COMMAND (wxID_ANY, SSH_TUNNEL_ERROR_EVENT, frmMain::OnSSHTunnelEvent)
|
|
#endif
|
|
|
|
END_EVENT_TABLE()
|
|
|
|
void frmMain::OnChildFocus(wxChildFocusEvent &event)
|
|
{
|
|
// Grab the focussed control and stash it away for later use
|
|
currentControl = dynamic_cast<wxControl *>(event.GetEventObject());
|
|
|
|
// Setup the menu controls according to the control that's selected
|
|
// and it's status.
|
|
|
|
// Defaults.
|
|
editMenu->Enable(MNU_COPY, false);
|
|
|
|
// ctlSQLBox?
|
|
ctlSQLBox *sb = dynamic_cast<ctlSQLBox *>(event.GetEventObject());
|
|
if (sb)
|
|
{
|
|
// Copy
|
|
editMenu->Enable(MNU_COPY, !sb->GetSelectedText().IsEmpty());
|
|
}
|
|
|
|
// Listview?
|
|
ctlListView *lv = dynamic_cast<ctlListView *>(event.GetEventObject());
|
|
if (lv)
|
|
{
|
|
// Copy
|
|
editMenu->Enable(MNU_COPY, lv->GetSelectedItemCount() > 0);
|
|
}
|
|
}
|
|
|
|
void frmMain::OnEraseBackground(wxEraseEvent &event)
|
|
{
|
|
event.Skip();
|
|
}
|
|
|
|
void frmMain::OnSize(wxSizeEvent &event)
|
|
{
|
|
event.Skip();
|
|
}
|
|
|
|
// unfortunately, under GTK we won't get the original wxKeyEvent
|
|
// to reset m_metaDown
|
|
void frmMain::OnTreeKeyDown(wxTreeEvent &event)
|
|
{
|
|
int keyCode = event.GetKeyCode();
|
|
switch (keyCode)
|
|
{
|
|
case WXK_F1:
|
|
OnHelp(event);
|
|
break;
|
|
case WXK_F5:
|
|
Refresh(currentObject);
|
|
break;
|
|
case WXK_DELETE:
|
|
OnDelete(event);
|
|
break;
|
|
// Is tempting to write all cases(this handler) in tree control itself
|
|
case WXK_LEFT:
|
|
case WXK_RIGHT:
|
|
browser->NavigateTree(keyCode);
|
|
break;
|
|
default:
|
|
event.Skip();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void frmMain::OnExit(wxCommandEvent &event)
|
|
{
|
|
Close(false); // Allow sub windows to stop us
|
|
event.Skip();
|
|
}
|
|
|
|
|
|
|
|
void frmMain::OnClose(wxCloseEvent &event)
|
|
{
|
|
wxWindow *fr;
|
|
windowList::Node *node;
|
|
while ((node = frames.GetFirst()) != NULL)
|
|
{
|
|
fr = node->GetData();
|
|
|
|
// if crashes occur here when closing the app,
|
|
// some actionFactory::StartDialog returned a wxWindow* (which is registered in frames)
|
|
// without code to handle OnClose (esp. removing itself with RemoveFrame)
|
|
|
|
if (!fr->Close(!event.CanVeto()))
|
|
{
|
|
if (event.CanVeto())
|
|
{
|
|
event.Veto();
|
|
return;
|
|
}
|
|
}
|
|
delete node;
|
|
fr->Destroy();
|
|
}
|
|
Destroy();
|
|
}
|
|
|
|
|
|
void frmMain::UpdateAllRecentFiles()
|
|
{
|
|
wxWindow *fr;
|
|
windowList::Node *node;
|
|
node = frames.GetFirst();
|
|
while (node)
|
|
{
|
|
fr = node->GetData();
|
|
((frmQuery *)fr)->UpdateRecentFiles(false);
|
|
node = node->GetNext();
|
|
}
|
|
}
|
|
|
|
|
|
void frmMain::UpdateAllFavouritesList()
|
|
{
|
|
wxWindow *fr;
|
|
windowList::Node *node;
|
|
node = frames.GetFirst();
|
|
while (node)
|
|
{
|
|
fr = node->GetData();
|
|
((frmQuery *)fr)->UpdateFavouritesList();
|
|
node = node->GetNext();
|
|
}
|
|
}
|
|
|
|
void frmMain::UpdateAllMacrosList()
|
|
{
|
|
wxWindow *fr;
|
|
windowList::Node *node;
|
|
node = frames.GetFirst();
|
|
while (node)
|
|
{
|
|
fr = node->GetData();
|
|
((frmQuery *)fr)->UpdateMacrosList();
|
|
node = node->GetNext();
|
|
}
|
|
}
|
|
|
|
|
|
void frmMain::OnAction(wxCommandEvent &ev)
|
|
{
|
|
if (currentObject) {
|
|
actionFactory *af = menuFactories->GetFactory(ev.GetId());
|
|
if (af)
|
|
{
|
|
wxWindow *wnd = af->StartDialog(this, currentObject);
|
|
if (wnd)
|
|
AddFrame(wnd);
|
|
}
|
|
}
|
|
}
|
|
|
|
wxString frmMain::GetHelpPage() const
|
|
{
|
|
wxString page;
|
|
|
|
if (currentObject)
|
|
page = currentObject->GetHelpPage(true);
|
|
|
|
if (page.IsEmpty())
|
|
page = wxT("pg/sql-commands");
|
|
|
|
return page;
|
|
}
|
|
|
|
void frmMain::OnCollapse(wxTreeEvent &event)
|
|
{
|
|
#ifdef WIN32
|
|
// This is weird stuff, but somewhere comes a collapse after we have done
|
|
// connecting the server and expanding the tree.
|
|
// Possibly not necessary
|
|
if (event.GetItem() == denyCollapseItem)
|
|
event.Veto();
|
|
#endif
|
|
denyCollapseItem = wxTreeItemId();
|
|
}
|
|
|
|
|
|
void frmMain::OnExpand(wxTreeEvent &event)
|
|
{
|
|
wxCookieType cookie;
|
|
wxTreeItemId item = browser->GetFirstChild(event.GetItem(), cookie);
|
|
if (item && !browser->GetItemData(item))
|
|
{
|
|
// the expanding node has a dummy item.
|
|
// delete dummy item, and expand kids.
|
|
execSelChange(event.GetItem(), browser->GetSelection() == item);
|
|
|
|
// we don't have any kids, so don't expand
|
|
if (!browser->GetChildrenCount(event.GetItem()))
|
|
event.Veto();
|
|
}
|
|
}
|
|
|
|
|
|
void frmMain::OnCheckAlive(wxCommandEvent &event)
|
|
{
|
|
CheckAlive();
|
|
}
|
|
|
|
|
|
void frmMain::OnStatRightClick(wxListEvent& event)
|
|
{
|
|
OnStatSelChanged(event);
|
|
|
|
if (currentObject)
|
|
doPopup(statistics, event.GetPoint(), currentObject);
|
|
}
|
|
void frmMain::OnStatSelChanged(wxListEvent& event)
|
|
{
|
|
if (statistics->GetSelectedItemCount() == 1)
|
|
{
|
|
int key = event.GetKeyCode();
|
|
wxTreeItemId item = browser->GetSelection();
|
|
if (item)
|
|
{
|
|
wxString table = statistics->GetItemText(event.GetIndex(), 0);
|
|
wxCookieType cookie;
|
|
wxTreeItemId idstop;
|
|
//if (!idstop.IsOk()) return;
|
|
wxTreeItemId p = item;
|
|
wxTreeItemId toFind;
|
|
do
|
|
{
|
|
toFind = browser->GetNextSibling(p);
|
|
p = browser->GetItemParent(p);
|
|
} while (p.IsOk() && !toFind.IsOk());
|
|
idstop = toFind;
|
|
|
|
//item = browser->GetFirstChild(item, cookie);
|
|
wxTreeItemId id = item;
|
|
wxString fn = "";
|
|
while (id.IsOk()) {
|
|
pgObject* oo = ((pgObject*)browser->GetItemData(id));
|
|
if (oo) {
|
|
pgaFactory* ff = oo->GetFactory();
|
|
wxString typen = ff->GetTypeName();
|
|
fn = oo->GetName();
|
|
bool isChilds = typen == wxT("Tables") || typen == wxT("Partitions");
|
|
if (typen == wxT("Table")|| typen == wxT("TABLE") && ((((pgTable*)oo)->GetIsPartitioned()))) isChilds = true;
|
|
if (fn == table) {
|
|
break;
|
|
}
|
|
if (browser->HasChildren(id) && ( isChilds)
|
|
)
|
|
{
|
|
if (oo) oo->ShowTreeDetail(browser);
|
|
id = browser->GetFirstChild(id, cookie);
|
|
}
|
|
else
|
|
{
|
|
// Try a sibling of this or ancestor instead
|
|
wxTreeItemId p = id;
|
|
wxTreeItemId toFind;
|
|
do
|
|
{
|
|
toFind = browser->GetNextSibling(p);
|
|
p = browser->GetItemParent(p);
|
|
} while (p.IsOk() && !toFind.IsOk());
|
|
id = toFind;
|
|
if (id == idstop) break;
|
|
}
|
|
|
|
} else
|
|
break;
|
|
|
|
}
|
|
if (id == idstop || !id.IsOk()) return;
|
|
|
|
pgObject* data = browser->GetObject(id);
|
|
if (data )
|
|
{
|
|
currentObject = data;
|
|
setDisplay(currentObject,0,0,false);
|
|
sqlPane->SetReadOnly(false);
|
|
sqlPane->SetText(currentObject->GetSql(browser));
|
|
sqlPane->SetReadOnly(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void frmMain::OnPropSelChanged(wxListEvent &event)
|
|
{
|
|
if (properties->GetSelectedItemCount() == 1)
|
|
{
|
|
wxTreeItemId item = browser->GetSelection();
|
|
if (item)
|
|
{
|
|
pgObject *data = browser->GetObject(item);
|
|
if (data && data->IsCollection())
|
|
{
|
|
currentObject = ((pgCollection *)data)->FindChild(browser, event.GetIndex());
|
|
if (currentObject)
|
|
{
|
|
setDisplay(currentObject);
|
|
sqlPane->SetReadOnly(false);
|
|
sqlPane->SetText(currentObject->GetSql(browser));
|
|
sqlPane->SetReadOnly(true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
editMenu->Enable(MNU_COPY, properties->GetSelectedItemCount() > 0);
|
|
|
|
// The generic list view control on the Mac doesn't fire focus events
|
|
// as it should, so we set currentControl here instead of relying on
|
|
// the ChildFocusEvent. The native list view does fire the events, but
|
|
// does weird things with multi-select items so we currently disable
|
|
// it (see the creation of the listviews in frmMain.cpp).
|
|
#ifdef __WXMAC__
|
|
currentControl = properties;
|
|
#endif
|
|
}
|
|
|
|
|
|
void frmMain::OnSelectItem(wxListEvent &event)
|
|
{
|
|
ctlListView *list;
|
|
|
|
switch(listViews->GetSelection())
|
|
{
|
|
case NBP_STATISTICS:
|
|
list = statistics;
|
|
break;
|
|
case NBP_DEPENDENCIES:
|
|
list = dependencies;
|
|
break;
|
|
case NBP_DEPENDENTS:
|
|
list = dependents;
|
|
break;
|
|
default:
|
|
// This shouldn't happen.
|
|
// If it does, it's no big deal, we just need to get out.
|
|
return;
|
|
break;
|
|
}
|
|
|
|
editMenu->Enable(MNU_COPY, list->GetSelectedItemCount() > 0);
|
|
|
|
// The generic list view control on the Mac doesn't fire focus events
|
|
// as it should, so we set currentControl here instead of relying on
|
|
// the ChildFocusEvent. The native list view does fire the events, but
|
|
// does weird things with multi-select items so we currently disable
|
|
// it (see the creation of the listviews in frmMain.cpp).
|
|
#ifdef __WXMAC__
|
|
currentControl = list;
|
|
#endif
|
|
}
|
|
|
|
void frmMain::OnPropSelActivated(wxListEvent &event)
|
|
{
|
|
if (propFactory->CheckEnable(currentObject))
|
|
propFactory->StartDialog(this, currentObject);
|
|
}
|
|
|
|
|
|
void frmMain::OnPropRightClick(wxListEvent &event)
|
|
{
|
|
OnPropSelChanged(event);
|
|
|
|
if (currentObject)
|
|
doPopup(properties, event.GetPoint(), currentObject);
|
|
}
|
|
|
|
|
|
void frmMain::OnTreeSelChanged(wxTreeEvent &event)
|
|
{
|
|
/*
|
|
* Do not honour the tree selection change, while a property dialog is
|
|
* closed and refresh is in progress
|
|
*/
|
|
if (m_refreshing)
|
|
return;
|
|
|
|
denyCollapseItem = wxTreeItemId();
|
|
// Reset the listviews/SQL pane
|
|
if (event.GetItem()) {
|
|
execSelChange(event.GetItem(), true);
|
|
wxTreeItemId s=browser->GetSelection();
|
|
if (currentObject) {
|
|
int imgidx = browser->GetItemImage(s);
|
|
wxString path = wxString::Format("%4d", imgidx) + GetCurrentNodePath();
|
|
;
|
|
int p = shortcut.Index(path);
|
|
if (shortcut.GetCount() >= 50) shortcut.RemoveAt(shortcut.GetCount() - 1);
|
|
if (p != wxNOT_FOUND) shortcut.RemoveAt(p);
|
|
shortcut.Insert(path, 0);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// Reset the list controls
|
|
void frmMain::ResetLists()
|
|
{
|
|
properties->ClearAll();
|
|
properties->AddColumn(_("Properties"), properties->GetSize().GetWidth() - 10);
|
|
properties->InsertItem(0, _("No properties are available for the current selection"), PGICON_PROPERTY);
|
|
statistics->ClearAll();
|
|
statistics->AddColumn(_("Statistics"), properties->GetSize().GetWidth() - 10);
|
|
statistics->InsertItem(0, _("No statistics are available for the current selection"), PGICON_PROPERTY);
|
|
dependencies->ClearAll();
|
|
dependencies->AddColumn(_("Dependencies"), properties->GetSize().GetWidth() - 10);
|
|
dependencies->InsertItem(0, _("No dependency information is available for the current selection"), PGICON_PROPERTY);
|
|
dependents->ClearAll();
|
|
dependents->AddColumn(_("Dependents"), properties->GetSize().GetWidth() - 10);
|
|
dependents->InsertItem(0, _("No dependent information is available for the current selection"), PGICON_PROPERTY);
|
|
}
|
|
|
|
|
|
void frmMain::execSelChange(wxTreeItemId item, bool currentNode)
|
|
{
|
|
static bool refresh = true;
|
|
|
|
if (currentNode)
|
|
{
|
|
ResetLists();
|
|
sqlPane->Clear();
|
|
}
|
|
|
|
// Get the item data, and feed it to the relevant handler,
|
|
// cast as required.
|
|
//
|
|
// Lock the assignment to prevent the race conditions between onSelRightClick and execSelChange.
|
|
//
|
|
s_currentObjectMutex.Lock();
|
|
currentObject = browser->GetObject(item);
|
|
s_currentObjectMutex.Unlock();
|
|
|
|
// If we didn't get an object, then we may have a right click, or
|
|
// invalid click, so ignore.
|
|
if (!currentObject)
|
|
{
|
|
menuFactories->CheckMenu(currentObject, menuBar, toolBar);
|
|
}
|
|
else
|
|
{
|
|
int settingRefreshOnClick = settings->GetRefreshOnClick();
|
|
if (currentObject->NeedRefresh()) settingRefreshOnClick = REFRESH_OBJECT_ONLY;
|
|
|
|
if (settingRefreshOnClick != REFRESH_OBJECT_NONE
|
|
&& refresh
|
|
&& currentObject->GetTypeName() != wxT("Server")
|
|
&& currentObject->GetTypeName() != wxT("Servers")
|
|
&& currentObject->GetTypeName() != wxT("Database")
|
|
&& !currentObject->IsCollection())
|
|
{
|
|
refresh = false;
|
|
|
|
if (settingRefreshOnClick == REFRESH_OBJECT_ONLY )
|
|
{
|
|
// We can not update the schema, because it would cause an update to the entire tree.
|
|
if (currentObject->GetTypeName() != wxT("Schema"))
|
|
{
|
|
wxTreeItemId currentItem = currentObject->GetId();
|
|
|
|
// Do not refresh and instead bail out if dialog of the currently selected
|
|
// node or it's child node is open, as refresh would delete this node's object
|
|
// and could cause a crash
|
|
pgObject *obj = NULL;
|
|
if (currentItem)
|
|
obj = browser->GetObject(currentItem);
|
|
|
|
if (obj && obj->CheckOpenDialogs(browser, currentItem))
|
|
{
|
|
properties->Freeze();
|
|
setDisplay(currentObject, properties, sqlPane);
|
|
properties->Thaw();
|
|
refresh = true;
|
|
return;
|
|
}
|
|
|
|
pgObject *newData = currentObject->Refresh(browser, currentItem);
|
|
|
|
if (newData != 0)
|
|
{
|
|
wxLogInfo(wxT("Replacing with new node %s %s for refresh"), newData->GetTypeName().c_str(), newData->GetQuotedFullIdentifier().c_str());
|
|
|
|
browser->DeleteChildren(currentItem);
|
|
newData->SetId(currentItem); // not done automatically
|
|
browser->SetItemData(currentItem, newData);
|
|
|
|
// Update the node text if this is an object, as it may have been renamed
|
|
if (!newData->IsCollection())
|
|
browser->SetItemText(currentItem, newData->GetDisplayName());
|
|
|
|
delete currentObject;
|
|
currentObject = newData;
|
|
}
|
|
else
|
|
{
|
|
// OK, we failed to refresh, so select the parent and delete the child.
|
|
browser->SelectItem(browser->GetItemParent(currentItem));
|
|
browser->Delete(currentItem);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
Refresh(currentObject);
|
|
|
|
refresh = true;
|
|
}
|
|
|
|
|
|
if (currentNode)
|
|
{
|
|
properties->Freeze();
|
|
setDisplay(currentObject, properties, sqlPane);
|
|
properties->Thaw();
|
|
}
|
|
else
|
|
setDisplay(currentObject, 0, 0);
|
|
browser->DrawDbName(currentObject->GetId());
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void frmMain::setDisplay(pgObject *data, ctlListView *props, ctlSQLBox *sqlbox, bool showtree)
|
|
{
|
|
pgServer *server = 0;
|
|
|
|
|
|
bool showTree = false;
|
|
|
|
pgaFactory *factory = data->GetFactory();
|
|
if (factory)
|
|
{
|
|
if (factory == &serverFactory)
|
|
{
|
|
server = (pgServer *)data;
|
|
|
|
data->ShowTree(this, browser, props, sqlbox);
|
|
showTree = false;
|
|
}
|
|
else
|
|
showTree = true;
|
|
}
|
|
else
|
|
showTree = false;
|
|
|
|
if (showTree && showtree)
|
|
data->ShowTree(this, browser, props, sqlbox);
|
|
|
|
if (sqlbox)
|
|
{
|
|
sqlbox->SetReadOnly(false);
|
|
sqlbox->SetText(data->GetSql(browser));
|
|
sqlbox->SetReadOnly(true);
|
|
}
|
|
|
|
pgConn *conn = data->GetConnection();
|
|
if (conn && (conn->GetStatus() == PGCONN_BROKEN || conn->GetStatus() == PGCONN_BAD))
|
|
{
|
|
CheckAlive();
|
|
return;
|
|
}
|
|
|
|
unsigned int i;
|
|
wxMenuItem *menuItem;
|
|
i = newMenu->GetMenuItemCount();
|
|
while (i--)
|
|
{
|
|
menuItem = newMenu->GetMenuItems().Item(i)->GetData();
|
|
if (menuItem)
|
|
delete newMenu->Remove(menuItem);
|
|
}
|
|
|
|
i = newContextMenu->GetMenuItemCount();
|
|
while (i--)
|
|
{
|
|
menuItem = newContextMenu->GetMenuItems().Item(i)->GetData();
|
|
if (menuItem)
|
|
delete newContextMenu->Remove(menuItem);
|
|
}
|
|
|
|
editMenu->Enable(newMenuFactory->GetId(), false);
|
|
|
|
wxMenu *indivMenu = data->GetNewMenu();
|
|
if (indivMenu)
|
|
{
|
|
if (indivMenu->GetMenuItemCount())
|
|
{
|
|
editMenu->Enable(newMenuFactory->GetId(), true);
|
|
|
|
for (i = 0 ; i < indivMenu->GetMenuItemCount() ; i++)
|
|
{
|
|
menuItem = indivMenu->GetMenuItems().Item(i)->GetData();
|
|
#if wxCHECK_VERSION(2, 9, 0)
|
|
wxString lab = menuItem->GetItemLabelText();
|
|
#else
|
|
wxString lab = menuItem->GetLabel(); // deprecated
|
|
#endif
|
|
|
|
newMenu->Append(menuItem->GetId(), lab, menuItem->GetHelp());
|
|
newContextMenu->Append(menuItem->GetId(), lab, menuItem->GetHelp());
|
|
}
|
|
}
|
|
delete indivMenu;
|
|
}
|
|
|
|
menuFactories->CheckMenu(data, menuBar, toolBar);
|
|
|
|
menuFactories->EnableSubmenu(menuBar, MNU_CONFIGSUBMENU);
|
|
menuFactories->EnableSubmenu(menuBar, MNU_SLONY_SUBMENU);
|
|
}
|
|
|
|
|
|
void frmMain::OnSelActivated(wxTreeEvent &event)
|
|
{
|
|
// This handler will primarily deal with displaying item
|
|
// properties in seperate windows and 'Add xxx...' clicks
|
|
|
|
// Get the item data, and feed it to the relevant handler,
|
|
// cast as required.
|
|
|
|
wxTreeItemId item = event.GetItem();
|
|
pgObject *data = browser->GetObject(item);
|
|
if (!data)
|
|
return;
|
|
pgServer *server;
|
|
wxCommandEvent nullEvent;
|
|
|
|
if (data->IsCreatedBy(serverFactory))
|
|
{
|
|
server = (pgServer *)data;
|
|
if (!server->GetConnected())
|
|
{
|
|
if (ReconnectServer(server) == PGCONN_OK)
|
|
{
|
|
// prevent from being collapsed immediately
|
|
|
|
denyCollapseItem = item;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (settings->GetDoubleClickProperties() && propFactory->CheckEnable(data))
|
|
{
|
|
propFactory->StartDialog(this, data);
|
|
event.Skip();
|
|
return;
|
|
}
|
|
}
|
|
|
|
browser->Expand(item);
|
|
}
|
|
|
|
void frmMain::doPopup(wxWindow *win, wxPoint point, pgObject *object)
|
|
{
|
|
if (treeContextMenu)
|
|
delete treeContextMenu;
|
|
|
|
treeContextMenu = new wxMenu();
|
|
|
|
menuFactories->AppendEnabledMenus(menuBar, treeContextMenu);
|
|
|
|
wxMenuItem *newItem = treeContextMenu->FindItem(newMenuFactory->GetId());
|
|
|
|
if (newItem)
|
|
{
|
|
size_t newItemPos;
|
|
|
|
wxMenuItemList mil = treeContextMenu->GetMenuItems();
|
|
for (newItemPos = 0 ; newItemPos < mil.GetCount() ; newItemPos++)
|
|
{
|
|
if (mil.Item(newItemPos)->GetData()->GetId() == newItem->GetId())
|
|
break;
|
|
}
|
|
|
|
if (object)
|
|
{
|
|
wxMenu *indivMenu = object->GetNewMenu();
|
|
if (indivMenu)
|
|
{
|
|
|
|
if (indivMenu->GetMenuItemCount() > 1)
|
|
{
|
|
wxMenuItem *menuItem = menuBar->FindItem(newMenuFactory->GetId());
|
|
#if wxCHECK_VERSION(2, 9, 0)
|
|
wxString lab = menuItem->GetItemLabelText();
|
|
#else
|
|
wxString lab = menuItem->GetLabel(); // deprecated
|
|
#endif
|
|
|
|
treeContextMenu->Insert(newItemPos, newMenuFactory->GetId(), lab, indivMenu, menuItem->GetHelp());
|
|
}
|
|
else
|
|
{
|
|
if (indivMenu->GetMenuItemCount() == 1)
|
|
{
|
|
wxMenuItem *menuItem = indivMenu->GetMenuItems().Item(0)->GetData();
|
|
#if wxCHECK_VERSION(2, 9, 0)
|
|
wxString lab = menuItem->GetItemLabelText();
|
|
#else
|
|
wxString lab = menuItem->GetLabel(); // deprecated
|
|
#endif
|
|
treeContextMenu->Insert(newItemPos, menuItem->GetId(), lab, menuItem->GetHelp());
|
|
}
|
|
delete indivMenu;
|
|
}
|
|
}
|
|
}
|
|
treeContextMenu->Remove(newItem);
|
|
delete newItem;
|
|
}
|
|
|
|
if (treeContextMenu->GetMenuItemCount())
|
|
win->PopupMenu(treeContextMenu, point);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// This handler will display a popup menu for the currently selected item
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void frmMain::OnContextMenu(wxCommandEvent &event)
|
|
{
|
|
wxPoint point;
|
|
|
|
if (FindFocus() == browser)
|
|
{
|
|
wxRect rect;
|
|
wxTreeItemId item = browser->GetSelection();
|
|
|
|
browser->GetBoundingRect(item, rect);
|
|
point = rect.GetPosition();
|
|
wxPoint origin = GetClientAreaOrigin();
|
|
|
|
// Because this Tree is inside a vertical splitter, we
|
|
// must compensate for the size of the other elements
|
|
point.x += origin.x;
|
|
point.y += origin.y;
|
|
|
|
doPopup(this, point, browser->GetObject(item));
|
|
}
|
|
|
|
}
|
|
void frmMain::OnShortCut(wxCommandEvent& event)
|
|
{
|
|
wxPoint point;
|
|
|
|
if (FindFocus() == browser)
|
|
{
|
|
wxRect rect;
|
|
wxTreeItemId item = browser->GetSelection();
|
|
|
|
browser->GetBoundingRect(item, rect);
|
|
point = rect.GetPosition();
|
|
wxPoint origin = GetClientAreaOrigin();
|
|
point.y += rect.GetHeight();
|
|
// Because this Tree is inside a vertical splitter, we
|
|
// must compensate for the size of the other elements
|
|
point.x += origin.x;
|
|
point.y += origin.y;
|
|
wxPoint ps;
|
|
ps= browser->ClientToScreen(point);
|
|
|
|
//ctlShortCut* cb = new ctlShortCut(wxTheApp->GetTopWindow(), wxID_ANY, ps, wxDefaultSize);
|
|
//dlgshrcut = new dlgShortCut(this, wxID_ANY, wxDefaultPosition, wxDefaultSize);
|
|
select_shortcut = wxEmptyString;
|
|
dlgShortCut dlg(this, wxID_ANY, ps, wxDefaultSize);
|
|
dlg.ShowModal();
|
|
wxString path;
|
|
bool add = false;
|
|
if (select_shortcut.IsEmpty()) return;
|
|
|
|
if (select_shortcut.StartsWith("@")) {
|
|
select_shortcut = select_shortcut.substr(4);
|
|
path = select_shortcut.SubString(1, select_shortcut.Length() - 1);
|
|
add = true;
|
|
}
|
|
else path = select_shortcut;
|
|
|
|
if (!SetCurrentNode(GetBrowser()->GetRootItem(), path))
|
|
{
|
|
path = path.substr(4).BeforeFirst('(').Trim();
|
|
if (!SetCurrentNode(GetBrowser()->GetRootItem(), path)) {
|
|
wxMessageBox(_("The specified object couldn't be found in the tree."));
|
|
return;
|
|
}
|
|
}
|
|
if (add) {
|
|
int p = shortcut.Index(path);
|
|
if (p != wxNOT_FOUND) shortcut.RemoveAt(p);
|
|
|
|
shortcut.Insert(path, 0);
|
|
}
|
|
|
|
|
|
|
|
//doPopup(this, point, browser->GetObject(item));
|
|
}
|
|
|
|
}
|
|
void frmMain::OnBrowserToolTip(wxTreeEvent& event)
|
|
{
|
|
|
|
}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// This handler will display a popup menu for the item at the mouse position
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
void frmMain::OnSelRightClick(wxTreeEvent &event)
|
|
{
|
|
wxTreeItemId item = event.GetItem();
|
|
if (item != browser->GetSelection())
|
|
{
|
|
browser->SelectItem(item);
|
|
|
|
// Prevent changes to "currentObject" by "execSelchange" function by another
|
|
// thread. Will hold the lock until we have the actual object in hand.
|
|
s_currentObjectMutex.Lock();
|
|
currentObject = browser->GetObject(item);
|
|
s_currentObjectMutex.Unlock();
|
|
}
|
|
|
|
if (currentObject)
|
|
doPopup(browser, event.GetPoint(), currentObject);
|
|
}
|
|
|
|
|
|
void frmMain::OnDelete(wxCommandEvent &ev)
|
|
{
|
|
if (currentObject->CanDrop())
|
|
ExecDrop(false);
|
|
}
|
|
|
|
|
|
void frmMain::ExecDrop(bool cascaded)
|
|
{
|
|
wxTreeItemId item = browser->GetSelection();
|
|
pgCollection *collection = (pgCollection *)browser->GetObject(item);
|
|
|
|
// Get any table object for later update
|
|
wxTreeItemId owneritem;
|
|
pgObject *node = (pgObject *)browser->GetObject(item);
|
|
|
|
int metatype = node->GetMetaType();
|
|
|
|
switch (metatype)
|
|
{
|
|
case PGM_COLUMN:
|
|
owneritem = node->GetTable()->GetId();
|
|
break;
|
|
|
|
case PGM_CHECK:
|
|
case PGM_CONSTRAINT:
|
|
case PGM_EXCLUDE:
|
|
case PGM_FOREIGNKEY:
|
|
case PGM_INDEX:
|
|
case PGM_PRIMARYKEY:
|
|
case PGM_UNIQUE:
|
|
case PGM_TRIGGER:
|
|
case PGM_RULE: // Rules are technically table objects! Yeuch
|
|
case EDB_PACKAGEFUNCTION:
|
|
case EDB_PACKAGEVARIABLE:
|
|
case PGM_SCHEDULE:
|
|
case PGM_STEP:
|
|
if (node->IsCollection())
|
|
owneritem = browser->GetParentObject(node->GetId())->GetId();
|
|
else
|
|
owneritem = browser->GetParentObject(browser->GetParentObject(node->GetId())->GetId())->GetId();
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Grab the parent item to re-focus on.
|
|
wxString parent = GetNodePath(item).BeforeLast('/');
|
|
|
|
bool success = false;
|
|
if (collection == currentObject)
|
|
success = dropSingleObject(currentObject, true, cascaded);
|
|
else
|
|
{
|
|
if (collection && collection->IsCollection())
|
|
{
|
|
long index = properties->GetFirstSelected();
|
|
|
|
if (index >= 0)
|
|
{
|
|
pgObject *data = collection->FindChild(browser, index);
|
|
|
|
if (!data || !data->CanDrop())
|
|
return;
|
|
|
|
if (properties->GetSelectedItemCount() == 1)
|
|
{
|
|
success = dropSingleObject(data, true, cascaded);
|
|
}
|
|
else
|
|
{
|
|
if (cascaded || data->RequireDropConfirm() || settings->GetConfirmDelete())
|
|
{
|
|
wxString text, caption;
|
|
if (cascaded)
|
|
{
|
|
text = _("Are you sure you wish to drop multiple objects including all objects that depend on them?");
|
|
caption = _("Drop multiple objects cascaded?");
|
|
}
|
|
else
|
|
{
|
|
text = _("Are you sure you wish to drop multiple objects?");
|
|
caption = _("Drop multiple objects?");
|
|
}
|
|
wxMessageDialog msg(this, text, caption, wxYES_NO | wxICON_QUESTION | wxNO_DEFAULT);
|
|
if (msg.ShowModal() != wxID_YES)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool done = true;
|
|
long count = 0;
|
|
while (done && data && index >= 0)
|
|
{
|
|
if (data->GetSystemObject())
|
|
{
|
|
wxMessageDialog msg(this,
|
|
data->GetTranslatedMessage(CANNOTDROPSYSTEM),
|
|
_("Trying to drop system object"), wxICON_EXCLAMATION);
|
|
msg.ShowModal();
|
|
return;
|
|
}
|
|
|
|
done = dropSingleObject(data, false, cascaded);
|
|
|
|
if (done)
|
|
{
|
|
properties->DeleteItem(index);
|
|
count++;
|
|
index = properties->GetFirstSelected();
|
|
|
|
if (index >= 0)
|
|
data = collection->FindChild(browser, index);
|
|
|
|
success = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
// If the collection has a table, refresh that as well.
|
|
if (owneritem)
|
|
{
|
|
ObjectBrowserRefreshing(true);
|
|
Refresh(browser->GetObject(owneritem));
|
|
ObjectBrowserRefreshing(false);
|
|
}
|
|
|
|
// Now re-focus on the parent of the deleted node
|
|
if (!parent.IsEmpty())
|
|
SetCurrentNode(browser->GetRootItem(), parent);
|
|
}
|
|
}
|
|
|
|
|
|
bool frmMain::dropSingleObject(pgObject *data, bool updateFinal, bool cascaded)
|
|
{
|
|
if (updateFinal)
|
|
{
|
|
// accelerator can bypass disabled menu, so we need to check
|
|
if (!data || !data->CanDrop())
|
|
return false;
|
|
|
|
if (data->CheckOpenDialogs(browser, browser->GetSelection()))
|
|
{
|
|
wxString msg = _("There are properties dialogues open for one or more objects that would be dropped. Please close the properties dialogues and try again.");
|
|
wxMessageBox(msg, _("Cannot drop object"), wxICON_WARNING | wxOK);
|
|
return false;
|
|
}
|
|
|
|
if (data->GetSystemObject())
|
|
{
|
|
wxMessageDialog msg(this, data->GetTranslatedMessage(CANNOTDROPSYSTEM),
|
|
_("Trying to drop system object"), wxICON_EXCLAMATION);
|
|
msg.ShowModal();
|
|
return false;
|
|
}
|
|
|
|
if (cascaded || data->RequireDropConfirm() || settings->GetConfirmDelete())
|
|
{
|
|
wxString text, caption;
|
|
if (cascaded)
|
|
{
|
|
text = data->GetTranslatedMessage(DROPINCLUDINGDEPS);
|
|
caption = data->GetTranslatedMessage(DROPCASCADETITLE);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* currentObject is set using the following command.
|
|
* i.e. currentObject = browser->GetObject(item);
|
|
* While fetching this object using this code, somehow it looses its virtual table pointer.
|
|
* Hence, it is not able to call the GetFullIdentifier - virtual function from the
|
|
* particular class, but it will always call this functions from pgObject class always.
|
|
* To rectify this problem, we need to explicitly check the meta data type and call the
|
|
* function from the particular class.
|
|
*/
|
|
if (data->GetMetaType() == PGM_SERVER)
|
|
text = wxString::Format(_("Are you sure you wish to drop server \"%s\"?"),
|
|
((pgServer *)data)->GetFullIdentifier().c_str());
|
|
else if (data->GetMetaType() == EDB_SYNONYM)
|
|
text = ((edbPrivateSynonym *)data)->GetTranslatedMessage(DROPEXCLUDINGDEPS);
|
|
else
|
|
text = data->GetTranslatedMessage(DROPEXCLUDINGDEPS);
|
|
caption = data->GetTranslatedMessage(DROPTITLE);
|
|
}
|
|
wxMessageDialog msg(this, text, caption, wxYES_NO | wxICON_QUESTION | wxNO_DEFAULT);
|
|
if (msg.ShowModal() != wxID_YES)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
bool done = data->DropObject(this, browser, cascaded);
|
|
|
|
if (done)
|
|
{
|
|
wxLogInfo(wxT("Dropping %s %s"), data->GetTypeName().c_str(), data->GetIdentifier().c_str());
|
|
|
|
wxTreeItemId parentItem = browser->GetItemParent(data->GetId());
|
|
|
|
if (updateFinal)
|
|
{
|
|
wxTreeItemId nextItem;
|
|
if (browser->IsVisible(data->GetId()))
|
|
nextItem = browser->GetNextVisible(data->GetId());
|
|
|
|
if (nextItem)
|
|
{
|
|
pgObject *nextData = browser->GetObject(nextItem);
|
|
if (!nextData || nextData->GetType() != data->GetType())
|
|
nextItem = browser->GetPrevSibling(data->GetId());
|
|
}
|
|
else
|
|
nextItem = browser->GetPrevSibling(data->GetId());
|
|
|
|
if (nextItem)
|
|
browser->SelectItem(nextItem);
|
|
}
|
|
pgaFactory *droppedCollFactory = data->GetFactory()->GetCollectionFactory();
|
|
|
|
wxTreeItemId oldgroupitem;
|
|
wxString oldgroupname;
|
|
if (data->IsCreatedBy(serverFactory))
|
|
{
|
|
oldgroupname = ((pgServer *)data)->GetGroup();
|
|
oldgroupitem = browser->GetItemParent(data->GetId());
|
|
}
|
|
|
|
browser->Delete(data->GetId());
|
|
// data is invalid now
|
|
|
|
if (updateFinal)
|
|
{
|
|
if (!oldgroupname.IsEmpty())
|
|
{
|
|
int total = browser->GetChildrenCount(oldgroupitem, false);
|
|
if (total == 0)
|
|
browser->Delete(oldgroupitem);
|
|
else
|
|
{
|
|
wxString label = oldgroupname + wxT(" (") + NumToStr((long)total) + wxT(")");
|
|
browser->SetItemText(oldgroupitem, label);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pgCollection *collection = 0;
|
|
|
|
while (parentItem)
|
|
{
|
|
collection = (pgCollection *)browser->GetObject(parentItem);
|
|
if (collection && collection->IsCollection() && collection->GetFactory() == droppedCollFactory)
|
|
{
|
|
collection->UpdateChildCount(browser);
|
|
break;
|
|
}
|
|
parentItem = browser->GetItemParent(parentItem);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the server list, if we dropped a server
|
|
StoreServers();
|
|
}
|
|
return done;
|
|
}
|
|
|
|
|
|
void frmMain::OnNew(wxCommandEvent &ev)
|
|
{
|
|
pgaFactory *factory = pgaFactory::GetFactory(ev.GetId() - MNU_NEW);
|
|
|
|
if (factory == &serverFactory)
|
|
{
|
|
if (currentObject && currentObject->IsCreatedBy(serverFactory))
|
|
{
|
|
pgServer *server = (pgServer *)currentObject;
|
|
if (!server->GetConnected())
|
|
ReconnectServer(server);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (currentObject)
|
|
{
|
|
if (!dlgProperty::CreateObjectDialog(this, currentObject, factory))
|
|
CheckAlive();
|
|
}
|
|
}
|
|
|
|
|
|
void frmMain::OnSaveDefinition(wxCommandEvent &event)
|
|
{
|
|
|
|
wxLogInfo(wxT("Saving object definition"));
|
|
|
|
if (sqlPane->GetText().IsNull())
|
|
{
|
|
wxLogError(__("There is nothing in the SQL pane to save!"));
|
|
return;
|
|
}
|
|
|
|
wxString file;
|
|
settings->Read(wxT("frmMain/LastFile"), &file, wxEmptyString);
|
|
|
|
#ifdef __WXMSW__
|
|
wxFileDialog filename(this, _("Select output file"), ::wxPathOnly(file), file, _("SQL Scripts (*.sql)|*.sql|All files (*.*)|*.*"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
|
#else
|
|
wxFileDialog filename(this, _("Select output file"), ::wxPathOnly(file), file, _("SQL Scripts (*.sql)|*.sql|All files (*)|*"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
|
#endif
|
|
|
|
// Show the dialogue
|
|
if (filename.ShowModal() == wxID_OK)
|
|
{
|
|
// Write the file
|
|
if (!FileWrite(filename.GetPath(), sqlPane->GetText()))
|
|
{
|
|
wxLogError(__("Could not write the file %s: Errcode=%d."), filename.GetPath().c_str(), wxSysErrorCode());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wxLogInfo(wxT("User cancelled"));
|
|
}
|
|
|
|
settings->Write(wxT("frmMain/LastFile"), filename.GetPath());
|
|
}
|
|
|
|
void frmMain::OnToggleSqlPane(wxCommandEvent &event)
|
|
{
|
|
if (viewMenu->IsChecked(MNU_SQLPANE))
|
|
manager.GetPane(wxT("sqlPane")).Show(true);
|
|
else
|
|
manager.GetPane(wxT("sqlPane")).Show(false);
|
|
manager.Update();
|
|
}
|
|
|
|
void frmMain::OnToggleObjectBrowser(wxCommandEvent &event)
|
|
{
|
|
if (viewMenu->IsChecked(MNU_OBJECTBROWSER))
|
|
manager.GetPane(wxT("objectBrowser")).Show(true);
|
|
else
|
|
manager.GetPane(wxT("objectBrowser")).Show(false);
|
|
manager.Update();
|
|
}
|
|
|
|
void frmMain::OnToggleToolBar(wxCommandEvent &event)
|
|
{
|
|
if (viewMenu->IsChecked(MNU_TOOLBAR))
|
|
manager.GetPane(wxT("toolBar")).Show(true);
|
|
else
|
|
manager.GetPane(wxT("toolBar")).Show(false);
|
|
manager.Update();
|
|
}
|
|
|
|
void frmMain::OnAuiUpdate(wxAuiManagerEvent &event)
|
|
{
|
|
if(event.pane->name == wxT("objectBrowser"))
|
|
{
|
|
viewMenu->Check(MNU_OBJECTBROWSER, false);
|
|
}
|
|
else if(event.pane->name == wxT("sqlPane"))
|
|
{
|
|
viewMenu->Check(MNU_SQLPANE, false);
|
|
}
|
|
else if(event.pane->name == wxT("toolBar"))
|
|
{
|
|
viewMenu->Check(MNU_TOOLBAR, false);
|
|
}
|
|
event.Skip();
|
|
}
|
|
|
|
void frmMain::OnAuiNotebookPageClose(wxAuiNotebookEvent &event)
|
|
{
|
|
// Prevent the user closing the four main tabs.
|
|
if (event.GetSelection() < 4)
|
|
{
|
|
wxMessageBox(_("This tab cannot be closed."), _("Close tab"), wxICON_INFORMATION | wxOK);
|
|
event.Veto();
|
|
return;
|
|
}
|
|
|
|
event.Skip();
|
|
}
|
|
|
|
void frmMain::OnDefaultView(wxCommandEvent &event)
|
|
{
|
|
manager.LoadPerspective(FRMMAIN_DEFAULT_PERSPECTIVE, true);
|
|
|
|
// Reset the captions for the current language
|
|
manager.GetPane(wxT("objectBrowser")).Caption(_("Object browser"));
|
|
manager.GetPane(wxT("listViews")).Caption(_("Info pane"));
|
|
manager.GetPane(wxT("sqlPane")).Caption(_("SQL pane"));
|
|
manager.GetPane(wxT("toolBar")).Caption(_("Tool bar"));
|
|
|
|
// tell the manager to "commit" all the changes just made
|
|
manager.Update();
|
|
|
|
// Sync the View menu options
|
|
viewMenu->Check(MNU_SQLPANE, manager.GetPane(wxT("sqlPane")).IsShown());
|
|
viewMenu->Check(MNU_OBJECTBROWSER, manager.GetPane(wxT("objectBrowser")).IsShown());
|
|
viewMenu->Check(MNU_TOOLBAR, manager.GetPane(wxT("toolBar")).IsShown());
|
|
}
|
|
|
|
void frmMain::OnPositionStc(wxStyledTextEvent &event)
|
|
{
|
|
if (sqlPane->GetSelectedText().IsNull())
|
|
editMenu->Enable(MNU_COPY, false);
|
|
else
|
|
editMenu->Enable(MNU_COPY, true);
|
|
}
|