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