From f66bc520ea7554ec9054372a49924f9b3f19ea3d Mon Sep 17 00:00:00 2001
From: Guillaume Lelarge <guillaume@lelarge.info>
Date: Sun, 27 Mar 2011 10:01:26 +0200
Subject: [PATCH] Support for extension object.

---
 pgadmin/dlg/dlgExtension.cpp            |  198 +++++++++++++++++++++++++++
 pgadmin/dlg/module.mk                   |    1 +
 pgadmin/frm/frmOptions.cpp              |    1 +
 pgadmin/include/dlg/dlgExtension.h      |   42 ++++++
 pgadmin/include/dlg/module.mk           |    1 +
 pgadmin/include/images/extension-sm.png |  Bin 0 -> 423 bytes
 pgadmin/include/images/extension.png    |  Bin 0 -> 996 bytes
 pgadmin/include/images/extensions.png   |  Bin 0 -> 1017 bytes
 pgadmin/include/images/module.mk        |    3 +
 pgadmin/include/schema/module.mk        |    1 +
 pgadmin/include/schema/pgExtension.h    |   93 +++++++++++++
 pgadmin/schema/module.mk                |    1 +
 pgadmin/schema/pgDatabase.cpp           |    5 +
 pgadmin/schema/pgExtension.cpp          |  225 +++++++++++++++++++++++++++++++
 pgadmin/ui/dlgExtension.xrc             |  160 ++++++++++++++++++++++
 pgadmin/ui/module.mk                    |    1 +
 16 files changed, 732 insertions(+), 0 deletions(-)
 create mode 100644 pgadmin/dlg/dlgExtension.cpp
 create mode 100644 pgadmin/include/dlg/dlgExtension.h
 create mode 100755 pgadmin/include/images/extension-sm.png
 create mode 100755 pgadmin/include/images/extension.png
 create mode 100755 pgadmin/include/images/extensions.png
 create mode 100644 pgadmin/include/schema/pgExtension.h
 create mode 100644 pgadmin/schema/pgExtension.cpp
 create mode 100644 pgadmin/ui/dlgExtension.xrc

