1 //////////////////////////////////////////////////////////////////////////
2 //
3 // pgAdmin III - PostgreSQL Tools
4 //
5 // Copyright (C) 2002 - 2016, The pgAdmin Development Team
6 // This software is released under the PostgreSQL Licence
7 //
8 // frmMain.cpp - The main form
9 //
10 // Note: Due to the size of frmMain, event handler, browser and statistics
11 // functions are in events.cpp.
12 //
13 //////////////////////////////////////////////////////////////////////////
14
15 #include "pgAdmin3.h"
16
17 #ifndef WIN32
18 #include <unistd.h>
19 #endif
20
21 // wxWindows headers
22 #include <wx/wx.h>
23 #include <wx/settings.h>
24 #include <wx/treectrl.h>
25 #include <wx/listctrl.h>
26 #include <wx/notebook.h>
27 #include <wx/toolbar.h>
28 #include <wx/imaglist.h>
29 #include <wx/busyinfo.h>
30 #include <wx/sysopt.h>
31 #include <wx/textbuf.h>
32 #include <wx/clipbrd.h>
33
34 // wxAUI
35 #include <wx/aui/aui.h>
36
37 // App headers
38 #include "utils/misc.h"
39 #include "frm/menu.h"
40 #include "utils/pgfeatures.h"
41 #include "debugger/debugger.h"
42 #include "frm/frmMain.h"
43 #include "ctl/ctlMenuToolbar.h"
44 #include "ctl/ctlSQLBox.h"
45 #include "db/pgConn.h"
46 #include "db/pgSet.h"
47 #include "agent/pgaJob.h"
48 #include "schema/pgDatabase.h"
49 #include "schema/pgServer.h"
50 #include "schema/pgObject.h"
51 #include "schema/pgCollection.h"
52 #include "frm/frmOptions.h"
53 #include "frm/frmAbout.h"
54 #include "frm/frmHint.h"
55 #include "frm/frmGrantWizard.h"
56 #include "frm/frmMainConfig.h"
57 #include "frm/frmHbaConfig.h"
58 #include "frm/frmPgpassConfig.h"
59 #include "frm/frmBackup.h"
60 #include "frm/frmBackupGlobals.h"
61 #include "frm/frmBackupServer.h"
62 #include "frm/frmRestore.h"
63 #include "frm/frmReport.h"
64 #include "frm/frmMaintenance.h"
65 #include "frm/frmStatus.h"
66 #include "frm/frmPassword.h"
67 #ifdef DATABASEDESIGNER
68 #include "frm/frmDatabaseDesigner.h"
69 #endif
70 #include "frm/frmQuery.h"
71 #include "frm/frmEditGrid.h"
72 #include "frm/frmImport.h"
73 #include "dlg/dlgServer.h"
74 #include "dlg/dlgDatabase.h"
75 #include "dlg/dlgSearchObject.h"
76 #include "schema/pgTable.h"
77 #include "schema/pgView.h"
78 #include "schema/pgFunction.h"
79 #include "schema/pgIndex.h"
80 #include "schema/pgTrigger.h"
81 #include "schema/pgRole.h"
82 #include "schema/pgRule.h"
83 #include "schema/pgServer.h"
84 #include "schema/pgTablespace.h"
85 #include "slony/slCluster.h"
86 #include "slony/slSet.h"
87 #include "schema/pgForeignKey.h"
88 #include "schema/pgCheck.h"
89 #include "schema/pgDomain.h"
90 #include "schema/pgEventTrigger.h"
91
92 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
93 #include "utils/sshTunnel.h"
94 #endif
95
96 #if wxDIALOG_UNIT_COMPATIBILITY
97 #error wxWindows must be compiled with wxDIALOG_UNIT_COMPATIBILITY=0!
98 #endif
99
100 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
101 DEFINE_EVENT_TYPE(SSH_TUNNEL_ERROR_EVENT);
102 #endif
103
frmMain(const wxString & title)104 frmMain::frmMain(const wxString &title)
105 : pgFrame((wxFrame *)NULL, title)
106 {
107 msgLevel = 0;
108 lastPluginUtility = NULL;
109 pluginUtilityCount = 0;
110 m_refreshing = false;
111
112 dlgName = wxT("frmMain");
113 SetMinSize(wxSize(600, 450));
114 RestorePosition(50, 50, 750, 550, 600, 450);
115
116 SetFont(settings->GetSystemFont());
117
118 {
119 wxLogInfo(wxT("Using fontmetrics %d/%d, %d Point"), GetCharWidth(), GetCharHeight(), GetFont().GetPointSize());
120 wxLogInfo(wxT("Native Description '%s'"), GetFont().GetNativeFontInfoDesc().c_str());
121 wxWindowDC dc(this);
122 dc.SetFont(GetFont());
123
124 wxCoord w, h, d, e;
125
126 dc.GetTextExtent(wxT("M"), &w, &h, &d, &e);
127 wxLogInfo(wxT("Draw size of 'M': w=%d, h=%d, descent %d, external lead %d."), w, h, d, e);
128
129 dc.GetTextExtent(wxT("g"), &w, &h, &d, &e);
130 wxLogInfo(wxT("Draw size of 'g': w=%d, h=%d, descent %d, external lead %d."), w, h, d, e);
131
132 dc.GetTextExtent(wxT("Mg"), &w, &h, &d, &e);
133 wxLogInfo(wxT("Draw size of 'Mg': w=%d, h=%d, descent %d, external lead %d."), w, h, d, e);
134 }
135
136 // Current database
137 denyCollapseItem = wxTreeItemId();
138 currentObject = 0;
139
140 appearanceFactory->SetIcons(this);
141
142 // notify wxAUI which frame to use
143 manager.SetManagedWindow(this);
144 manager.SetFlags(wxAUI_MGR_DEFAULT | wxAUI_MGR_TRANSPARENT_DRAG | wxAUI_MGR_ALLOW_ACTIVE_PANE);
145
146 // wxGTK needs this deferred
147 pgaFactory::RealizeImages();
148
149 CreateMenus();
150
151 // Setup the object browser
152 browser = new ctlTree(this, CTL_BROWSER, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS | wxSIMPLE_BORDER);
153 browser->SetImageList(imageList);
154
155 // Setup the listview
156 listViews = new ctlAuiNotebook(this, CTL_NOTEBOOK, wxDefaultPosition, wxDefaultSize, wxAUI_NB_TOP | wxAUI_NB_TAB_SPLIT | wxAUI_NB_TAB_MOVE | wxAUI_NB_TAB_EXTERNAL_MOVE | wxAUI_NB_SCROLL_BUTTONS | wxAUI_NB_WINDOWLIST_BUTTON);
157
158 // Switch to the generic list control. Native doesn't play well with
159 // multi-row select on Mac.
160 #ifdef __WXMAC__
161 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), true);
162 #endif
163
164 properties = new ctlListView(listViews, CTL_PROPVIEW, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER);
165 statistics = new ctlListView(listViews, CTL_STATVIEW, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER);
166 dependencies = new ctlListView(listViews, CTL_DEPVIEW, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER);
167 dependents = new ctlListView(listViews, CTL_REFVIEW, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER);
168
169
170
171 // Switch back to the native list control.
172 #ifdef __WXMAC__
173 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), false);
174 #endif
175
176 listViews->AddPage(properties, _("Properties")); // NBP_PROPERTIES
177 listViews->AddPage(statistics, _("Statistics")); // NBP_STATISTICS
178 listViews->AddPage(dependencies, _("Dependencies")); // NBP_DEPENDENCIES
179 listViews->AddPage(dependents, _("Dependents")); // NBP_DEPENDENTS
180
181 properties->SetImageList(imageList, wxIMAGE_LIST_SMALL);
182 statistics->SetImageList(imageList, wxIMAGE_LIST_SMALL);
183 dependencies->SetImageList(imageList, wxIMAGE_LIST_SMALL);
184 dependents->SetImageList(imageList, wxIMAGE_LIST_SMALL);
185
186 wxColour background;
187 background = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
188 statistics->SetBackgroundColour(background);
189 dependencies->SetBackgroundColour(background);
190 dependents->SetBackgroundColour(background);
191
192 // Setup the SQL pane
193 sqlPane = new ctlSQLBox(this, CTL_SQLPANE, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxSIMPLE_BORDER | wxTE_READONLY | wxTE_RICH2);
194 sqlPane->SetBackgroundColour(background);
195
196 // Setup menus
197 pgaFactory::RegisterMenu(this, wxCommandEventHandler(frmMain::OnNew));
198 menuFactories->RegisterMenu(this, wxCommandEventHandler(frmMain::OnAction));
199 menuFactories->CheckMenu(0, menuBar, toolBar);
200
201 // Kickstart wxAUI
202 manager.AddPane(browser, wxAuiPaneInfo().Name(wxT("objectBrowser")).Caption(_("Object browser")).Left().MinSize(wxSize(100, 200)).BestSize(wxSize(200, 450)));
203 manager.AddPane(listViews, wxAuiPaneInfo().Name(wxT("listViews")).Caption(_("Info pane")).Center().CaptionVisible(false).CloseButton(false).MinSize(wxSize(200, 100)).BestSize(wxSize(400, 200)));
204 manager.AddPane(sqlPane, wxAuiPaneInfo().Name(wxT("sqlPane")).Caption(_("SQL pane")).Bottom().MinSize(wxSize(200, 100)).BestSize(wxSize(400, 200)));
205 manager.AddPane(toolBar, wxAuiPaneInfo().Name(wxT("toolBar")).Caption(_("Tool bar")).ToolbarPane().Top().LeftDockable(false).RightDockable(false));
206
207 // Now load the layout
208 wxString perspective;
209 settings->Read(wxT("frmMain/Perspective-") + wxString(FRMMAIN_PERSPECTIVE_VER), &perspective, FRMMAIN_DEFAULT_PERSPECTIVE);
210 manager.LoadPerspective(perspective, true);
211
212 // and reset the captions for the current language
213 manager.GetPane(wxT("objectBrowser")).Caption(_("Object browser"));
214 manager.GetPane(wxT("listViews")).Caption(_("Info pane"));
215 manager.GetPane(wxT("sqlPane")).Caption(_("SQL pane"));
216 manager.GetPane(wxT("toolBar")).Caption(_("Tool bar"));
217
218 // Sync the View menu options
219 viewMenu->Check(MNU_SQLPANE, manager.GetPane(wxT("sqlPane")).IsShown());
220 viewMenu->Check(MNU_OBJECTBROWSER, manager.GetPane(wxT("objectBrowser")).IsShown());
221 viewMenu->Check(MNU_TOOLBAR, manager.GetPane(wxT("toolBar")).IsShown());
222
223 ResetLists();
224
225 // tell the manager to "commit" all the changes just made
226 manager.Update();
227
228 // Add the root node
229 serversObj = new pgServerCollection(serverFactory.GetCollectionFactory());
230 wxTreeItemId root = browser->AddRoot(_("Server Groups"), serversObj->GetIconId(), -1, serversObj);
231
232 // Work around a bug in the generic tree control in wxWidgets,
233 // Per http://trac.wxwidgets.org/ticket/10085
234 browser->SetItemText(root, _("Server Groups"));
235
236 // Load servers
237 RetrieveServers();
238
239 browser->Expand(root);
240 browser->SortChildren(root);
241 browser->SetFocus();
242 }
243
244
~frmMain()245 frmMain::~frmMain()
246 {
247 // Store the servers, to ensure we store the last database/schema etc
248 StoreServers();
249
250 settings->Write(wxT("frmMain/Perspective-") + wxString(FRMMAIN_PERSPECTIVE_VER), manager.SavePerspective());
251 manager.UnInit();
252
253 // Clear the treeview
254 browser->DeleteAllItems();
255
256 if (treeContextMenu)
257 delete treeContextMenu;
258
259 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
260 if(pgadminTunnelThread && pgadminTunnelThread->IsAlive())
261 {
262 pgadminTunnelThread->Cleanup();
263 pgadminTunnelThread = NULL;
264 }
265 #endif
266 }
267
268
269
CreateMenus()270 void frmMain::CreateMenus()
271 {
272 // to add a new menu or context menu to the main window, i.e. define a possible
273 // action on a pgObject, everything has to go into this method. Doing menu related
274 // stuff elsewhere is plain wrong!
275 // Create a proper actionFactory (or contextActionFactory) for each of your new actions
276 // in the new frmXXX.cpp and register it here.
277
278 fileMenu = new wxMenu();
279 pluginsMenu = new wxMenu();
280 viewMenu = new wxMenu();
281 editMenu = new wxMenu();
282 newMenu = new wxMenu();
283 toolsMenu = new wxMenu();
284 slonyMenu = new wxMenu();
285 scriptingMenu = new wxMenu();
286 viewDataMenu = new wxMenu();
287 debuggingMenu = new wxMenu();
288 reportMenu = new wxMenu();
289 wxMenu *cfgMenu = new wxMenu();
290 helpMenu = new wxMenu();
291 newContextMenu = new wxMenu();
292
293 toolBar = new ctlMenuToolbar(this, -1, wxDefaultPosition, wxDefaultSize, wxTB_FLAT | wxTB_NODIVIDER );
294 toolBar->SetToolBitmapSize(wxSize(32, 32));
295 menuFactories = new menuFactoryList();
296
297 // Load plugins - must do this after creating the menus and the factories
298 LoadPluginUtilities();
299
300 //--------------------------
301 fileMenu->Append(MNU_SAVEDEFINITION, _("&Save Definition..."), _("Save the SQL definition of the selected object."));
302 fileMenu->AppendSeparator();
303 new addServerFactory(menuFactories, fileMenu, toolBar);
304
305 viewMenu->Append(MNU_OBJECTBROWSER, _("&Object browser\tCtrl-Alt-O"), _("Show or hide the object browser."), wxITEM_CHECK);
306 viewMenu->Append(MNU_SQLPANE, _("&SQL pane\tCtrl-Alt-S"), _("Show or hide the SQL pane."), wxITEM_CHECK);
307 viewMenu->Append(MNU_TOOLBAR, _("&Tool bar\tCtrl-Alt-T"), _("Show or hide the tool bar."), wxITEM_CHECK);
308 viewMenu->AppendSeparator();
309 viewMenu->Append(MNU_DEFAULTVIEW, _("&Default view\tCtrl-Alt-V"), _("Restore the default view."));
310 viewMenu->AppendSeparator();
311 actionFactory *refFact = new refreshFactory(menuFactories, viewMenu, toolBar);
312 new countRowsFactory(menuFactories, viewMenu, 0);
313 new refreshMatViewFactory(menuFactories, viewMenu, 0);
314 new refreshConcurrentlyMatViewFactory(menuFactories, viewMenu, 0);
315 new executePgstattupleFactory(menuFactories, viewMenu, 0);
316 new executePgstatindexFactory(menuFactories, viewMenu, 0);
317 new enabledisableRuleFactory(menuFactories, toolsMenu, 0);
318 new enabledisableTriggerFactory(menuFactories, toolsMenu, 0);
319 new enabledisableEventTriggerFactory(menuFactories, toolsMenu, 0);
320 new disableAllTriggersFactory(menuFactories, toolsMenu, 0);
321 new enableAllTriggersFactory(menuFactories, toolsMenu, 0);
322 new validateForeignKeyFactory(menuFactories, toolsMenu, 0);
323 new validateCheckFactory(menuFactories, toolsMenu, 0);
324 new validateDomainCheckFactory(menuFactories, toolsMenu, 0);
325 toolsMenu->AppendSeparator();
326
327 //--------------------------
328 new separatorFactory(menuFactories);
329
330 toolBar->AddSeparator();
331
332 new passwordFactory(menuFactories, fileMenu, 0);
333 fileMenu->AppendSeparator();
334 optionsFactory *optFact = new optionsFactory(menuFactories, fileMenu, 0);
335 fileMenu->AppendSeparator();
336 new mainConfigFileFactory(menuFactories, fileMenu, 0);
337 new hbaConfigFileFactory(menuFactories, fileMenu, 0);
338 new pgpassConfigFileFactory(menuFactories, fileMenu, 0);
339
340 fileMenu->AppendSeparator();
341 fileMenu->Append(MNU_EXIT, _("E&xit\tCtrl-Q"), _("Quit this program."));
342
343 new slonyRestartFactory(menuFactories, slonyMenu, 0);
344 new slonyUpgradeFactory(menuFactories, slonyMenu, 0);
345 new slonyFailoverFactory(menuFactories, slonyMenu, 0);
346 new slonyLockSetFactory(menuFactories, slonyMenu, 0);
347 new slonyUnlockSetFactory(menuFactories, slonyMenu, 0);
348 new slonyMergeSetFactory(menuFactories, slonyMenu, 0);
349 new slonyMoveSetFactory(menuFactories, slonyMenu, 0);
350 toolsMenu->Append(MNU_SLONY_SUBMENU, _("Slony Replication"), slonyMenu);
351
352 propFactory = new propertyFactory(menuFactories, 0, toolBar);
353 new separatorFactory(menuFactories);
354
355
356 // -------------------------
357
358 editMenu->Append(MNU_COPY, _("&Copy\tCtrl-C"), _("Copy selected text to clipboard"));
359 editMenu->AppendSeparator();
360
361 // -------------------------
362
363 //--------------------------
364
365 newMenuFactory = new submenuFactory(menuFactories); // placeholder where "New objects" submenu will be inserted
366 editMenu->Append(newMenuFactory->GetId(), _("New &Object"), newMenu, _("Create a new object."));
367 editMenu->AppendSeparator();
368
369
370 //--------------------------
371
372 new connectServerFactory(menuFactories, toolsMenu, 0);
373 new disconnectServerFactory(menuFactories, toolsMenu, 0);
374 new disconnectDatabaseFactory(menuFactories, toolsMenu, 0);
375
376 new startServiceFactory(menuFactories, toolsMenu, 0);
377 new stopServiceFactory(menuFactories, toolsMenu, 0);
378 new reloadconfServiceFactory(menuFactories, toolsMenu, 0);
379 new pausereplayServiceFactory(menuFactories, toolsMenu, 0);
380 new resumereplayServiceFactory(menuFactories, toolsMenu, 0);
381 new addnamedrestorepointServiceFactory(menuFactories, toolsMenu, 0);
382
383 new createFactory(menuFactories, editMenu, toolBar);
384 new dropFactory(menuFactories, editMenu, toolBar);
385 new dropCascadedFactory(menuFactories, editMenu, 0);
386 new truncateFactory(menuFactories, editMenu, 0);
387 new truncateCascadedFactory(menuFactories, editMenu, 0);
388 new resetTableStatsFactory(menuFactories, editMenu, 0);
389 new resetFunctionStatsFactory(menuFactories, editMenu, 0);
390 new reassignDropOwnedFactory(menuFactories, editMenu, 0);
391 new moveTablespaceFactory(menuFactories, editMenu, 0);
392 new searchObjectFactory(menuFactories, editMenu, 0);
393 editMenu->AppendSeparator();
394
395 new separatorFactory(menuFactories);
396
397 toolBar->AddSeparator();
398 toolsMenu->AppendSeparator();
399
400 debuggingMenuFactory = new submenuFactory(menuFactories); // placeholder where "Debugging" submenu will be inserted
401 toolsMenu->Append(debuggingMenuFactory->GetId(), _("&Debugging"), debuggingMenu, _("Debugging options for the selected item."));
402 new debuggerFactory(menuFactories, debuggingMenu, 0);
403 new breakpointFactory(menuFactories, debuggingMenu, 0);
404
405 new queryToolFactory(menuFactories, toolsMenu, toolBar);
406 scriptingMenuFactory = new submenuFactory(menuFactories); // placeholder where "Query Template" submenu will be inserted
407 toolsMenu->Append(scriptingMenuFactory->GetId(), _("Scripts"), scriptingMenu, _("Start Query Tool with scripted query."));
408 new queryToolSqlFactory(menuFactories, scriptingMenu, 0);
409 new queryToolSelectFactory(menuFactories, scriptingMenu, 0);
410 new queryToolExecFactory(menuFactories, scriptingMenu, 0);
411 new queryToolInsertFactory(menuFactories, scriptingMenu, 0);
412 new queryToolUpdateFactory(menuFactories, scriptingMenu, 0);
413 new queryToolDeleteFactory(menuFactories, scriptingMenu, 0);
414
415 #ifdef DATABASEDESIGNER
416 new databaseDesignerFactory(menuFactories, toolsMenu, toolBar);
417 #endif
418
419 viewdataMenuFactory = new submenuFactory(menuFactories); // placeholder where "View data" submenu will be inserted
420 toolsMenu->Append(viewdataMenuFactory->GetId(), _("View &Data"), viewDataMenu, _("View data."));
421
422 reportMenuFactory = new submenuFactory(menuFactories); // placeholder where "Reports" submenu will be inserted
423 toolsMenu->Append(reportMenuFactory->GetId(), _("&Reports"), reportMenu, _("Create reports about the selected item."));
424 new reportObjectPropertiesFactory(menuFactories, reportMenu, 0);
425 new reportObjectDdlFactory(menuFactories, reportMenu, 0);
426 new reportObjectDataDictionaryFactory(menuFactories, reportMenu, 0);
427 new reportObjectStatisticsFactory(menuFactories, reportMenu, 0);
428 new reportObjectDependenciesFactory(menuFactories, reportMenu, 0);
429 new reportObjectDependentsFactory(menuFactories, reportMenu, 0);
430 new reportObjectListFactory(menuFactories, reportMenu, 0);
431
432
433 toolsMenu->AppendSeparator();
434
435 new editGridLimitedFactory(menuFactories, viewDataMenu, toolBar, 100, true);
436 new editGridLimitedFactory(menuFactories, viewDataMenu, toolBar, 100, false);
437 new editGridFactory(menuFactories, viewDataMenu, toolBar);
438 new editGridFilteredFactory(menuFactories, viewDataMenu, toolBar);
439
440 new maintenanceFactory(menuFactories, toolsMenu, toolBar);
441
442 new backupFactory(menuFactories, toolsMenu, 0);
443 new backupGlobalsFactory(menuFactories, toolsMenu, 0);
444 new backupServerFactory(menuFactories, toolsMenu, 0);
445 new restoreFactory(menuFactories, toolsMenu, 0);
446 new importFactory(menuFactories, toolsMenu, 0);
447
448 new grantWizardFactory(menuFactories, toolsMenu, 0);
449 new mainConfigFactory(menuFactories, cfgMenu, 0);
450 new hbaConfigFactory(menuFactories, cfgMenu, 0);
451 toolsMenu->Append(MNU_CONFIGSUBMENU, _("Server Configuration"), cfgMenu);
452 toolsMenu->AppendSeparator();
453
454 new runNowFactory(menuFactories, toolsMenu, 0);
455 toolsMenu->AppendSeparator();
456
457 new separatorFactory(menuFactories);
458
459 new propertyFactory(menuFactories, editMenu, 0);
460 new serverStatusFactory(menuFactories, toolsMenu, 0);
461
462 // Add the plugin toolbar button/menu
463 new pluginButtonMenuFactory(menuFactories, pluginsMenu, toolBar, pluginUtilityCount);
464
465 //--------------------------
466 toolBar->AddSeparator();
467
468 actionFactory *helpFact = new contentsFactory(menuFactories, helpMenu, 0);
469 new hintFactory(menuFactories, helpMenu, toolBar, true);
470 new faqFactory(menuFactories, helpMenu, 0);
471 new bugReportFactory(menuFactories, helpMenu, 0);
472
473 helpMenu->AppendSeparator();
474
475 new pgsqlHelpFactory(menuFactories, helpMenu, toolBar, true);
476 if (!appearanceFactory->GetHideEnterprisedbHelp())
477 new edbHelpFactory(menuFactories, helpMenu, toolBar, true);
478 if (!appearanceFactory->GetHideGreenplumHelp())
479 new greenplumHelpFactory(menuFactories, helpMenu, toolBar, true);
480 new slonyHelpFactory(menuFactories, helpMenu, toolBar, true);
481
482 // Don't include this seperator on Mac, because the only option
483 // under it will be moved to the application menu.
484 #ifndef __WXMAC__
485 helpMenu->AppendSeparator();
486 #endif
487
488 actionFactory *abFact = new aboutFactory(menuFactories, helpMenu, 0);
489
490 #ifdef __WXMAC__
491 wxApp::s_macPreferencesMenuItemId = optFact->GetId();
492 wxApp::s_macExitMenuItemId = MNU_EXIT;
493 wxApp::s_macAboutMenuItemId = abFact->GetId();
494 #else
495 (void)optFact;
496 (void)abFact;
497 #endif
498
499
500 menuBar = new wxMenuBar();
501 menuBar->Append(fileMenu, _("&File"));
502 menuBar->Append(editMenu, _("&Edit"));
503 // Changing the caption of the plugins menu also needs a similar change below
504 menuBar->Append(pluginsMenu, _("&Plugins"));
505 menuBar->Append(viewMenu, _("&View"));
506 menuBar->Append(toolsMenu, _("&Tools"));
507 menuBar->Append(helpMenu, _("&Help"));
508 SetMenuBar(menuBar);
509
510 // Disable the plugins menu if there aren't any.
511 if (!pluginUtilityCount)
512 {
513 pluginsMenu->Append(MNU_DUMMY, _("No plugins installed"));
514 pluginsMenu->Enable(MNU_DUMMY, false);
515 }
516
517 treeContextMenu = 0;
518
519 // Status bar
520 statusBar = CreateStatusBar(4);
521 int iWidths[4] = {0, -1, 400, 100};
522 SetStatusWidths(4, iWidths);
523 SetStatusBarPane(-1);
524 statusBar->SetStatusText(wxT(""), 0);
525 statusBar->SetStatusText(_("Ready."), 1);
526 statusBar->SetStatusText(_("0 Secs"), 3);
527
528 wxAcceleratorEntry entries[4];
529 entries[0].Set(wxACCEL_NORMAL, WXK_F5, refFact->GetId());
530 entries[1].Set(wxACCEL_NORMAL, WXK_DELETE, MNU_DELETE);
531 entries[2].Set(wxACCEL_NORMAL, WXK_F1, helpFact->GetId());
532 entries[3].Set(wxACCEL_SHIFT, WXK_F10, MNU_CONTEXTMENU);
533 wxAcceleratorTable accel(4, entries);
534
535 SetAcceleratorTable(accel);
536
537 // Display the bar and configure buttons.
538 toolBar->Realize();
539 }
540
541
Refresh(pgObject * data)542 void frmMain::Refresh(pgObject *data)
543 {
544 bool done = false;
545 pgObject *obj = NULL;
546
547 StartMsg(data->GetTranslatedMessage(REFRESHINGDETAILS));
548 browser->Freeze();
549
550 wxTreeItemId currentItem = data->GetId();
551 if (currentItem)
552 obj = browser->GetObject(currentItem);
553
554 if (obj && obj->CheckOpenDialogs(browser, currentItem))
555 {
556 wxString msg = _("There are properties dialogues open for one or more objects that would be refreshed. Please close the properties dialogues and try again.");
557 wxMessageBox(msg, _("Cannot refresh browser"), wxICON_WARNING | wxOK);
558 }
559 else
560 {
561 if (data->GetMetaType() == PGM_SCHEMA && !data->IsCollection() && data->GetConnection()->BackendMinimumVersion(9, 3))
562 {
563 // Event triggers backend functions are at schema level.
564 // Hence, we can consider that Event Triggers at schema level and partly at database.
565 // So, if any schema is refreshed, we need to the event trigger collection as well.
566 // It's a special case, which effects the schema operations on the event triggers as well.
567 // To solve this, we are navigating to the parent node (database node), and then locating event trigger collections.
568 // Once we've found the event triggers collection, we refresh it.
569 //
570 wxTreeItemId dbItem = browser->GetItemParent(browser->GetItemParent(browser->GetSelection()));
571 pgCollection *eventTrgCol = browser->FindCollection(eventTriggerFactory, dbItem);
572
573 if(eventTrgCol)
574 Refresh(eventTrgCol);
575 }
576
577 // Scan the child nodes and make a list of those that are expanded
578 // This is not an exact science as node names may change etc.
579 wxArrayString expandedNodes;
580 GetExpandedChildNodes(currentItem, expandedNodes);
581
582 browser->DeleteChildren(currentItem);
583
584 // refresh information about the object
585 data->SetDirty();
586
587 pgObject *newData = data->Refresh(browser, currentItem);
588 done = !data->GetConnection() || data->GetConnection()->GetStatus() == PGCONN_OK;
589
590 if (newData != data)
591 {
592 wxLogInfo(wxT("Deleting %s %s for refresh"), data->GetTypeName().c_str(), data->GetQuotedFullIdentifier().c_str());
593
594 if (data == currentObject)
595 currentObject = newData;
596
597 if (newData)
598 {
599 wxLogInfo(wxT("Replacing with new node %s %s for refresh"), newData->GetTypeName().c_str(), newData->GetQuotedFullIdentifier().c_str());
600
601 newData->SetId(currentItem); // not done automatically
602 browser->SetItemData(currentItem, newData);
603
604 // Update the node text if this is an object, as it may have been renamed
605 if (!newData->IsCollection())
606 browser->SetItemText(currentItem, newData->GetDisplayName());
607
608 delete data;
609 data = NULL;
610 }
611 else
612 {
613 wxLogInfo(wxT("No object to replace: vanished after refresh."));
614
615 // If the connection is dead, just return here
616 if (data->GetConnection()->GetStatus() != PGCONN_OK)
617 {
618 CheckAlive();
619 browser->Thaw();
620 return;
621 }
622
623 wxTreeItemId delItem = currentItem;
624 currentItem = browser->GetItemParent(currentItem);
625 browser->SelectItem(currentItem);
626 browser->Delete(delItem);
627 }
628 }
629
630 if (currentItem)
631 {
632 // Select the current node
633 execSelChange(currentItem, currentItem == browser->GetSelection());
634
635 // Attempt to expand any child nodes that were previously expanded
636 ExpandChildNodes(currentItem, expandedNodes);
637 }
638 }
639
640 browser->Thaw();
641 EndMsg(done);
642 }
643
OnCopy(wxCommandEvent & ev)644 void frmMain::OnCopy(wxCommandEvent &ev)
645 {
646 wxString text;
647
648 // Attempt to copy from the current object
649
650 // Listview
651 ctlListView *lv = dynamic_cast<ctlListView *>(currentControl);
652 if (lv)
653 {
654 int row = lv->GetFirstSelected();
655
656 while (row >= 0)
657 {
658 for (int col = 0; col < lv->GetColumnCount(); col++)
659 {
660 text.Append(lv->GetText(row, col) + wxT("\t"));
661 }
662 text.Append(wxT("\n"));
663 row = lv->GetNextSelected(row);
664 }
665 text = text.Trim();
666 }
667
668 // ctlSQLBox
669 ctlSQLBox *sb = dynamic_cast<ctlSQLBox *>(currentControl);
670 if (sb)
671 {
672 text = sb->GetSelectedText();
673 }
674
675 // Set the clipboard text
676 if (text.Length() > 0 && wxTheClipboard->Open())
677 {
678 wxTheClipboard->SetData(new wxTextDataObject(wxTextBuffer::Translate(text)));
679 wxTheClipboard->Close();
680 }
681 }
682
GetExpandedChildNodes(wxTreeItemId node,wxArrayString & expandedNodes)683 void frmMain::GetExpandedChildNodes(wxTreeItemId node, wxArrayString &expandedNodes)
684 {
685 wxTreeItemIdValue cookie;
686 wxTreeItemId child = browser->GetFirstChild(node, cookie);
687
688 while (child.IsOk())
689 {
690 if (browser->IsExpanded(child))
691 {
692 GetExpandedChildNodes(child, expandedNodes);
693 expandedNodes.Add(GetNodePath(child));
694 }
695
696 child = browser->GetNextChild(node, cookie);
697 }
698 }
699
ExpandChildNodes(wxTreeItemId node,wxArrayString & expandedNodes)700 void frmMain::ExpandChildNodes(wxTreeItemId node, wxArrayString &expandedNodes)
701 {
702 wxTreeItemIdValue cookie;
703 wxTreeItemId child = browser->GetFirstChild(node, cookie);
704
705 while (child.IsOk())
706 {
707 if (expandedNodes.Index(GetNodePath(child)) != wxNOT_FOUND)
708 {
709 browser->Expand(child);
710 ExpandChildNodes(child, expandedNodes);
711 }
712
713 child = browser->GetNextChild(node, cookie);
714 }
715 }
716
GetNodePath(wxTreeItemId node)717 wxString frmMain::GetNodePath(wxTreeItemId node)
718 {
719 wxString path;
720 path = browser->GetItemText(node).BeforeFirst('(').Trim();
721
722 wxTreeItemId parent = browser->GetItemParent(node);
723 while (parent.IsOk())
724 {
725 path = browser->GetItemText(parent).BeforeFirst('(').Trim() + wxT("/") + path;
726 parent = browser->GetItemParent(parent);
727 }
728
729 return path;
730 }
731
732 // Return the path for the current node
GetCurrentNodePath()733 wxString frmMain::GetCurrentNodePath()
734 {
735 return GetNodePath(currentObject->GetId());
736 }
737
738 // Attempt to reselect the node with the given path
SetCurrentNode(wxTreeItemId node,const wxString & origPath)739 bool frmMain::SetCurrentNode(wxTreeItemId node, const wxString &origPath)
740 {
741 wxString path = origPath.Lower();
742 wxTreeItemIdValue cookie;
743 wxTreeItemId child = browser->GetFirstChild(node, cookie);
744
745
746 while (child.IsOk())
747 {
748 wxString actNodePath = GetNodePath(child).Lower();
749
750 if(path.StartsWith(actNodePath))
751 {
752 if(!browser->IsExpanded(child))
753 {
754 browser->SelectItem(child, true);
755 browser->Expand(child);
756 }
757
758 if (actNodePath == path)
759 {
760 browser->SelectItem(child, true);
761 return true;
762 }
763 else if (SetCurrentNode(child, path))
764 return true;
765 }
766 child = browser->GetNextChild(node, cookie);
767
768 }
769
770 return false;
771 }
772
ShowObjStatistics(pgObject * data,wxWindow * ctrl)773 void frmMain::ShowObjStatistics(pgObject *data, wxWindow *ctrl)
774 {
775
776 // Refresh panes if they're currently shown on screen, unless
777 // they've been specifically requested (eg. a notebook
778 // event is telling us they're about to become visible).
779
780 if ((!ctrl && statistics->IsShownOnScreen()) || ctrl == statistics)
781 {
782 statistics->Freeze();
783 data->ShowStatistics(this, statistics);
784 statistics->Thaw();
785 }
786
787 if ((!ctrl && dependencies->IsShownOnScreen()) || ctrl == dependencies)
788 {
789 dependencies->Freeze();
790 data->ShowDependencies(this, dependencies);
791 dependencies->Thaw();
792 }
793
794 if ((!ctrl && dependents->IsShownOnScreen()) || ctrl == dependents)
795 {
796 dependents->Freeze();
797 data->ShowDependents(this, dependents);
798 dependents->Thaw();
799 }
800 }
801
802
803 // Ensure we show the data in any tabs that become visible
OnPageChange(wxAuiNotebookEvent & event)804 void frmMain::OnPageChange(wxAuiNotebookEvent &event)
805 {
806 pgObject *data = browser->GetObject(browser->GetSelection());
807
808 if (!data)
809 return;
810
811 ShowObjStatistics(data, ((wxAuiNotebook *)event.GetEventObject())->GetPage(event.GetSelection()));
812 }
813
814
GetStatistics()815 ctlListView *frmMain::GetStatistics()
816 {
817 return statistics;
818 }
819
GetDependencies()820 ctlListView *frmMain::GetDependencies()
821 {
822 return dependencies;
823 }
824
GetReferencedBy()825 ctlListView *frmMain::GetReferencedBy()
826 {
827 return dependents;
828 }
829
CheckAlive()830 bool frmMain::CheckAlive()
831 {
832 bool userInformed = false;
833 bool closeIt = false;
834
835 wxTreeItemIdValue foldercookie;
836 wxTreeItemId folderitem = browser->GetFirstChild(browser->GetRootItem(), foldercookie);
837 while (folderitem)
838 {
839 if (browser->ItemHasChildren(folderitem))
840 {
841 wxCookieType cookie;
842 wxTreeItemId serverItem = browser->GetFirstChild(folderitem, cookie);
843 while (serverItem)
844 {
845 pgServer *server = (pgServer *)browser->GetObject(serverItem);
846
847 if (server && server->IsCreatedBy(serverFactory) && server->connection())
848 {
849 if (server->connection()->IsAlive())
850 {
851 wxCookieType cookie2;
852 wxTreeItemId item = browser->GetFirstChild(serverItem, cookie2);
853 while (item)
854 {
855 pgObject *obj = browser->GetObject(item);
856 if (obj && obj->IsCreatedBy(databaseFactory.GetCollectionFactory()))
857 {
858 wxCookieType cookie3;
859 item = browser->GetFirstChild(obj->GetId(), cookie3);
860 while (item)
861 {
862 pgDatabase *db = (pgDatabase *)browser->GetObject(item);
863 if (db && db->IsCreatedBy(databaseFactory))
864 {
865 pgConn *conn = db->GetConnection();
866 if (conn)
867 {
868 if (!conn->IsAlive() && (conn->GetStatus() == PGCONN_BROKEN || conn->GetStatus() == PGCONN_BAD))
869 {
870 conn->Close();
871 if (!userInformed)
872 {
873 wxMessageDialog dlg(this, _("Do you want to attempt to reconnect to the database?"),
874 wxString::Format(_("Connection to database %s lost."), db->GetName().c_str()),
875 wxICON_EXCLAMATION | wxYES_NO | wxYES_DEFAULT);
876
877 closeIt = (dlg.ShowModal() != wxID_YES);
878 userInformed = true;
879 }
880 if (closeIt)
881 {
882 db->Disconnect();
883
884 browser->DeleteChildren(db->GetId());
885 db->UpdateIcon(browser);
886 }
887 else
888 {
889 // Create a server object and connect it.
890 wxBusyInfo waiting(wxString::Format(_("Reconnecting to database %s"),
891 db->GetName().c_str()), this);
892
893 // Give the UI a chance to redraw
894 wxSafeYield();
895 wxMilliSleep(100);
896 wxSafeYield();
897
898 if (!conn->Reconnect())
899 {
900 db->Disconnect();
901
902 browser->DeleteChildren(db->GetId());
903 db->UpdateIcon(browser);
904 }
905 else
906 // Indicate things are back to normal
907 userInformed = false;
908 }
909
910 }
911 }
912 }
913 item = browser->GetNextChild(obj->GetId(), cookie3);
914 }
915 }
916 item = browser->GetNextChild(serverItem, cookie2);
917 }
918 }
919 else
920 {
921 if (server->connection()->GetStatus() == PGCONN_BROKEN || server->connection()->GetStatus() == PGCONN_BAD)
922 {
923 server->connection()->Close();
924 if (!userInformed)
925 {
926 wxMessageDialog dlg(this, _("Do you want to attempt to reconnect to the server?"),
927 wxString::Format(_("Connection to server %s lost."), server->GetName().c_str()),
928 wxICON_EXCLAMATION | wxYES_NO | wxYES_DEFAULT);
929
930 closeIt = (dlg.ShowModal() != wxID_YES);
931 userInformed = true;
932 }
933 if (closeIt)
934 {
935 server->Disconnect(this);
936 browser->SelectItem(serverItem);
937 execSelChange(serverItem, true);
938 browser->DeleteChildren(serverItem);
939 }
940 else
941 {
942 // Create a server object and connect it.
943 wxBusyInfo waiting(wxString::Format(_("Reconnecting to server %s (%s:%d)"),
944 server->GetDescription().c_str(), server->GetName().c_str(), server->GetPort()), this);
945
946 // Give the UI a chance to redraw
947 wxSafeYield();
948 wxMilliSleep(100);
949 wxSafeYield();
950
951 if (!server->connection()->Reconnect())
952 {
953 server->Disconnect(this);
954 browser->SelectItem(serverItem);
955 execSelChange(serverItem, true);
956 browser->DeleteChildren(serverItem);
957 }
958 else
959 // Indicate things are back to normal
960 userInformed = false;
961 }
962 }
963 }
964 }
965
966 serverItem = browser->GetNextChild(folderitem, cookie);
967 }
968 }
969 folderitem = browser->GetNextChild(browser->GetRootItem(), foldercookie);
970 }
971 return userInformed;
972 }
973
974
RestoreEnvironment(pgServer * server)975 wxTreeItemId frmMain::RestoreEnvironment(pgServer *server)
976 {
977 wxTreeItemId item, lastItem;
978 wxString lastDatabase = server->GetLastDatabase();
979 if (lastDatabase.IsNull())
980 return item;
981
982 wxCookieType cookie;
983 pgObject *data = 0;
984 item = browser->GetFirstChild(server->GetId(), cookie);
985 while (item)
986 {
987 data = browser->GetObject(item);
988 if (data && data->IsCreatedBy(databaseFactory.GetCollectionFactory()))
989 break;
990 // Get the next item
991 item = browser->GetNextChild(server->GetId(), cookie);
992 }
993 if (!item)
994 return item;
995
996 // found DATABASES item
997 listViews->SetSelection(NBP_PROPERTIES);
998 data->ShowTree(this, browser, 0, 0);
999 lastItem = item;
1000
1001 item = browser->GetFirstChild(lastItem, cookie);
1002 while (item)
1003 {
1004 data = browser->GetObject(item);
1005 if (data && data->IsCreatedBy(databaseFactory) && data->GetName() == lastDatabase)
1006 break;
1007 // Get the next item
1008 item = browser->GetNextChild(lastItem, cookie);
1009 }
1010 if (!item)
1011 return lastItem;
1012
1013 // found last DATABASE
1014 data->ShowTree(this, browser, 0, 0);
1015 lastItem = item;
1016
1017 wxString lastSchema = server->GetLastSchema();
1018 if (lastSchema.IsNull())
1019 return lastItem;
1020
1021 item = browser->GetFirstChild(lastItem, cookie);
1022 while (item)
1023 {
1024 data = browser->GetObject(item);
1025 if (data && data->GetMetaType() == PGM_SCHEMA)
1026 break;
1027 // Get the next item
1028 item = browser->GetNextChild(lastItem, cookie);
1029 }
1030 if (!item)
1031 return lastItem;
1032
1033 // found SCHEMAS item
1034 data->ShowTree(this, browser, 0, 0);
1035 lastItem = item;
1036
1037 item = browser->GetFirstChild(lastItem, cookie);
1038 while (item)
1039 {
1040 data = browser->GetObject(item);
1041 if (data && data->GetMetaType() == PGM_SCHEMA && data->GetName() == lastSchema)
1042 break;
1043 // Get the next item
1044 item = browser->GetNextChild(lastItem, cookie);
1045 }
1046
1047 return (item ? item : lastItem);
1048 }
1049
1050
ReconnectServer(pgServer * server,bool restore)1051 int frmMain::ReconnectServer(pgServer *server, bool restore)
1052 {
1053 // Create a server object and connect it.
1054 wxBusyInfo waiting(wxString::Format(_("Connecting to server %s (%s:%d)"),
1055 server->GetDescription().c_str(), server->GetName().c_str(), server->GetPort()), this);
1056
1057 // Give the UI a chance to redraw
1058 wxSafeYield();
1059 wxMilliSleep(100);
1060 wxSafeYield();
1061
1062 int res = server->Connect(this, true, wxEmptyString, false, true);
1063
1064 // Check the result, and handle it as appropriate
1065 wxTreeItemId item;
1066 switch (res)
1067 {
1068 case PGCONN_OK:
1069 {
1070 if (restore && server->GetRestore())
1071 StartMsg(_("Restoring previous environment"));
1072 else
1073 StartMsg(_("Establishing connection"));
1074
1075 wxLogInfo(wxT("pgServer object initialised as required."));
1076
1077 server->ShowTreeDetail(browser);
1078
1079 browser->Freeze();
1080 if (restore && server->GetRestore())
1081 item = RestoreEnvironment(server);
1082 else
1083 item = server->GetId();
1084 browser->Thaw();
1085
1086 if (item)
1087 {
1088 browser->SelectItem(item);
1089
1090 wxSafeYield();
1091 browser->Expand(item);
1092 browser->EnsureVisible(item);
1093 }
1094
1095 if (item)
1096 EndMsg(true);
1097 else
1098 {
1099 if (restore && server->GetRestore())
1100 EndMsg(false);
1101 else
1102 EndMsg(true);
1103 }
1104 if (item)
1105 GetMenuFactories()->CheckMenu((pgObject *)browser->GetItemData(item), GetMenuBar(), (ctlMenuToolbar *)GetToolBar());
1106 else
1107 GetMenuFactories()->CheckMenu(server, GetMenuBar(), (ctlMenuToolbar *)GetToolBar());
1108 browser->SetFocus();
1109 return res;
1110 }
1111 case PGCONN_DNSERR:
1112 /*
1113 // looks strange to me. Shouldn_t server be removed from the tree as well?
1114 delete server;
1115 OnAddServer(wxCommandEvent());
1116 break;
1117 */
1118 case PGCONN_BAD:
1119 ReportConnError(server);
1120 break;
1121
1122 default:
1123 wxLogInfo(wxT("pgServer object didn't initialise because the user aborted."));
1124 break;
1125 }
1126
1127 server->Disconnect(this);
1128 return res;
1129 }
1130
1131
reportError(const wxString & error,const wxString & msgToIdentify,const wxString & hint)1132 bool frmMain::reportError(const wxString &error, const wxString &msgToIdentify, const wxString &hint)
1133 {
1134 bool identified = false;
1135
1136 wxString translated = wxGetTranslation(msgToIdentify);
1137 if (translated != msgToIdentify)
1138 {
1139 identified = (error.Find(translated) >= 0);
1140 }
1141
1142 if (!identified)
1143 {
1144 if (msgToIdentify.Left(20) == wxT("Translator attention"))
1145 identified = (error.Find(msgToIdentify.Mid(msgToIdentify.Find('!') + 1)) >= 0);
1146 else
1147 identified = (error.Find(msgToIdentify) >= 0);
1148 }
1149
1150 if (identified)
1151 {
1152 if (frmHint::WantHint(hint))
1153 frmHint::ShowHint(this, hint, error);
1154 }
1155 return identified;
1156 }
1157
1158
ReportConnError(pgServer * server)1159 void frmMain::ReportConnError(pgServer *server)
1160 {
1161 wxString error = server->GetLastError();
1162 bool wantHint = false;
1163
1164 wantHint = reportError(error, __("Translator attention: must match libpq translation!Is the server running on host"), HINT_CONNECTSERVER);
1165 if (!wantHint)
1166 {
1167 wantHint = reportError(error, __("Translator attention: must match backend translation!no pg_hba.conf entry for"), HINT_MISSINGHBA);
1168 }
1169 if (!wantHint)
1170 {
1171 wantHint = reportError(error, __("Translator attention: must match backend translation!Ident authentication failed"), HINT_MISSINGIDENT);
1172 }
1173 if (!wantHint)
1174 {
1175 wxLogError(__("Error connecting to the server: %s"), error.c_str());
1176 }
1177 }
1178
1179
StoreServers()1180 void frmMain::StoreServers()
1181 {
1182 wxLogInfo(wxT("Storing listed servers for later..."));
1183
1184 // Store the currently listed servers for later retrieval.
1185 pgServer *server;
1186 int numServers = 0;
1187
1188 // Get the hostname for later...
1189 char buf[255];
1190 gethostname(buf, 255);
1191 wxString hostname = wxString(buf, wxConvUTF8);
1192
1193 wxTreeItemIdValue foldercookie;
1194 wxTreeItemId folderitem = browser->GetFirstChild(browser->GetRootItem(), foldercookie);
1195 while (folderitem)
1196 {
1197 if (browser->ItemHasChildren(folderitem))
1198 {
1199 wxTreeItemIdValue servercookie;
1200 wxTreeItemId serveritem = browser->GetFirstChild(folderitem, servercookie);
1201 while (serveritem)
1202 {
1203 server = (pgServer *)browser->GetItemData(serveritem);
1204 if (server != NULL && server->IsCreatedBy(serverFactory))
1205 {
1206 wxString key;
1207 ++numServers;
1208
1209 key.Printf(wxT("Servers/%d/"), numServers);
1210 settings->Write(key + wxT("Server"), server->GetName());
1211 settings->Write(key + wxT("HostAddr"), server->GetHostAddr());
1212 settings->Write(key + wxT("Description"), server->GetDescription());
1213 settings->Write(key + wxT("Service"), server->GetService());
1214 settings->Write(key + wxT("ServiceID"), server->GetServiceID());
1215 settings->Write(key + wxT("DiscoveryID"), server->GetDiscoveryID());
1216 settings->WriteInt(key + wxT("Port"), server->GetPort());
1217 settings->WriteBool(key + wxT("StorePwd"), server->GetStorePwd());
1218 settings->Write(key + wxT("Rolename"), server->GetRolename());
1219 settings->WriteBool(key + wxT("Restore"), server->GetRestore());
1220 settings->Write(key + wxT("Database"), server->GetDatabaseName());
1221 settings->Write(key + wxT("Username"), server->GetUsername());
1222 settings->Write(key + wxT("LastDatabase"), server->GetLastDatabase());
1223 settings->Write(key + wxT("LastSchema"), server->GetLastSchema());
1224 settings->Write(key + wxT("DbRestriction"), server->GetDbRestriction());
1225 settings->Write(key + wxT("Colour"), server->GetColour());
1226 settings->WriteInt(key + wxT("SSL"), server->GetSSL());
1227 settings->Write(key + wxT("Group"), server->GetGroup());
1228 settings->Write(key + wxT("SSLCert"), server->GetSSLCert());
1229 settings->Write(key + wxT("SSLKey"), server->GetSSLKey());
1230 settings->Write(key + wxT("SSLRootCert"), server->GetSSLRootCert());
1231 settings->Write(key + wxT("SSLCrl"), server->GetSSLCrl());
1232 settings->WriteBool(key + wxT("SSLCompression"), server->GetSSLCompression());
1233 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
1234 settings->WriteBool(key + wxT("SSHTunnel"), server->GetSSHTunnel());
1235 settings->Write(key + wxT("TunnelHost"), server->GetTunnelHost());
1236 settings->Write(key + wxT("TunnelUserName"), server->GetTunnelUserName());
1237 settings->WriteBool(key + wxT("TunnelModePwd"), server->GetAuthModePwd());
1238 settings->Write(key + wxT("PublicKeyFile"), server->GetPublicKeyFile());
1239 settings->Write(key + wxT("IdentityFile"), server->GetIdentityFile());
1240 settings->WriteInt(key + wxT("TunnelPort"), server->GetTunnelPort());
1241 #endif
1242 pgCollection *coll = browser->FindCollection(databaseFactory, server->GetId());
1243 if (coll)
1244 {
1245 treeObjectIterator dbs(browser, coll);
1246 pgDatabase *db;
1247
1248 while ((db = (pgDatabase *)dbs.GetNextObject()) != 0)
1249 settings->Write(key + wxT("Databases/") + db->GetName() + wxT("/SchemaRestriction"), db->GetSchemaRestriction());
1250 }
1251 }
1252 serveritem = browser->GetNextChild(folderitem, servercookie);
1253 }
1254 }
1255 folderitem = browser->GetNextChild(browser->GetRootItem(), foldercookie);
1256 }
1257
1258 // Write the server count
1259 settings->WriteInt(wxT("Servers/Count"), numServers);
1260 settings->FlushChanges();
1261 wxLogInfo(wxT("Stored %d servers."), numServers);
1262 }
1263
1264
RetrieveServers()1265 void frmMain::RetrieveServers()
1266 {
1267 wxString label;
1268 int total = 0;
1269 wxTreeItemIdValue groupcookie;
1270 wxTreeItemId groupitem;
1271
1272 // Retrieve previously stored servers
1273 wxLogInfo(wxT("Reloading servers..."));
1274
1275 // Create all servers' nodes
1276 serverFactory.CreateObjects(serversObj, browser);
1277
1278 // Count number of servers and groups
1279 groupitem = browser->GetFirstChild(browser->GetRootItem(), groupcookie);
1280 while (groupitem)
1281 {
1282 total = browser->GetChildrenCount(groupitem, false);
1283 label = browser->GetItemText(groupitem) + wxT(" (") + NumToStr((long)total) + wxT(")");
1284 browser->SetItemText(groupitem, label);
1285 browser->SortChildren(groupitem);
1286 browser->Expand(groupitem);
1287 groupitem = browser->GetNextChild(browser->GetRootItem(), groupcookie);
1288 }
1289 }
1290
ConnectToServer(const wxString & servername,bool restore)1291 pgServer *frmMain::ConnectToServer(const wxString &servername, bool restore)
1292 {
1293 wxTreeItemIdValue foldercookie, servercookie;
1294 wxTreeItemId folderitem, serveritem;
1295 pgObject *object;
1296 pgServer *server;
1297
1298 folderitem = browser->GetFirstChild(browser->GetRootItem(), foldercookie);
1299 while (folderitem)
1300 {
1301 if (browser->ItemHasChildren(folderitem))
1302 {
1303 serveritem = browser->GetFirstChild(folderitem, servercookie);
1304 while (serveritem)
1305 {
1306 object = browser->GetObject(serveritem);
1307 if (object && object->IsCreatedBy(serverFactory))
1308 {
1309 server = (pgServer *)object;
1310 if (server->GetDescription() == servername)
1311 {
1312 ReconnectServer(server, restore);
1313 return server;
1314 }
1315 }
1316 serveritem = browser->GetNextChild(folderitem, servercookie);
1317 }
1318 }
1319 folderitem = browser->GetNextChild(browser->GetRootItem(), foldercookie);
1320 }
1321
1322 return 0;
1323 }
1324
StartMsg(const wxString & msg)1325 void frmMain::StartMsg(const wxString &msg)
1326 {
1327 if (msgLevel++)
1328 return;
1329
1330 timermsg.Printf(wxT("%s..."), msg.c_str());
1331 wxBeginBusyCursor();
1332 stopwatch.Start(0);
1333
1334 // Create a copy of the message, with %'s escaped for wxLogStatus
1335 wxString logmsg = timermsg;
1336 logmsg.Replace(wxT("%"), wxT("%%"));
1337 wxLogStatus(logmsg);
1338
1339 statusBar->SetStatusText(timermsg, 1);
1340 statusBar->SetStatusText(wxT(""), 2);
1341 }
1342
1343
EndMsg(bool done)1344 void frmMain::EndMsg(bool done)
1345 {
1346 msgLevel--;
1347
1348 if (!msgLevel)
1349 {
1350 // Get the execution time & display it
1351 float timeval = stopwatch.Time();
1352 statusBar->SetStatusText(ElapsedTimeToStr(timeval), 3);
1353
1354 // Display the name of the connection for currently selected object
1355 wxString connection;
1356 if (currentObject)
1357 {
1358 pgConn *conn = currentObject->GetConnection();
1359
1360 if (conn)
1361 connection = conn->GetName();
1362 }
1363 statusBar->SetStatusText(connection, 2);
1364
1365 // Display the 'Done' message
1366 if (done)
1367 statusBar->SetStatusText(timermsg + _(" Done."), 1);
1368 else
1369 statusBar->SetStatusText(timermsg + _(" Failed."), 1);
1370
1371 wxLogStatus(
1372 wxT("%s (%s)"), timermsg.c_str(),
1373 ElapsedTimeToStr(timeval).c_str()
1374 );
1375 wxEndBusyCursor();
1376 }
1377 }
1378
1379
SetStatusText(const wxString & msg)1380 void frmMain::SetStatusText(const wxString &msg)
1381 {
1382 statusBar->SetStatusText(msg, 1);
1383 statusBar->SetStatusText(wxEmptyString, 2);
1384 }
1385
SetItemBackgroundColour(wxTreeItemId item,wxColour colour)1386 void frmMain::SetItemBackgroundColour(wxTreeItemId item, wxColour colour)
1387 {
1388 wxTreeItemIdValue cookie;
1389
1390 browser->SetItemBackgroundColour(item, wxColour(colour));
1391 if (browser->ItemHasChildren(item))
1392 {
1393 wxTreeItemId childitem = browser->GetFirstChild(item, cookie);
1394 while (childitem)
1395 {
1396 SetItemBackgroundColour(childitem, colour);
1397 childitem = browser->GetNextChild(item, cookie);
1398 }
1399 }
1400 }
1401
1402 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
OnSSHTunnelEvent(wxCommandEvent & event)1403 void frmMain::OnSSHTunnelEvent(wxCommandEvent &event)
1404 {
1405 wxLogError(event.GetString());
1406 }
1407 #endif
1408
1409 /////////////////////////////////////////
1410
1411
contentsFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)1412 contentsFactory::contentsFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : actionFactory(list)
1413 {
1414 mnu->Append(id, _("&Help contents"), _("Open the helpfile."));
1415 }
1416
1417
StartDialog(frmMain * form,pgObject * obj)1418 wxWindow *contentsFactory::StartDialog(frmMain *form, pgObject *obj)
1419 {
1420 DisplayHelp(wxT("index"), HELP_PGADMIN);
1421 return 0;
1422 }
1423
1424
faqFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)1425 faqFactory::faqFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : actionFactory(list)
1426 {
1427 mnu->Append(id, _("&FAQ"), _("Frequently asked questions."));
1428 }
1429
1430
StartDialog(frmMain * form,pgObject * obj)1431 wxWindow *faqFactory::StartDialog(frmMain *form, pgObject *obj)
1432 {
1433 wxLaunchDefaultBrowser(wxT("http://www.pgadmin.org/support/faq.php"));
1434
1435 return 0;
1436 }
1437
1438 #include "images/help.pngc"
1439 #include "images/help2.pngc"
pgsqlHelpFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar,bool bigIcon)1440 pgsqlHelpFactory::pgsqlHelpFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar, bool bigIcon) : actionFactory(list)
1441 {
1442 mnu->Append(id, _("&PostgreSQL Help"), _("Display help on the PostgreSQL database system."));
1443 if (toolbar)
1444 {
1445 if (bigIcon)
1446 toolbar->AddTool(id, wxEmptyString, *help2_png_bmp, _("Display help on SQL commands."));
1447 else
1448 toolbar->AddTool(id, wxEmptyString, *help_png_bmp, _("Display help on SQL commands."));
1449 }
1450 }
1451
1452
StartDialog(frmMain * form,pgObject * obj)1453 wxWindow *pgsqlHelpFactory::StartDialog(frmMain *form, pgObject *obj)
1454 {
1455 DisplayHelp(wxT("index"), HELP_POSTGRESQL);
1456 return 0;
1457 }
1458
edbHelpFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar,bool bigIcon)1459 edbHelpFactory::edbHelpFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar, bool bigIcon) : actionFactory(list)
1460 {
1461 mnu->Append(id, _("&EnterpriseDB Help"), _("Display help on the EnterpriseDB database system."));
1462 }
1463
1464
StartDialog(frmMain * form,pgObject * obj)1465 wxWindow *edbHelpFactory::StartDialog(frmMain *form, pgObject *obj)
1466 {
1467 DisplayHelp(wxT("index"), HELP_ENTERPRISEDB);
1468 return 0;
1469 }
1470
greenplumHelpFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar,bool bigIcon)1471 greenplumHelpFactory::greenplumHelpFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar, bool bigIcon) : actionFactory(list)
1472 {
1473 mnu->Append(id, _("&Greenplum Database Help"), _("Display help on the Greenplum Database system."));
1474 }
1475
1476
StartDialog(frmMain * form,pgObject * obj)1477 wxWindow *greenplumHelpFactory::StartDialog(frmMain *form, pgObject *obj)
1478 {
1479 DisplayHelp(wxT("index"), HELP_GREENPLUM);
1480 return 0;
1481 }
1482
1483
slonyHelpFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar,bool bigIcon)1484 slonyHelpFactory::slonyHelpFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar, bool bigIcon) : actionFactory(list)
1485 {
1486 mnu->Append(id, _("&Slony Help"), _("Display help on the Slony replication system."));
1487 }
1488
1489
StartDialog(frmMain * form,pgObject * obj)1490 wxWindow *slonyHelpFactory::StartDialog(frmMain *form, pgObject *obj)
1491 {
1492 DisplayHelp(wxT("index"), HELP_SLONY);
1493 return 0;
1494 }
1495
bugReportFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)1496 bugReportFactory::bugReportFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : actionFactory(list)
1497 {
1498 mnu->Append(id, _("&Bug Report"), _("How to send a bugreport to the pgAdmin Development Team."));
1499 }
1500
1501
StartDialog(frmMain * form,pgObject * obj)1502 wxWindow *bugReportFactory::StartDialog(frmMain *form, pgObject *obj)
1503 {
1504 DisplayHelp(wxT("bugreport"), HELP_PGADMIN);
1505 return 0;
1506 }
1507