From 34528cf32340b4d003f5597fd0862b691e757345 Mon Sep 17 00:00:00 2001
From: Jasmin Dizdarevic <jasmin.dizdarevic@gmail.com>
Date: Wed, 15 Jun 2011 00:55:27 +0200
Subject: [PATCH 2/2] Search: Added missing objects, outside database objects, changed UI, bugfixes,...

---
 pgadmin/frm/frmMain.cpp         |    6 ++-
 pgadmin/frm/frmSearchObject.cpp |  117 ++++++++++++++++++++++++++++++------
 pgadmin/frm/module.mk           |    1 +
 pgadmin/include/frm/module.mk   |    1 +
 pgadmin/ui/frmSearchObject.xrc  |  128 ++++++++++++++++++++++++++++-----------
 pgadmin/ui/module.mk            |    3 +-
 6 files changed, 200 insertions(+), 56 deletions(-)

diff --git a/pgadmin/frm/frmMain.cpp b/pgadmin/frm/frmMain.cpp
index 50580c6..fc78705 100644
--- a/pgadmin/frm/frmMain.cpp
+++ b/pgadmin/frm/frmMain.cpp
@@ -147,6 +147,8 @@ frmMain::frmMain(const wxString &title)
 	dependencies = new ctlListView(listViews, CTL_DEPVIEW, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER);
 	dependents = new ctlListView(listViews, CTL_REFVIEW, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER);
 
+	
+
 	// Switch back to the native list control.
 #ifdef __WXMAC__
 	wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), false);