diff --git a/pgadmin/dlg/dlgExtension.cpp b/pgadmin/dlg/dlgExtension.cpp
new file mode 100644
index 0000000..9ca56d2
--- /dev/null
+++ b/pgadmin/dlg/dlgExtension.cpp
@@ -0,0 +1,198 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin III - PostgreSQL Tools
+//
+// Copyright (C) 2002 - 2011, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+// dlgExtension.cpp - PostgreSQL Extension Property
+//
+//////////////////////////////////////////////////////////////////////////
+
+// wxWindows headers
+#include <wx/wx.h>
+
+// App headers
+#include "pgAdmin3.h"
+#include "utils/misc.h"
+#include "utils/pgDefs.h"
+
+#include "dlg/dlgExtension.h"
+#include "schema/pgExtension.h"
+
+
+// pointer to controls
+#define cbName          CTRL_COMBOBOX("cbName")
+#define cbSchema        CTRL_COMBOBOX("cbSchema")
+#define cbVersion       CTRL_COMBOBOX("cbVersion")
+
+
+dlgProperty *pgExtensionFactory::CreateDialog(frmMain *frame, pgObject *node, pgObject *parent)
+{
+	return new dlgExtension(this, frame, (pgExtension *)node);
+}
+
+
+BEGIN_EVENT_TABLE(dlgExtension, dlgProperty)
+	EVT_TEXT(XRCID("cbName"),                       dlgExtension::OnChangeName)
+	EVT_COMBOBOX(XRCID("cbName"),                   dlgExtension::OnChangeName)
+	EVT_TEXT(XRCID("cbSchema"),                     dlgProperty::OnChange)
+	EVT_COMBOBOX(XRCID("cbSchema"),                 dlgProperty::OnChange)
+	EVT_TEXT(XRCID("cbVersion"),                    dlgProperty::OnChange)
+	EVT_COMBOBOX(XRCID("cbVersion"),                dlgProperty::OnChange)
+END_EVENT_TABLE();
+
+
+dlgExtension::dlgExtension(pgaFactory *f, frmMain *frame, pgExtension *node)
+	: dlgProperty(f, frame, wxT("dlgExtension"))
+{
+	extension = node;
+}
+
+
+pgObject *dlgExtension::GetObject()
+{
+	return extension;
+}
+
+
+int dlgExtension::Go(bool modal)
+{
+	txtComment->Disable();
+
+    // add all schemas
+    cbSchema->Append(wxEmptyString);
+    pgSetIterator schemas(connection,
+                            wxT("SELECT nspname FROM pg_namespace\n")
+                            wxT(" ORDER BY nspname"));
+
+    while (schemas.RowsLeft())
+        cbSchema->Append(schemas.GetVal(wxT("nspname")));
+    cbSchema->SetSelection(0);
+
+	if (extension)
+	{
+		// edit mode
+        cbName->Append(extension->GetName());
+        cbName->SetSelection(0);
+        cbName->Disable();
+        
+        cbSchema->SetValue(extension->GetSchemaStr());
+        cbSchema->Enable(extension->GetIsRelocatable());
+        
+        // add all versions
+        cbVersion->Clear();
+        cbVersion->Append(wxEmptyString);
+        pgSetIterator versions(connection,
+                                wxT("SELECT version, relocatable FROM pg_available_extension_versions\n")
+                                wxT(" WHERE name=") + qtDbString(cbName->GetValue()) + wxT(" ")
+                                wxT(" ORDER BY version"));
+
+        while (versions.RowsLeft())
+            cbVersion->Append(versions.GetVal(wxT("version")));
+        cbVersion->SetValue(extension->GetVersion());
+	}
+	else
+	{
+		// create mode
+        
+        // add available extensions (but not the installed ones)
+        cbName->Append(wxEmptyString);
+        pgSetIterator extensions(connection,
+                                wxT("SELECT name FROM pg_available_extensions\n")
+                                wxT(" WHERE installed_version IS NULL\n")
+                                wxT(" ORDER BY name"));
+
+        while (extensions.RowsLeft())
+            cbName->Append(extensions.GetVal(wxT("name")));
+        cbName->SetSelection(0);
+	}
+
+	return dlgProperty::Go(modal);
+}
+
+
+pgObject *dlgExtension::CreateObject(pgCollection *collection)
+{
+	wxString name = cbName->wxComboBox::GetValue();
+
+	pgObject *obj = extensionFactory.CreateObjects(collection, 0, wxT("\n   AND extname ILIKE ") + qtDbString(name));
+	return obj;
+}
+
+
+void dlgExtension::OnChangeName(wxCommandEvent &ev)
+{
+    bool relocatable;
+    
+    // add all versions
+    cbVersion->Clear();
+    cbVersion->Append(wxEmptyString);
+    pgSetIterator versions(connection,
+                            wxT("SELECT version, relocatable FROM pg_available_extension_versions\n")
+                            wxT(" WHERE name=") + qtDbString(cbName->GetValue()) + wxT(" ")
+                            wxT(" ORDER BY version"));
+
+    while (versions.RowsLeft())
+    {
+        relocatable = versions.GetBool(wxT("relocatable"));
+        cbVersion->Append(versions.GetVal(wxT("version")));
+    }
+    cbVersion->SetSelection(0);
+    
+    if (relocatable)
+    {
+        cbSchema->Enable();
+    }
+    else
+    {
+        cbSchema->SetSelection(0);
+        cbSchema->Disable();
+    }
+
+	OnChange(ev);
+}
+
+
+void dlgExtension::CheckChange()
+{
+	bool didChange = true;
+	if (extension)
+	{
+		didChange = cbSchema->GetValue() != extension->GetSchemaStr()
+                    || cbVersion->GetValue() != extension->GetVersion();
+		EnableOK(didChange);
+	}
+	else
+	{
+		bool enable = true;
+
+		CheckValid(enable, !cbName->GetValue().IsEmpty(), _("Please specify name."));
+		EnableOK(enable);
+	}
+}
+
+
+wxString dlgExtension::GetSql()
+{
+	wxString sql;
+
+	if (extension)
+	{
+		// edit mode
+		if (cbSchema->GetValue() != extension->GetSchemaStr())
+			sql += wxT("ALTER EXTENSION ") + qtIdent(extension->GetName())
+			       +  wxT(" SET SCHEMA ") + qtIdent(cbSchema->GetValue()) + wxT(";\n");
+		if (cbVersion->GetValue() != extension->GetVersion())
+			sql += wxT("ALTER EXTENSION ") + qtIdent(extension->GetName())
+			       +  wxT(" UPDATE TO ") + qtIdent(cbVersion->GetValue()) + wxT(";\n");
+	}
+	else
+	{
+        sql = wxT("CREATE EXTENSION ") + qtIdent(cbName->GetValue());
+        AppendIfFilled(sql, wxT("\n   SCHEMA "), qtIdent(cbSchema->GetValue()));
+        AppendIfFilled(sql, wxT("\n   VERSION "), qtIdent(cbVersion->GetValue()));
+	}
+    
+	return sql;
+}
diff --git a/pgadmin/dlg/module.mk b/pgadmin/dlg/module.mk
index 2252957..c7ab4cc 100644
--- a/pgadmin/dlg/module.mk
+++ b/pgadmin/dlg/module.mk
@@ -20,6 +20,7 @@ pgadmin3_SOURCES += \
 	$(srcdir)/dlg/dlgConversion.cpp \
 	$(srcdir)/dlg/dlgDatabase.cpp \
 	$(srcdir)/dlg/dlgDomain.cpp \
+	$(srcdir)/dlg/dlgExtension.cpp \
 	$(srcdir)/dlg/dlgEditGridOptions.cpp \
 	$(srcdir)/dlg/dlgFindReplace.cpp \
 	$(srcdir)/dlg/dlgForeignDataWrapper.cpp \
diff --git a/pgadmin/frm/frmOptions.cpp b/pgadmin/frm/frmOptions.cpp
index 6762b6b..b1588c3 100644
--- a/pgadmin/frm/frmOptions.cpp
+++ b/pgadmin/frm/frmOptions.cpp
@@ -335,6 +335,7 @@ frmOptions::frmOptions(frmMain *parent)
 	lstDisplay->Append(_("Aggregates"));
 	lstDisplay->Append(_("Conversions"));
 	lstDisplay->Append(_("Domains"));
+	lstDisplay->Append(_("Extensions"));
 	lstDisplay->Append(_("Functions"));
 	lstDisplay->Append(_("Trigger Functions"));
 	lstDisplay->Append(_("Packages"));
diff --git a/pgadmin/include/dlg/dlgExtension.h b/pgadmin/include/dlg/dlgExtension.h
new file mode 100644
index 0000000..6bece0b
--- /dev/null
+++ b/pgadmin/include/dlg/dlgExtension.h
@@ -0,0 +1,42 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin III - PostgreSQL Tools
+//
+// Copyright (C) 2002 - 2011, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+// dlgExtension.h - Extension property
+//
+//////////////////////////////////////////////////////////////////////////
+
+
+#ifndef __DLG_EXTENSIONPROP
+#define __DLG_EXTENSIONPROP
+
+#include "dlg/dlgProperty.h"
+
+class pgExtension;
+
+class dlgExtension : public dlgProperty
+{
+public:
+	dlgExtension(pgaFactory *factory, frmMain *frame, pgExtension *ext);
+	int Go(bool modal);
+
+	void CheckChange();
+	wxString GetSql();
+	pgObject *CreateObject(pgCollection *collection);
+	pgObject *GetObject();
+
+private:
+	pgExtension *extension;
+	void OnChangeName(wxCommandEvent &ev);
+#ifdef __WXMAC__
+	void OnChangeSize(wxSizeEvent &ev);
+#endif
+
+	DECLARE_EVENT_TABLE()
+};
+
+
+#endif
diff --git a/pgadmin/include/dlg/module.mk b/pgadmin/include/dlg/module.mk
index 4bf7cd1..673e095 100644
--- a/pgadmin/include/dlg/module.mk
+++ b/pgadmin/include/dlg/module.mk
@@ -20,6 +20,7 @@ pgadmin3_SOURCES += \
 	$(srcdir)/include/dlg/dlgConversion.h \
 	$(srcdir)/include/dlg/dlgDatabase.h \
 	$(srcdir)/include/dlg/dlgDomain.h \