@@ -683,8 +685,10 @@ bool frmMain::SetCurrentNode(wxTreeItemId node, const wxString &origPath)
 
 		if(path.StartsWith(actNodePath))
 		{	
-			if(!browser->IsExpanded(child))
+			if(!browser->IsExpanded(child)) {
+				browser->SelectItem(child, true);
 				browser->Expand(child);
+			}
 
 			if (actNodePath == path)
 			{
diff --git a/pgadmin/frm/frmSearchObject.cpp b/pgadmin/frm/frmSearchObject.cpp
index 4240a01..d148fca 100644
--- a/pgadmin/frm/frmSearchObject.cpp
+++ b/pgadmin/frm/frmSearchObject.cpp
@@ -77,13 +77,21 @@ frmSearchObject::frmSearchObject(frmMain *p, pgDatabase *db)
 	aMap[_("Languages")] = wxT("Languages");
 	aMap[_("Conversions")] = wxT("Conversions");
 	aMap[_("Casts")] = wxT("Casts");
+	aMap[_("Login Roles")] = wxT("Login Roles");
+	aMap[_("Group Roles")] = wxT("Group Roles");
 	aMap[_("FTS Configurations")] = wxT("FTS Configurations");
 	aMap[_("FTS Dictionarie")] = wxT("FTS Dictionaries");
 	aMap[_("FTS Parsers")] = wxT("FTS Parsers");
 	aMap[_("FTS Templates")] = wxT("FTS Templates");
 	aMap[_("Foreign Data Wrappers")] = wxT("Foreign Data Wrappers");
+	aMap[_("Foreign Servers")] = wxT("Foreign Servers");
+	aMap[_("User Mappings")] = wxT("User Mappings");
+	aMap[_("Operators")] = wxT("Operators");
+	aMap[_("Operator Classes")] = wxT("Operator Classes");
+	aMap[_("Operator Families")] = wxT("Operator Families");
 	
-	/* Duplicate definition, if somebody knows hwo to sort wxHashTable, please make it better and use the iteration to fill the combobox:
+	/* Duplicate definition, if somebody knows how to use wxHashTable to fill the dropdown, please make it better and use the iteration to fill the combobox:
+	The problem is, that the hash table is automatically sorted and that's unuseable. 
 
 	LngMapping::iterator it;
 	for(it = aMap.begin(); it != aMap.end(); ++it) 
@@ -111,11 +119,18 @@ frmSearchObject::frmSearchObject(frmMain *p, pgDatabase *db)
 	cbType->Append(_("Domains"));
 	cbType->Append(_("Conversions"));
 	cbType->Append(_("Casts"));
+	cbType->Append(_("Login Roles"));
+	cbType->Append(_("Group Roles"));
 	cbType->Append(_("FTS Configurations"));
 	cbType->Append(_("FTS Dictionaries"));
 	cbType->Append(_("FTS Parsers"));
 	cbType->Append(_("FTS Templates"));
 	cbType->Append(_("Foreign Data Wrappers"));
+	cbType->Append(_("Foreign Servers"));
+	cbType->Append(_("User Mappings"));
+	cbType->Append(_("Operators"));
+	cbType->Append(_("Operator Classes"));
+	cbType->Append(_("Operator Families"));
 	cbType->SetSelection(0);
 		
 
@@ -169,13 +184,15 @@ void frmSearchObject::OnSelSearchResult(wxListEvent &ev)
 }
 
 void frmSearchObject::OnChange(wxCommandEvent &ev) {
-	if(txtPattern->GetValue().Length() >= 3) 
+
+	/* When someone searches for operators the limit of 3 characters is ignored */
+	if(aMap[cbType->GetValue()] != wxT("Operators") && txtPattern->GetValue().Length() < 3) 
 	{
-		btnSearch->Enable();
+		btnSearch->Disable();
 	}
 	else 
 	{
-		btnSearch->Disable();
+		btnSearch->Enable();
 	}
 }
 
@@ -210,15 +227,16 @@ void frmSearchObject::OnSearch(wxCommandEvent &ev)
 							wxT("	LEFT JOIN pg_namespace n ON n.oid = c.relnamespace     ")
 							wxT("	WHERE c.relkind in ('r','S','v')  ")
 							wxT("	union  ")
-							wxT("	SELECT 'Index', i.relname AS objectname, ':Schemas/' || n.nspname ||'/:Tables/'|| c.relname || '/' || i.relname as path  ")
+							wxT("	SELECT 'Index', i.relname AS objectname, ':Schemas/' || n.nspname ||'/:Tables/'|| c.relname || '/:Indexes/' || i.relname as path  ")
 							wxT("	FROM pg_index x  ")
 							wxT("	JOIN pg_class c ON c.oid = x.indrelid  ")
 							wxT("	JOIN pg_class i ON i.oid = x.indexrelid  ")
 							wxT("	LEFT JOIN pg_namespace n ON n.oid = c.relnamespace  ")
 							wxT("	LEFT JOIN pg_tablespace t ON t.oid = i.reltablespace  ")
-							wxT("	WHERE c.relkind = 'r' AND i.relkind = 'i'  ")
+							wxT("	LEFT JOIN pg_constraint xc on x.indexrelid = xc.conindid ")
+							wxT("	WHERE c.relkind = 'r' AND i.relkind = 'i' and coalesce(xc.contype,'x') != 'p' ")
 							wxT("	union  ")
-							wxT("	select case when t.typname = 'Triggers' then 'Trigger Functions' else 'Functions' end as type, p.proname,  ")
+							wxT("	select case when t.typname = 'trigger' then 'Trigger Functions' else 'Functions' end as type, p.proname,  ")
 							wxT("	':Schemas/' || n.nspname || '/' || case when t.typname = 'trigger' then ':Trigger Functions' else ':Functions' end || '/' || p.proname ")
 							wxT("	from pg_proc p  ")
 							wxT("	left join pg_namespace n on p.pronamespace = n.oid  ")
@@ -238,8 +256,9 @@ void frmSearchObject::OnSearch(wxCommandEvent &ev)
 							wxT("	inner join pg_class t on a.attrelid = t.oid and t.relkind in ('r','v')  ")
 							wxT("	left join pg_namespace n on t.relnamespace = n.oid where a.attnum > 0  ")
 							wxT("	union  ")
-							wxT("	select 'Constraints', c.conname, ':Schemas/' || n.nspname||'/:Tables/'||t.relname||'/:Constraints/'||c.conname from pg_constraint c  ")
+							wxT("	select 'Constraints', case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end, ':Schemas/' || n.nspname||'/:Tables/'||t.relname||'/:Constraints/'||case when tf.relname is null then c.conname else c.conname || ' -> ' || tf.relname end from pg_constraint c    ")
 							wxT("	left join pg_class t on c.conrelid = t.oid  ")
+							wxT("	left join pg_class tf on c.confrelid = tf.oid  ")
 							wxT("	left join pg_namespace n on t.relnamespace = n.oid 						 ")
 							wxT("	union  ")
 							wxT("	select 'Rules', r.rulename, ':Schemas/' || n.nspname||'/:Views/'||t.relname||'/:Rules/'|| r.rulename from pg_rewrite r  ")
@@ -296,6 +315,31 @@ void frmSearchObject::OnSearch(wxCommandEvent &ev)
 							wxT("	left join pg_namespace ns on  pr.pronamespace = ns.oid ")
 							wxT("	union ")
 							wxT("	select 'Foreign Data Wrappers', fdwname, ':Foreign Data Wrappers/' || fdwname from pg_foreign_data_wrapper ")
+							wxT("	union ")
+							wxT("	select case when rolcanlogin = true then 'Login Roles' else 'Group Roles' end, rolname, case when rolcanlogin = true then ':Login Roles' else ':Group Roles' end || '/' || rolname ")
+							wxT("	from pg_roles ")
+							wxT("	union ")
+							wxT("	select 'Tablespaces', spcname, ':Tablespaces/'||spcname from pg_tablespace ")
+							wxT("	union ")
+							wxT("	SELECT 'Operators', op.oprname, ':Schemas/' || ns.nspname || '/:Operators/' || op.oprname ")
+						    wxT("	FROM pg_operator op ")
+							wxT("	left join pg_namespace ns on op.oprnamespace = ns.oid ")
+							wxT("	union ")
+							wxT("	SELECT 'Operator Classes', op.opcname, ':Schemas/' || ns.nspname || '/:Operator Classes/' || op.opcname ")
+							wxT("	FROM pg_opclass op ")
+							wxT("	left join pg_namespace ns on op.opcnamespace = ns.oid ")
+							wxT("	union ")
+							wxT("	SELECT 'Operator Families', opf.opfname, ':Schemas/' || ns.nspname || '/:Operator Families/' || opf.opfname ")
+							wxT("	FROM pg_opfamily opf ")
+							wxT("	left join pg_namespace ns on opf.opfnamespace = ns.oid ")
+							wxT("	union ")
+							wxT("	select 'Foreign Server', sr.srvname, ':Foreign Data Wrappers/' || fdw.fdwname || '/:Foreign Servers/' || sr.srvname from pg_foreign_server sr ")
+							wxT("	inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid ")
+							wxT("	union ")
+							wxT("	select 'User Mappings', ro.rolname, ':Foreign Data Wrappers/' || fdw.fdwname || '/:Foreign Servers/' || sr.srvname || '/:User Mappings/' || ro.rolname from pg_user_mapping um ")
+							wxT("	inner join pg_roles ro on um.umuser = ro.oid ")
+							wxT("	inner join pg_foreign_server sr on um.umserver = sr.oid ")
+							wxT("	inner join pg_foreign_data_wrapper fdw on sr.srvfdw = fdw.oid ")
 							wxT(") i ") 
 						wxT("where lower(i.objectname) like '%") + txtPattern->GetValue().Lower() + wxT("%' ");
 						if(cbType->GetValue() != _("All types")) 
@@ -311,32 +355,69 @@ void frmSearchObject::OnSearch(wxCommandEvent &ev)
 	int i = 0;
 	if(set) 
 	{
-		lcResults->DeleteAllItems();
+		lcResults->DeleteAllItems();		
+
 		while(!set->Eof()) 
-		{
-			wxListItem item;	
-			item.SetId(i);
-			lcResults->InsertItem(item);
+		{			
+			wxString objectType = set->GetVal(wxT("type"));
+			wxString objectName = set->GetVal(wxT("objectname"));
+			wxString ItemPath;
+
+
+			/* Login Roles, Group Roles and Tablespaces are "outside" the database, so we have to adjust the path */
+			if(objectType == wxT("Login Roles") || objectType == wxT("Group Roles") || objectType == wxT("Tablespaces"))
+			{
+				wxStringTokenizer tkz(databasePath, wxT("/"));
+				wxString newPath;
+				while(tkz.HasMoreTokens()) 
+				{
+					wxString token = tkz.GetNextToken();
+					if(token == _("Databases"))
+						break;
+					ItemPath += token + wxT("/");
+				}
+				ItemPath += set->GetVal(wxT("path"));
+			}
+			else
+			{
+				ItemPath = databasePath + wxT("/") + set->GetVal(wxT("path"));
+			}
 
-			wxString ItemPath = databasePath + wxT("/") + set->GetVal(wxT("path"));
+			
 			if(ItemPath.Contains(wxT("Schemas/information_schema")))
 			{
-				ItemPath.Replace(wxT("Schemas/information_schema"), wxT("Catalogs/ANSI"));
+				/* In information Schema only views and columns are displayed, nothing else */
+
+				if(objectType == wxT("Views") || objectType == wxT("Columns")) 
+				{					
+					ItemPath.Replace(wxT(":Schemas/information_schema"), wxT(":Catalogs/ANSI/:Catalog Objects"));
+					ItemPath.Replace(wxT(":Views/"), wxT(""));
+				}
+				else {
+					set->MoveNext();
+					continue;
+				}
+
 			}
 			if(ItemPath.Contains(wxT("Schemas/pg_catalog")))
 			{
-				ItemPath.Replace(wxT("Schemas/pg_catalog"), wxT("Catalogs/PostgreSQL"));
+				ItemPath.Replace(wxT(":Schemas/pg_catalog"), wxT(":Catalogs/PostgreSQL"));
 			}
 
+			wxListItem item;	
+			item.SetId(i);
+			lcResults->InsertItem(item);
+
 			wxString locTypeStr = wxGetTranslation(set->GetVal(wxT("type")));
 
+			/* Check if viewing of the sepcified object is enabled in settings */
 			if(!settings->GetDisplayOption(locTypeStr)) 
 			{				
 				lcResults->SetItemTextColour(i, wxColour(128,128,128));
 			}
 
 			lcResults->SetItem(i, 0, locTypeStr);
-			lcResults->SetItem(i, 1, set->GetVal(wxT("objectname")));
+			lcResults->SetItem(i, 1, objectName);
 			lcResults->SetItem(i, 2, TranslatePath(ItemPath));
 			set->MoveNext();
 			i++;
@@ -353,7 +434,7 @@ void frmSearchObject::OnSearch(wxCommandEvent &ev)
 
 wxString frmSearchObject::TranslatePath(wxString &path) 
 {
-	
+	/* Translate a path, but only word that start's with a colon (:) */
 	wxStringTokenizer tkz(path, wxT("/"));
 	wxString newPath;
 	while(tkz.HasMoreTokens()) 
diff --git a/pgadmin/frm/module.mk b/pgadmin/frm/module.mk
index 5ea77e4..329cc04 100644
--- a/pgadmin/frm/module.mk
+++ b/pgadmin/frm/module.mk
@@ -30,6 +30,7 @@ pgadmin3_SOURCES += \
 	$(srcdir)/frm/frmQuery.cpp \
 	$(srcdir)/frm/frmReport.cpp \
 	$(srcdir)/frm/frmRestore.cpp \
+	$(srcdir)/frm/frmSearchObject.cpp \
 	$(srcdir)/frm/frmSplash.cpp \
 	$(srcdir)/frm/frmStatus.cpp \
 	$(srcdir)/frm/plugins.cpp
diff --git a/pgadmin/include/frm/module.mk b/pgadmin/include/frm/module.mk
index 8a03e5c..1ca9768 100644
--- a/pgadmin/include/frm/module.mk
+++ b/pgadmin/include/frm/module.mk
@@ -29,6 +29,7 @@ pgadmin3_SOURCES += \
 	$(srcdir)/include/frm/frmQuery.h \
 	$(srcdir)/include/frm/frmReport.h \
 	$(srcdir)/include/frm/frmRestore.h \
+	$(srcdir)/include/frm/frmSearchObject.h \
 	$(srcdir)/include/frm/frmSplash.h \
 	$(srcdir)/include/frm/frmStatus.h \
     $(srcdir)/include/frm/menu.h
diff --git a/pgadmin/ui/frmSearchObject.xrc b/pgadmin/ui/frmSearchObject.xrc
index 13b7909..a36d60e 100644
--- a/pgadmin/ui/frmSearchObject.xrc
+++ b/pgadmin/ui/frmSearchObject.xrc
@@ -3,42 +3,98 @@
   <object class="wxDialog" name="frmSearchObject">
     <title>Search Objects</title>
     <size>353,40d</size>
-    <style>wxDEFAULT_DIALOG_STYLE</style>
-    <object class="wxStaticText" name="stTitle">
-      <label>Search pattern</label>
-      <pos>5,5d</pos>
-    </object>
-    <object class="wxTextCtrl" name="txtPattern">
-      <pos>5,15d</pos>
-      <size>290,-1d</size>
-      <tooltip>Enter part of the object's name you're looking for</tooltip>
-    </object>        
-    <object class="wxButton" name="btnSearch">
-      <label>Find</label>
-      <default>1</default>
-      <pos>300,14d</pos>      
-      <style></style>
-    </object>
-    <object class="wxComboBox" name="cbType">
-      <pos>5,30d</pos>
-      <size>196,-1d</size>
-      <content/>
-      <style>wxCB_READONLY|wxCB_DROPDOWN</style>
-    </object>
-    <object class="wxListCtrl" name="lcResults">
-      <pos>10,80</pos>
-      <size>340,150d</size>
-      <style>wxLC_REPORT</style>
-    </object>
-    <object class="wxButton" name="wxID_HELP">
-      <label>&amp;Help</label>
-      <pos>2,200d</pos>
-      <style></style>
-    </object>    
-    <object class="wxButton" name="wxID_CANCEL">
-      <label>&amp;Close</label>
-      <default>0</default>
-      <pos>300,200d</pos>
+    <style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>
+    <object class="wxFlexGridSizer">
+      <cols>2</cols>
+      <rows>4</rows>
+      <vgap>3</vgap>
+      <hgap>3</hgap>
+      <growablecols>1</growablecols>
+      <growablerows>2</growablerows>
+      <object class="sizeritem">
+        <object class="wxStaticText" name="stFilename">
+          <label>Pattern</label>
+        </object>
+        <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+        <border>4</border>
+      </object>
+      <object class="sizeritem">
+        <object class="wxFlexGridSizer">
+          <cols>2</cols>
+          <rows>1</rows>
+          <vgap>5</vgap>
+          <hgap>5</hgap>
+          <growablecols>0</growablecols>
+          <growablerows>2</growablerows>
+          <object class="sizeritem">
+            <object class="wxTextCtrl" name="txtPattern">              
+              <size>200,-1d</size>
+              <tooltip>Enter part of the object's name you're looking for</tooltip>
+            </object>
+            <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+            <border>4</border>
+          </object>
+          <object class="sizeritem">
+            <object class="wxButton" name="btnSearch">
+              <label>Find</label>
+              <default>1</default>
+              <pos>300,14d</pos>
+              <style></style>
+            </object>
+            <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+            <border>4</border>
+          </object>
+          <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+          <border>4</border>
+        </object>
+        <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+        <border>4</border>
+      </object>
+      <object class="sizeritem">
+        <object class="wxStaticText" name="stFormat">
+          <label>Type</label>
+        </object>
+        <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+        <border>4</border>
+      </object>
+      <object class="sizeritem">
+        <object class="wxComboBox" name="cbType">          
+          <size>196,-1d</size>
+          <content/>
+          <style>wxCB_READONLY|wxCB_DROPDOWN</style>
+        </object>
+        <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+        <border>4</border>
+      </object>
+      <object class="sizeritem">
+        <object class="wxStaticText" name="stCompressRatio">
+          <label>Result</label>
+        </object>
+        <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+        <border>4</border>
+      </object>
+      <object class="sizeritem">
+        <object class="wxListCtrl" name="lcResults">
+          <pos>10,80</pos>
+          <size>340,150d</size>
+          <style>wxLC_REPORT</style>
+        </object>
+        <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT|wxBOTTOM</flag>
+        <border>4</border>
+      </object>    
+      <object class="sizeritem">
+        <object class="wxButton" name="wxID_HELP">
+          <label>&amp;Help</label>
+          <flag>wxALL|wxALIGN_RIGHT</flag>
+        </object>
+      </object>
+      <object class="sizeritem">
+        <object class="wxButton" name="wxID_CANCEL">
+          <label>&amp;Close</label>
+          <default>0</default>          
+        </object>
+        <flag>wxALL|wxALIGN_RIGHT</flag>
+      </object>
     </object>
   </object>
 </resource>
\ No newline at end of file
diff --git a/pgadmin/ui/module.mk b/pgadmin/ui/module.mk
index 21a62bb..1cfda1f 100644
--- a/pgadmin/ui/module.mk
+++ b/pgadmin/ui/module.mk
@@ -87,7 +87,8 @@ TMP_ui += \
 	$(srcdir)/ui/frmOptions.xrc \
 	$(srcdir)/ui/frmPassword.xrc \
 	$(srcdir)/ui/frmReport.xrc \
-	$(srcdir)/ui/frmRestore.xrc
+	$(srcdir)/ui/frmRestore.xrc \
+	$(srcdir)/ui/frmSearchObject.xrc
 
 EXTRA_DIST += \
 	$(srcdir)/ui/module.mk \
-- 
1.7.3.1.msysgit.0