+	$(srcdir)/include/dlg/dlgExtension.h \
 	$(srcdir)/include/dlg/dlgEditGridOptions.h \
 	$(srcdir)/include/dlg/dlgFindReplace.h \
 	$(srcdir)/include/dlg/dlgForeignDataWrapper.h \
diff --git a/pgadmin/include/images/extension-sm.png b/pgadmin/include/images/extension-sm.png
new file mode 100755
index 0000000000000000000000000000000000000000..432d2f44231c1f88e787091060efc5125d80ef64
GIT binary patch
diff --git a/pgadmin/include/images/extension.png b/pgadmin/include/images/extension.png
new file mode 100755
index 0000000000000000000000000000000000000000..e3c533347883fc1dec73bcb21b32fc54e3c31732
GIT binary patch
diff --git a/pgadmin/include/images/extensions.png b/pgadmin/include/images/extensions.png
new file mode 100755
index 0000000000000000000000000000000000000000..eed7ca97a33ef595f448b8621168d531f86d51d5
GIT binary patch
diff --git a/pgadmin/include/images/module.mk b/pgadmin/include/images/module.mk
index 6a666b2..7990691 100644
--- a/pgadmin/include/images/module.mk
+++ b/pgadmin/include/images/module.mk
@@ -58,6 +58,9 @@ pgadmin3_SOURCES += \
 	$(srcdir)/include/images/domain-sm.png \
 	$(srcdir)/include/images/domain.png \
 	$(srcdir)/include/images/domains.png \
+	$(srcdir)/include/images/extension-sm.png \
+	$(srcdir)/include/images/extension.png \
+	$(srcdir)/include/images/extensions.png \
 	$(srcdir)/include/images/down.png \
 	$(srcdir)/include/images/drop.png \
 	$(srcdir)/include/images/edit_clear.png \
diff --git a/pgadmin/include/schema/module.mk b/pgadmin/include/schema/module.mk
index e897e37..a2d23bf 100644
--- a/pgadmin/include/schema/module.mk
+++ b/pgadmin/include/schema/module.mk
@@ -26,6 +26,7 @@ pgadmin3_SOURCES += \
 	$(srcdir)/include/schema/pgDatabase.h \
 	$(srcdir)/include/schema/pgDatatype.h \
 	$(srcdir)/include/schema/pgDomain.h \
+	$(srcdir)/include/schema/pgExtension.h \
 	$(srcdir)/include/schema/pgForeignDataWrapper.h \
 	$(srcdir)/include/schema/pgForeignKey.h \
     $(subdir)/pgForeignServer.h \
diff --git a/pgadmin/include/schema/pgExtension.h b/pgadmin/include/schema/pgExtension.h
new file mode 100644
index 0000000..1c7db9a
--- /dev/null
+++ b/pgadmin/include/schema/pgExtension.h
@@ -0,0 +1,93 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin III - PostgreSQL Tools
+//
+// Copyright (C) 2002 - 2011, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+// pgExtension.h PostgreSQL Extension
+//
+//////////////////////////////////////////////////////////////////////////
+
+#ifndef PGEXTENSION_H
+#define PGEXTENSION_H
+
+#include "pgDatabase.h"
+
+class pgCollection;
+class pgExtensionFactory : public pgDatabaseObjFactory
+{
+public:
+	pgExtensionFactory();
+	virtual dlgProperty *CreateDialog(frmMain *frame, pgObject *node, pgObject *parent);
+	virtual pgObject *CreateObjects(pgCollection *obj, ctlTree *browser, const wxString &restr = wxEmptyString);
+};
+extern pgExtensionFactory extensionFactory;
+
+class pgExtension : public pgDatabaseObject
+{
+public:
+	pgExtension(const wxString &newName = wxT(""));
+
+	wxString GetTranslatedMessage(int kindOfMessage) const;
+	void ShowTreeDetail(ctlTree *browser, frmMain *form = 0, ctlListView *properties = 0, ctlSQLBox *sqlPane = 0);
+	bool CanDropCascaded()
+	{
+		return true;
+	}
+
+	wxString GetSchemaStr() const
+	{
+		return schema;
+	}
+	void iSetSchemaStr(const wxString &s)
+	{
+		schema = s;
+	}
+	wxString GetVersion() const
+	{
+		return version;
+	}
+	void iSetVersion(const wxString &s)
+	{
+		version = s;
+	}
+	bool GetIsRelocatable() const
+	{
+		return isrelocatable;
+	}
+	void iSetIsRelocatable(const bool b)
+	{
+		isrelocatable = b;
+	}
+
+	bool DropObject(wxFrame *frame, ctlTree *browser, bool cascaded);
+	wxString GetSql(ctlTree *browser);
+	pgObject *Refresh(ctlTree *browser, const wxTreeItemId item);
+
+	bool HasStats()
+	{
+		return false;
+	}
+	bool HasDepends()
+	{
+		return false;
+	}
+	bool HasReferences()
+	{
+		return false;
+	}
+
+private:
+	wxString schema, version;
+    bool isrelocatable;
+};
+
+class pgExtensionCollection : public pgDatabaseObjCollection
+{
+public:
+	pgExtensionCollection(pgaFactory *factory, pgDatabase *db);
+	wxString GetTranslatedMessage(int kindOfMessage) const;
+};
+
+#endif
diff --git a/pgadmin/schema/module.mk b/pgadmin/schema/module.mk
index bbcd106..f6b7a6f 100644
--- a/pgadmin/schema/module.mk
+++ b/pgadmin/schema/module.mk
@@ -28,6 +28,7 @@ pgadmin3_SOURCES += \
         $(subdir)/pgDatabase.cpp \
         $(subdir)/pgDatatype.cpp \
         $(subdir)/pgDomain.cpp \
+        $(subdir)/pgExtension.cpp \
         $(subdir)/pgForeignDataWrapper.cpp \
         $(subdir)/pgForeignKey.cpp \
         $(subdir)/pgForeignServer.cpp \
diff --git a/pgadmin/schema/pgDatabase.cpp b/pgadmin/schema/pgDatabase.cpp
index 02555fb..7388d73 100644
--- a/pgadmin/schema/pgDatabase.cpp
+++ b/pgadmin/schema/pgDatabase.cpp
@@ -19,6 +19,7 @@
 #include "frm/frmMain.h"
 #include "schema/edbSynonym.h"
 #include "schema/pgCast.h"
+#include "schema/pgExtension.h"
 #include "schema/pgForeignDataWrapper.h"
 #include "schema/pgLanguage.h"
 #include "schema/pgSchema.h"
@@ -131,6 +132,8 @@ wxMenu *pgDatabase::GetNewMenu()
 	{
 		if (settings->GetDisplayOption(_("Casts")))
 			castFactory.AppendMenu(menu);
+		if (settings->GetDisplayOption(_("Extensions")))
+			extensionFactory.AppendMenu(menu);
 		if (settings->GetDisplayOption(_("Foreign Data Wrappers")))
 			foreignDataWrapperFactory.AppendMenu(menu);
 		if (settings->GetDisplayOption(_("Languages")))
@@ -563,6 +566,8 @@ void pgDatabase::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *pr
 				browser->AppendCollection(this, catalogFactory);
 			if (settings->GetDisplayOption(_("Casts")))
 				browser->AppendCollection(this, castFactory);
+			if (settings->GetDisplayOption(_("Extensions")))
+				browser->AppendCollection(this, extensionFactory);
 			if (settings->GetDisplayOption(_("Foreign Data Wrappers")))
 				browser->AppendCollection(this, foreignDataWrapperFactory);
 			if (settings->GetDisplayOption(_("Languages")))
diff --git a/pgadmin/schema/pgExtension.cpp b/pgadmin/schema/pgExtension.cpp
new file mode 100644
index 0000000..1e14104
--- /dev/null
+++ b/pgadmin/schema/pgExtension.cpp
@@ -0,0 +1,225 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin III - PostgreSQL Tools
+//
+// Copyright (C) 2002 - 2011, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+// pgExtension.cpp - Extension class
+//
+//////////////////////////////////////////////////////////////////////////
+
+// wxWindows headers
+#include <wx/wx.h>
+
+// App headers
+#include "pgAdmin3.h"
+#include "utils/misc.h"
+#include "schema/pgExtension.h"
+
+
+pgExtension::pgExtension(const wxString &newName)
+	: pgDatabaseObject(extensionFactory, newName)
+{
+}
+
+wxString pgExtension::GetTranslatedMessage(int kindOfMessage) const
+{
+	wxString message = wxEmptyString;
+
+	switch (kindOfMessage)
+	{
+		case RETRIEVINGDETAILS:
+			message = _("Retrieving details on extension");
+			message += wxT(" ") + GetName();
+			break;
+		case REFRESHINGDETAILS:
+			message = _("Refreshing extension");
+			message += wxT(" ") + GetName();
+			break;
+		case DROPINCLUDINGDEPS:
+			message = wxString::Format(_("Are you sure you wish to drop extension \"%s\" including all objects that depend on it?"),
+			                           GetFullIdentifier().c_str());
+			break;
+		case DROPEXCLUDINGDEPS:
+			message = wxString::Format(_("Are you sure you wish to drop extension \"%s?\""),
+			                           GetFullIdentifier().c_str());
+			break;
+		case DROPCASCADETITLE:
+			message = _("Drop extension cascaded?");
+			break;
+		case DROPTITLE:
+			message = _("Drop extension?");
+			break;
+		case PROPERTIESREPORT:
+			message = _("Extension properties report");
+			message += wxT(" - ") + GetName();
+			break;
+		case PROPERTIES:
+			message = _("Extension properties");
+			break;
+		case DDLREPORT:
+			message = _("Extension DDL report");
+			message += wxT(" - ") + GetName();
+			break;
+		case DDL:
+			message = _("Extension DDL");
+			break;
+		case DEPENDENCIESREPORT:
+			message = _("Extension dependencies report");
+			message += wxT(" - ") + GetName();
+			break;
+		case DEPENDENCIES:
+			message = _("Extension dependencies");
+			break;
+		case DEPENDENTSREPORT:
+			message = _("Extension dependents report");
+			message += wxT(" - ") + GetName();
+			break;
+		case DEPENDENTS:
+			message = _("Extension dependents");
+			break;
+	}
+
+	return message;
+}
+
+bool pgExtension::DropObject(wxFrame *frame, ctlTree *browser, bool cascaded)
+{
+	wxString sql = wxT("DROP EXTENSION ") + GetQuotedIdentifier();
+	if (cascaded)
+		sql += wxT(" CASCADE");
+	return GetDatabase()->ExecuteVoid(sql);
+}
+
+
+wxString pgExtension::GetSql(ctlTree *browser)
+{
+	if (sql.IsNull())
+	{
+		sql = wxT("-- Extension: ") + GetQuotedIdentifier() + wxT("\n\n")
+		      + wxT("-- DROP EXTENSION ") + GetQuotedIdentifier() + wxT(";")
+		      + wxT("\n\n CREATE EXTENSION ") + GetName();
+
+		if (!GetSchemaStr().IsEmpty())
+			sql += wxT("\n  SCHEMA ") + GetSchemaStr();
+		if (!GetVersion().IsEmpty())
+			sql += wxT("\n  VERSION ") + GetVersion();
+
+		sql += wxT(";\n")
+		       +  GetOwnerSql(9, 1, wxT("EXTENSION ") + GetName());
+	}
+	return sql;
+}
+
+
+void pgExtension::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane)
+{
+	if (properties)
+	{
+		CreateListColumns(properties);
+
+		properties->AppendItem(_("Name"), GetName());
+		properties->AppendItem(_("OID"), GetOid());
+        properties->AppendItem(_("Owner"), GetOwner());
+		properties->AppendItem(_("Schema"), GetSchemaStr());
+		properties->AppendYesNoItem(_("Relocatable?"), GetIsRelocatable());
+		properties->AppendItem(_("Version"), GetVersion());
+        properties->AppendItem(_("Comment"), firstLineOnly(GetComment()));
+	}
+}
+
+
+
+pgObject *pgExtension::Refresh(ctlTree *browser, const wxTreeItemId item)
+{
+	pgObject *language = 0;
+	pgCollection *coll = browser->GetParentCollection(item);
+	if (coll)
+		language = extensionFactory.CreateObjects(coll, 0, wxT("\n   AND x.oid=") + GetOidStr());
+
+	return language;
+}
+
+
+
+pgObject *pgExtensionFactory::CreateObjects(pgCollection *collection, ctlTree *browser, const wxString &restriction)
+{
+	wxString sql;
+	pgExtension *extension = 0;
+
+	sql = wxT("select x.oid, x.extname, r.rolname, n.nspname, x.extrelocatable, x.extversion, e.comment")
+           wxT("  FROM pg_extension x\n")
+	       wxT("  JOIN pg_roles r on x.extowner=r.oid \n")
+	       wxT("  JOIN pg_namespace n on x.extnamespace=n.oid\n")
+           wxT("  join pg_available_extensions() e(name, default_version, comment) ON x.extname=e.name\n")
+	       + restriction + wxT("\n")
+	       wxT(" ORDER BY x.extname");
+	pgSet *extensions = collection->GetDatabase()->ExecuteSet(sql);
+
+	if (extensions)
+	{
+		while (!extensions->Eof())
+		{
+
+			extension = new pgExtension(extensions->GetVal(wxT("extname")));
+			extension->iSetDatabase(collection->GetDatabase());
+			extension->iSetOid(extensions->GetOid(wxT("oid")));
+			extension->iSetOwner(extensions->GetVal(wxT("rolname")));
+			extension->iSetSchemaStr(extensions->GetVal(wxT("nspname")));
+			extension->iSetIsRelocatable(extensions->GetBool(wxT("extrelocatable")));
+			extension->iSetVersion(extensions->GetVal(wxT("extversion")));
+			extension->iSetComment(extensions->GetVal(wxT("comment")));
+
+			if (browser)
+			{
+				browser->AppendObject(collection, extension);
+
+				extensions->MoveNext();
+			}
+			else
+				break;
+		}
+
+		delete extensions;
+	}
+	return extension;
+}
+
+
+/////////////////////////////
+
+wxString pgExtensionCollection::GetTranslatedMessage(int kindOfMessage) const
+{
+	wxString message = wxEmptyString;
+
+	switch (kindOfMessage)
+	{
+		case RETRIEVINGDETAILS:
+			message = _("Retrieving details on extensions");
+			break;
+		case REFRESHINGDETAILS:
+			message = _("Refreshing extensions");
+			break;
+		case OBJECTSLISTREPORT:
+			message = _("Extensions list report");
+			break;
+	}
+
+	return message;
+}
+
+///////////////////////////////////////////////////
+
+#include "images/extension.pngc"
+#include "images/extension-sm.pngc"
+#include "images/extensions.pngc"
+
+pgExtensionFactory::pgExtensionFactory()
+	: pgDatabaseObjFactory(__("Extension"), __("New Extension..."), __("Create a new Extension."), extension_png_img, extension_sm_png_img)
+{
+}
+
+
+pgExtensionFactory extensionFactory;
+static pgaCollectionFactory cf(&extensionFactory, __("Extensions"), extensions_png_img);
diff --git a/pgadmin/ui/dlgExtension.xrc b/pgadmin/ui/dlgExtension.xrc
new file mode 100644
index 0000000..baaae05
--- /dev/null
+++ b/pgadmin/ui/dlgExtension.xrc
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<resource>
+  <object class="wxDialog" name="dlgExtension">
+    <title></title>
+    <size>220,250d</size>
+    <style>wxDEFAULT_DIALOG_STYLE|wxCAPTION|wxSYSTEM_MENU|wxRESIZE_BORDER</style>
+    <object class="wxFlexGridSizer">
+      <cols>1</cols>
+      <growablerows>0</growablerows>
+      <growablecols>0</growablecols>
+      <object class="sizeritem">
+        <object class="wxNotebook" name="nbNotebook">
+          <size>216,225d</size>
+          <selected>0</selected>
+          <object class="notebookpage">
+            <label>Properties</label>
+            <object class="wxPanel" name="pnlProperties">
+              <object class="wxFlexGridSizer">
+                <cols>2</cols>
+                <rows>6</rows>
+                <vgap>5</vgap>
+                <hgap>5</hgap>
+                <growablerows>4</growablerows>
+                <growablecols>1</growablecols>
+                <object class="sizeritem">
+                  <object class="wxStaticText" name="stName">
+                    <label>Name</label>
+                  </object>
+                  <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxComboBox" name="cbName">
+                    <content/>
+                    <style>wxCB_DROPDOWN</style>
+                  </object>
+                  <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxStaticText" name="stOID">
+                    <label>OID</label>
+                  </object>
+                  <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxTextCtrl" name="txtOID">
+                  </object>
+                  <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxStaticText" name="stSchema">
+                    <label>Schema</label>
+                  </object>
+                  <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="ctlComboBox" name="cbSchema">
+                    <content/>
+                    <style>wxCB_DROPDOWN</style>
+                  </object>
+                  <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxStaticText" name="stVersion">
+                    <label>Version</label>
+                  </object>
+                  <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="ctlComboBox" name="cbVersion">
+                    <content/>
+                    <style>wxCB_DROPDOWN</style>
+                  </object>
+                  <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxStaticText" name="stComment">
+                    <label>Comment</label>
+                  </object>
+                  <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxTextCtrl" name="txtComment">
+                    <style>wxTE_MULTILINE</style>
+                  </object>
+                  <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxStaticText" name="stClusterSet">
+                    <label>Use replication</label>
+                  </object>
+                  <flag>wxALIGN_CENTRE_VERTICAL|wxALL</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxComboBox" name="cbClusterSet">
+                    <content/>
+                    <style>wxCB_READONLY|wxCB_DROPDOWN</style>
+                  </object>
+                  <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxALL</flag>
+                  <border>4</border>
+                </object>
+              </object>
+            </object>
+          </object>
+        </object>
+        <flag>wxALL|wxGROW|wxALIGN_CENTRE</flag>
+        <border>3</border>
+      </object>
+      <object class="sizeritem">
+        <object class="wxFlexGridSizer">
+          <cols>4</cols>
+          <growablecols>1</growablecols>
+          <object class="sizeritem">
+            <object class="wxButton" name="wxID_HELP">
+              <label>Help</label>
+            </object>
+            <flag>wxEXPAND|wxALL</flag>
+            <border>3</border>
+          </object>
+          <object class="spacer">
+            <size>0,0d</size>
+          </object>
+          <object class="sizeritem">
+            <object class="wxButton" name="wxID_OK">
+              <label>&amp;OK</label>
+              <default>1</default>
+            </object>
+            <flag>wxEXPAND|wxALL</flag>
+            <border>3</border>
+          </object>
+          <object class="sizeritem">
+            <object class="wxButton" name="wxID_CANCEL">
+              <label>&amp;Cancel</label>
+            </object>
+            <flag>wxEXPAND|wxALL</flag>
+            <border>3</border>
+          </object>
+        </object>
+        <flag>wxEXPAND|wxTOP|wxLEFT|wxRIGHT</flag>
+      </object>
+      <object class="sizeritem">
+        <object class="wxStatusBar" name="unkStatusBar">
+          <style>wxST_SIZEGRIP</style>
+        </object>
+        <flag>wxEXPAND|wxALIGN_CENTRE</flag>
+        <border>3</border>
+      </object>
+    </object>
+  </object>
+</resource>
diff --git a/pgadmin/ui/module.mk b/pgadmin/ui/module.mk
index 79da290..0956c57 100644
--- a/pgadmin/ui/module.mk
+++ b/pgadmin/ui/module.mk
@@ -23,6 +23,7 @@ TMP_ui += \
 	$(srcdir)/ui/dlgDatabase.xrc \
 	$(srcdir)/ui/dlgDirectDbg.xrc \
 	$(srcdir)/ui/dlgDomain.xrc \
+	$(srcdir)/ui/dlgExtension.xrc \
 	$(srcdir)/ui/dlgEditGridOptions.xrc \
 	$(srcdir)/ui/dlgExtTable.xrc \
 	$(srcdir)/ui/dlgFindReplace.xrc \
-- 
1.7.1

