From 1250c481c75afd4af1f29628d9eb528884618d3d Mon Sep 17 00:00:00 2001
From: Guillaume Lelarge <guillaume@lelarge.info>
Date: Tue, 22 Mar 2011 21:54:56 +0100
Subject: [PATCH] Support for Foreign Server object.

---
 pgadmin/dlg/dlgForeignServer.cpp              |  353 +++++++++++++++++++++++++
 pgadmin/dlg/module.mk                         |    1 +
 pgadmin/include/dlg/dlgForeignServer.h        |   51 ++++
 pgadmin/include/dlg/module.mk                 |    1 +
 pgadmin/include/images/foreignserver-sm.png   |  Bin 0 -> 423 bytes
 pgadmin/include/images/foreignserver.png      |  Bin 0 -> 465 bytes
 pgadmin/include/images/foreignservers.png     |  Bin 0 -> 477 bytes
 pgadmin/include/images/module.mk              |    3 +
 pgadmin/include/precomp.h                     |    2 +
 pgadmin/include/schema/module.mk              |    1 +
 pgadmin/include/schema/pgCollection.h         |    6 +
 pgadmin/include/schema/pgForeignDataWrapper.h |   54 ++++
 pgadmin/include/schema/pgForeignServer.h      |   68 +++++
 pgadmin/include/utils/misc.h                  |    1 +
 pgadmin/schema/module.mk                      |    1 +
 pgadmin/schema/pgCollection.cpp               |    1 +
 pgadmin/schema/pgForeignDataWrapper.cpp       |  107 ++++++++
 pgadmin/schema/pgForeignServer.cpp            |  229 ++++++++++++++++
 pgadmin/schema/pgObject.cpp                   |    3 +
 pgadmin/ui/dlgForeignServer.xrc               |  283 ++++++++++++++++++++
 pgadmin/ui/module.mk                          |    1 +
 21 files changed, 1166 insertions(+), 0 deletions(-)
 create mode 100644 pgadmin/dlg/dlgForeignServer.cpp
 create mode 100644 pgadmin/include/dlg/dlgForeignServer.h
 create mode 100644 pgadmin/include/images/foreignserver-sm.png
 create mode 100644 pgadmin/include/images/foreignserver.png
 create mode 100644 pgadmin/include/images/foreignservers.png
 create mode 100644 pgadmin/include/schema/pgForeignServer.h
 create mode 100644 pgadmin/schema/pgForeignServer.cpp
 create mode 100644 pgadmin/ui/dlgForeignServer.xrc

diff --git a/pgadmin/dlg/dlgForeignServer.cpp b/pgadmin/dlg/dlgForeignServer.cpp
new file mode 100644
index 0000000..06119f0
--- /dev/null
+++ b/pgadmin/dlg/dlgForeignServer.cpp
@@ -0,0 +1,353 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin III - PostgreSQL Tools
+// RCS-ID:      $Id$
+// Copyright (C) 2002 - 2010, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+// dlgForeignServer.cpp - PostgreSQL Foreign Server Property
+//
+//////////////////////////////////////////////////////////////////////////
+
+// wxWindows headers
+#include <wx/wx.h>
+
+// App headers
+#include "pgAdmin3.h"
+#include "utils/misc.h"
+#include "utils/pgDefs.h"
+
+#include "dlg/dlgForeignServer.h"
+#include "schema/pgForeignServer.h"
+
+
+// pointer to controls
+#define cbForeignDataWrapper CTRL_COMBOBOX("cbForeignDataWrapper")
+#define txtType              CTRL_TEXT("txtType")
+#define txtVersion           CTRL_TEXT("txtVersion")
+#define lstOptions           CTRL_LISTVIEW("lstOptions")
+#define txtOption            CTRL_TEXT("txtOption")
+#define txtValue             CTRL_TEXT("txtValue")
+#define btnAdd               CTRL_BUTTON("wxID_ADD")
+#define btnRemove            CTRL_BUTTON("wxID_REMOVE")
+
+
+dlgProperty *pgForeignServerFactory::CreateDialog(frmMain *frame, pgObject *node, pgObject *parent)
+{
+    return new dlgForeignServer(this, frame, (pgForeignServer*)node);
+}
+
+
+BEGIN_EVENT_TABLE(dlgForeignServer, dlgSecurityProperty)
+    EVT_TEXT(XRCID("cbForeignDataWrapper"),     dlgForeignServer::OnChange)
+    EVT_COMBOBOX(XRCID("cbForeignDataWrapper"), dlgForeignServer::OnChange)
+    EVT_LIST_ITEM_SELECTED(XRCID("lstOptions"), dlgForeignServer::OnSelChangeOption)
+    EVT_TEXT(XRCID("txtOption"),                dlgForeignServer::OnChangeOptionName)
+    EVT_BUTTON(wxID_ADD,                        dlgForeignServer::OnAddOption)
+    EVT_BUTTON(wxID_REMOVE,                     dlgForeignServer::OnRemoveOption)
+END_EVENT_TABLE();
+
+
+dlgForeignServer::dlgForeignServer(pgaFactory *f, frmMain *frame, pgForeignServer *node)
+: dlgSecurityProperty(f, frame, node, wxT("dlgForeignServer"), wxT("USAGE"), "U")
+{
+    foreignserver=node;
+}
+
+
+pgObject *dlgForeignServer::GetObject()
+{
+    return foreignserver;
+}
+
+
+int dlgForeignServer::Go(bool modal)
+{
+	if (!foreignserver)
+		cbOwner->Append(wxT(""));
+
+    // Fill owner combobox
+    AddGroups();
+    AddUsers(cbOwner);
+    
+    // Fill validator combobox
+    cbForeignDataWrapper->Append(wxT(""));
+    pgSet *set=connection->ExecuteSet(
+        wxT("SELECT fdwname\n")
+        wxT("  FROM pg_foreign_data_wrapper\n")
+        wxT("  ORDER BY fdwname"));
+    if (set)
+    {
+        while (!set->Eof())
+        {
+            wxString fdwname = set->GetVal(wxT("fdwname"));
+            cbForeignDataWrapper->Append(fdwname);
+            set->MoveNext();
+        }
+        delete set;
+    }
+    cbForeignDataWrapper->SetSelection(0);
+
+    // Initialize options listview and buttons
+    lstOptions->AddColumn(_("Option"), 80);
+    lstOptions->AddColumn(_("Value"), 40);
+    txtOption->SetValue(wxT(""));
+    txtValue->SetValue(wxT(""));
+    btnAdd->Disable();
+    btnRemove->Disable();
+
+    if (foreignserver)
+    {
+        // edit mode
+        txtName->Disable();
+        txtType->Disable();
+        
+        txtType->SetValue(foreignserver->GetType());
+        txtVersion->SetValue(foreignserver->GetVersion());
+
+        wxString options = foreignserver->GetOptions();
+        wxString option, optionname, optionvalue;
+        while (options.Length() > 0)
+        {
+          option = options.BeforeFirst(',');
+          optionname = option.BeforeFirst(wxT('=')).Trim(false).Trim();
+          optionvalue = option.AfterFirst(wxT('=')).Trim(false).Trim();
+          lstOptions->AppendItem(optionname, optionvalue);
+          options = options.AfterFirst(',');
+        }
+    }
+    else
+    {
+        // create mode
+    }
+
+    return dlgSecurityProperty::Go(modal);
+}
+
+
+pgObject *dlgForeignServer::CreateObject(pgCollection *collection)
+{
+    wxString name=txtName->GetValue();
+
+    pgObject *obj=foreignServerFactory.CreateObjects(collection, 0, wxT("\n   AND srvname ILIKE ") + qtDbString(name));
+    return obj;
+}
+
+
+void dlgForeignServer::CheckChange()
+{
+    bool didChange=true;
+    wxString name=txtName->GetValue();
+    if (foreignserver)
+    {
+        didChange = name != foreignserver->GetName()
+          || txtComment->GetValue() != foreignserver->GetComment()
+          || cbOwner->GetValue() != foreignserver->GetOwner()
+          || txtType->GetValue() != foreignserver->GetType()
+          || txtVersion->GetValue() != foreignserver->GetVersion()
+          || cbForeignDataWrapper->GetValue() != foreignserver->GetFdw();
+        EnableOK(didChange);
+    }
+    else
+    {
+        bool enable=true;
+
+        CheckValid(enable, !name.IsEmpty(), _("Please specify name."));
+        CheckValid(enable, !cbForeignDataWrapper->GetValue().IsEmpty(), _("Please specify foreign data wrapper."));
+        EnableOK(enable);
+    }
+}
+
+
+
+void dlgForeignServer::OnChange(wxCommandEvent &ev)
+{
+    CheckChange();
+}
+
+
+void dlgForeignServer::OnChangeOptionName(wxCommandEvent &ev)
+{
+    btnAdd->Enable(txtOption->GetValue().Length() > 0);
+}
+
+
+void dlgForeignServer::OnSelChangeOption(wxListEvent &ev)
+{
+    int row=lstOptions->GetSelection();
+    if (row >= 0)
+    {
+        txtOption->SetValue(lstOptions->GetText(row, 0));
+        txtValue->SetValue(lstOptions->GetText(row, 1));
+    }
+
+    btnRemove->Enable(row >= 0);
+}
+
+
+void dlgForeignServer::OnAddOption(wxCommandEvent &ev)
+{
+    bool found = false;
+
+    for (int pos = 0 ; pos < lstOptions->GetItemCount() ; pos++)
+    {
+        if (lstOptions->GetText(pos).IsSameAs(txtOption->GetValue(), false))
+        {
+            lstOptions->SetItem(pos, 1, txtValue->GetValue());
+            found = true;
+            break;
+        }
+    }
+
+    if (!found)
+    {
+        lstOptions->AppendItem(txtOption->GetValue(), txtValue->GetValue());
+    }
+
+    txtOption->SetValue(wxT(""));
+    txtValue->SetValue(wxT(""));
+    btnAdd->Disable();
+
+    CheckChange();
+}
+
+
+void dlgForeignServer::OnRemoveOption(wxCommandEvent &ev)
+{
+    int sel=lstOptions->GetSelection();
+    lstOptions->DeleteItem(sel);
+
+    txtOption->SetValue(wxT(""));
+    txtValue->SetValue(wxT(""));
+    btnRemove->Disable();
+
+    CheckChange();
+}
+
+
+wxString dlgForeignServer::GetOptionsSql()
+{
+    wxString options = foreignserver->GetOptions();
+    wxString option, optionname, optionvalue, sqloptions;
+    bool found;
+    int pos;
+
+    while (options.Length() > 0)
+    {
+        option = options.BeforeFirst(',');
+        optionname = option.BeforeFirst(wxT('=')).Trim(false).Trim();
+        optionvalue = option.AfterFirst(wxT('=')).Trim(false).Trim();
+
+        // check for options
+        found = false;
+        for (pos=0 ; pos < lstOptions->GetItemCount() && !found; pos++)
+        {
+            found = lstOptions->GetText(pos, 0).Cmp(optionname) == 0;
+            if (found) break;
+        }
+
+        if (found)
+        {
+            if (lstOptions->GetText(pos, 1).Cmp(optionvalue) != 0)
+            {
+                if (sqloptions.Length() > 0)
+                    sqloptions += wxT(", ");
+                sqloptions += wxT("SET ") + optionname + wxT(" '") + lstOptions->GetText(pos, 1) + wxT("'");
+            }
+        }
+        else
+        {
+            if (sqloptions.Length() > 0)
+                sqloptions += wxT(", ");
+            sqloptions += wxT("DROP ") + optionname;
+        }
+
+        options = options.AfterFirst(',');
+    }
+
+    for (pos=0 ; pos < lstOptions->GetItemCount() ; pos++)
+    {
+        options = foreignserver->GetOptions();
+        found = false;
+
+        while (options.Length() > 0 && !found)
+        {
+            option = options.BeforeFirst(',');
+            optionname = option.BeforeFirst(wxT('=')).Trim(false).Trim();
+            found = lstOptions->GetText(pos, 0).Cmp(optionname) == 0;
+            options = options.AfterFirst(',');
+        }
+
+        if (!found)
+        {
+            optionvalue = option.AfterFirst(wxT('=')).Trim(false).Trim();
+
+            if (sqloptions.Length() > 0)
+                sqloptions += wxT(", ");
+            sqloptions += wxT("ADD ") + lstOptions->GetText(pos, 0) + wxT(" '") + lstOptions->GetText(pos, 1) + wxT("'");
+        }
+    }
+
+    return sqloptions;
+}
+
+
+wxString dlgForeignServer::GetSql()
+{
+    wxString sql, name;
+    name=txtName->GetValue();
+
+    if (foreignserver)
+    {
+        // edit mode
+        if (txtVersion->GetValue() != foreignserver->GetVersion())
+        {
+            sql = wxT("ALTER SERVER ") + qtIdent(name)
+                + wxT(" VERSION ") + qtDbString(txtVersion->GetValue()) + wxT(";\n");
+        }
+
+        wxString sqloptions = GetOptionsSql();
+        if (sqloptions.Length() > 0)
+        {
+            sql += wxT("ALTER SERVER ") + name
+                 + wxT(" OPTIONS (") + sqloptions + wxT(");\n");
+        }
+
+        AppendOwnerChange(sql, wxT("SERVER ") + qtIdent(name));
+    }
+    else
+    {
+        // create mode
+        sql = wxT("CREATE SERVER ") + qtIdent(name);
+        if (!(txtType->GetValue()).IsEmpty())
+            sql += wxT("\n   TYPE ") + qtDbString(txtType->GetValue());
+        if (!(txtVersion->GetValue()).IsEmpty())
+            sql += wxT("\n   VERSION ") + qtDbString(txtVersion->GetValue());
+        sql += wxT("\n   FOREIGN DATA WRAPPER ") + qtIdent(cbForeignDataWrapper->GetValue());
+
+        // check for options
+        if (lstOptions->GetItemCount() > 0)
+        {
+            wxString options = wxEmptyString;
+            for (int pos=0 ; pos < lstOptions->GetItemCount() ; pos++)
+            {
+                if (options.Length() > 0)
+                    options += wxT(", ");
+
+                options += lstOptions->GetText(pos, 0)
+                    + wxT(" '") + lstOptions->GetText(pos, 1) + wxT("' ");
+            }
+            sql += wxT("\n  OPTIONS (") + options + wxT(")");
+        }
+
+        sql += wxT(";\n");
+        AppendOwnerNew(sql, wxT("SERVER ") + qtIdent(name));
+    }
+
+    sql += GetGrant(wxT("U"), wxT("SERVER ") + qtIdent(name));
+
+    return sql;
+}
+
+
+
diff --git a/pgadmin/dlg/module.mk b/pgadmin/dlg/module.mk
index a107d5b..2252957 100644
--- a/pgadmin/dlg/module.mk
+++ b/pgadmin/dlg/module.mk
@@ -24,6 +24,7 @@ pgadmin3_SOURCES += \
 	$(srcdir)/dlg/dlgFindReplace.cpp \
 	$(srcdir)/dlg/dlgForeignDataWrapper.cpp \
 	$(srcdir)/dlg/dlgForeignKey.cpp \
+	$(srcdir)/dlg/dlgForeignServer.cpp \
 	$(srcdir)/dlg/dlgFunction.cpp \
 	$(srcdir)/dlg/dlgGroup.cpp \
 	$(srcdir)/dlg/dlgHbaConfig.cpp \
diff --git a/pgadmin/include/dlg/dlgForeignServer.h b/pgadmin/include/dlg/dlgForeignServer.h
new file mode 100644
index 0000000..20d54c0
--- /dev/null
+++ b/pgadmin/include/dlg/dlgForeignServer.h
@@ -0,0 +1,51 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin III - PostgreSQL Tools
+// RCS-ID:      $Id$
+// Copyright (C) 2002 - 2010, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+// dlgForeignServer.h - Foreign Server property
+//
+//////////////////////////////////////////////////////////////////////////
+
+
+#ifndef __DLG_FOREIGNSERVERPROP
+#define __DLG_FOREIGNSERVERPROP
+
+#include "dlg/dlgProperty.h"
+
+class pgForeignServer;
+
+class dlgForeignServer : public dlgSecurityProperty
+{
+public:
+    dlgForeignServer(pgaFactory *factory, frmMain *frame, pgForeignServer *_foreignserver);
+    int Go(bool modal);
+
+    void CheckChange();
+    wxString GetSql();
+    pgObject *CreateObject(pgCollection *collection);
+    pgObject *GetObject();
+
+private:
+    pgForeignServer *foreignserver;
+
+#ifdef __WXMAC__
+    void OnChangeSize(wxSizeEvent &ev);
+#endif
+
+    void OnSelChangeOption(wxListEvent &ev);
+    void OnChange(wxCommandEvent &ev);
+    void OnChangeOptionName(wxCommandEvent &ev);
+    void OnAddOption(wxCommandEvent &ev);
+    void OnChangeOption(wxCommandEvent &ev);
+    void OnRemoveOption(wxCommandEvent &ev);
+
+    wxString GetOptionsSql();
+
+    DECLARE_EVENT_TABLE()
+};
+
+
+#endif
diff --git a/pgadmin/include/dlg/module.mk b/pgadmin/include/dlg/module.mk
index 07f2ec7..4bf7cd1 100644
--- a/pgadmin/include/dlg/module.mk
+++ b/pgadmin/include/dlg/module.mk
@@ -24,6 +24,7 @@ pgadmin3_SOURCES += \
 	$(srcdir)/include/dlg/dlgFindReplace.h \
 	$(srcdir)/include/dlg/dlgForeignDataWrapper.h \
 	$(srcdir)/include/dlg/dlgForeignKey.h \
+	$(srcdir)/include/dlg/dlgForeignServer.h \
 	$(srcdir)/include/dlg/dlgFunction.h \
 	$(srcdir)/include/dlg/dlgGroup.h \
 	$(srcdir)/include/dlg/dlgHbaConfig.h \
diff --git a/pgadmin/include/images/foreignserver-sm.png b/pgadmin/include/images/foreignserver-sm.png
new file mode 100644
index 0000000000000000000000000000000000000000..2467ccf1422a59a7218fd0bb19c2a42bdf52e5d7
GIT binary patch
literal 423
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}QGic~E0BJDv+cp5$Qv6qzrVk7
zW3&9@vzBik`G5Ho|K-)uTicc2-1GkNGyU0x%oo?3fBedPak1gnHlr`^;(z|izO~Kb
z%lm|1zjI$+bN~H2|Mm{mcMpR9{3*J*S>f3^`;Si}e|^pQ`={jETDdE$#Qyy)dv><$
z|KAGswyocQwlbCk`2{mLJiCzw<Zu>vL>2>S4={E+nQaGT<aoL`hDcoQ?f2wsP!M2o
z7l{eDQ+~(c|9@BE84^1Kx361bY|Bu`qQb-J62DBxZ_<p5BE`pwna}6wxpa1%>e!Vz
zahdU=*X&ESFOpJE*&;e)`qd3*DpaT5u9JDLS%3P((k)@<ZbaLzV+h!Of4=?`KK92q
z=3fE@l4^--L`h0wNvc(HQ7VvPFfuSS)HN{HHLwUVG_o=@w=%HQHZZd?Fu43|MG}gJ
c-29Zxv`X9>7VQ?e2h_me>FVdQ&MBb@04%Yw7ytkO

literal 0
HcmV?d00001

diff --git a/pgadmin/include/images/foreignserver.png b/pgadmin/include/images/foreignserver.png
new file mode 100644
index 0000000000000000000000000000000000000000..acc1d95747a4202889d290c09723ad256b3ade99
GIT binary patch
literal 465
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}dw@@fE0BJ4H1XC}ldG$x-rk;b
zbBn^`(-v<Y_<VXF^X*6KhesRkAJ%{WH0a0Aw7dJXKfR9n@iXJ;>B3jHJ%0Ymyt&2b
z>xaajzp}r6O#1aZ_swnZ-@o(j?brSKHsR0jg12|(Jv?Ik>3Q^@KSejUDm^`G_u*04
zkB=FDei#4!Q*vdM*uTG}&(4<p`&<71Z^e=6KGr~|FqQ=Q1v5B2yO9Rua29w(76WMy
zFm^kcZ3kpDdb&7<NL<c6_mZ#4K)~%H<IV4zPAv*`$UXSI-fsDoOA`wI)tYBoF*GH{
z`5b0CS{8Hud(3gZCwz+|x(?;4XD(a9nKwy1%8%jHs%xu+oQtnY@ho|}MQpx<{hcWb
z#rNNN`S_>%Q`v(SXV-scH!NM%y4?8OPq~)XwXYQue#$XVWA*#P5bMk*{PSFAAJ8$X
zC9V-ADTyViR>?)FK#IZ0z|c_Fz*yJ7BE-<h%Fx`(z*5`5%*w#v^0O65C>nC}Q!>*k
Wacfw#Ti_m01B0ilpUXO@geCx4-OoAz

literal 0
HcmV?d00001

diff --git a/pgadmin/include/images/foreignservers.png b/pgadmin/include/images/foreignservers.png
new file mode 100644
index 0000000000000000000000000000000000000000..b8b5104a55e51fc1c5d3da2cb371ec755296e5bf
GIT binary patch
literal 477
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}SAb85E0BJ3YvzMPkvBGK-q<Yv
z_^jpINB&<v#eaEq^wxIeH}|}M{7nDyA@0RB=X(cruWyvSy;JqY#fBfhGT%Q7xwXyW
z%e(l`Z)3l_Pk4IX?&UT2TicXx?@+z5N&eb8>7T!{zq~y1>v!(&-}&zz1poO{baS)9
zvvc+zpGN-rn)CNh$+fj|S5}Gr`&;(xY}x<66?UsN(t)mFED7=pW^j0RBMr#mEbxdd
z2GSm2>~=ES4#?>8ba4!kxE$JlQ>@8=hxKsWg{al8YedCe4mSP&U)?4&{ap03GlzK@
z90c3~B@Rrt@Z7B9o8(p=r!%ca^+?p2?N4UEU0&!k)p~#6)qD9%>~<Ure3EgdFpER)
z;*}e7I)WBjBo`~L@?=>3b?Sv8x#U^17aMMww)MOF^{=(Rt2quWmu2Jr-}CJ$w~6ur
zX+A&R+4(bNJ_B8)TH+c}l9E`GYL#4+3Zxi}3=9o*4UBaSEJ6&8tPIVq3@o(`%&ZIy
jE<an5grXrgKP5A*61Rp$y9Mq6H86O(`njxgN@xNAfBVo@

literal 0
HcmV?d00001

diff --git a/pgadmin/include/images/module.mk b/pgadmin/include/images/module.mk
index e06a850..6a666b2 100644
--- a/pgadmin/include/images/module.mk
+++ b/pgadmin/include/images/module.mk
@@ -113,6 +113,9 @@ pgadmin3_SOURCES += \
 	$(srcdir)/include/images/foreigndatawrappers.png \
 	$(srcdir)/include/images/foreignkey.png \
 	$(srcdir)/include/images/foreignkeybad.png \
+	$(srcdir)/include/images/foreignserver.png \
+	$(srcdir)/include/images/foreignserver-sm.png \
+	$(srcdir)/include/images/foreignservers.png \
 	$(srcdir)/include/images/forward.png \
 	$(srcdir)/include/images/function.png \
 	$(srcdir)/include/images/functions.png \
diff --git a/pgadmin/include/precomp.h b/pgadmin/include/precomp.h
index 75bbb9b..82da403 100644
--- a/pgadmin/include/precomp.h
+++ b/pgadmin/include/precomp.h
@@ -80,6 +80,7 @@
 #include "dlg/dlgFindReplace.h"
 #include "dlg/dlgForeignDataWrapper.h"
 #include "dlg/dlgForeignKey.h"
+#include "dlg/dlgForeignServer.h"
 #include "dlg/dlgFunction.h"
 #include "dlg/dlgGroup.h"
 #include "dlg/dlgHbaConfig.h"
@@ -188,6 +189,7 @@
 #include "schema/pgDomain.h"
 #include "schema/pgForeignDataWrapper.h"
 #include "schema/pgForeignKey.h"
+#include "schema/pgForeignServer.h"
 #include "schema/pgFunction.h"
 #include "schema/pgGroup.h"
 #include "schema/pgIndex.h"
diff --git a/pgadmin/include/schema/module.mk b/pgadmin/include/schema/module.mk
index 9be78b7..e897e37 100644
--- a/pgadmin/include/schema/module.mk
+++ b/pgadmin/include/schema/module.mk
@@ -28,6 +28,7 @@ pgadmin3_SOURCES += \
 	$(srcdir)/include/schema/pgDomain.h \
 	$(srcdir)/include/schema/pgForeignDataWrapper.h \
 	$(srcdir)/include/schema/pgForeignKey.h \
+    $(subdir)/pgForeignServer.h \
 	$(srcdir)/include/schema/pgFunction.h \
 	$(srcdir)/include/schema/pgGroup.h \
 	$(srcdir)/include/schema/pgIndex.h \
diff --git a/pgadmin/include/schema/pgCollection.h b/pgadmin/include/schema/pgCollection.h
index 9ceb001..9805704 100644
--- a/pgadmin/include/schema/pgCollection.h
+++ b/pgadmin/include/schema/pgCollection.h
@@ -20,6 +20,7 @@ class pgServer;
 class pgDatabase;
 class pgaJob;
 class pgSchema;
+class pgForeignDataWrapper;
 
 // Class declarations
 class pgCollection : public pgObject
@@ -46,6 +47,10 @@ public:
 	{
 		return schema;
 	}
+	pgForeignDataWrapper *GetForeignDataWrapper() const
+	{
+		return fdw;
+	}
 	pgaJob *GetJob() const
 	{
 		return job;
@@ -81,6 +86,7 @@ protected:
 	pgDatabase *database;
 	pgSchema *schema;
 	pgaJob *job;
+	pgForeignDataWrapper *fdw;
 };
 
 
diff --git a/pgadmin/include/schema/pgForeignDataWrapper.h b/pgadmin/include/schema/pgForeignDataWrapper.h
index 543103f..8f42822 100644
--- a/pgadmin/include/schema/pgForeignDataWrapper.h
+++ b/pgadmin/include/schema/pgForeignDataWrapper.h
@@ -34,6 +34,7 @@ public:
 	{
 		return true;
 	}
+	wxMenu *GetNewMenu();
 
 	wxString GetValidatorProc() const
 	{
@@ -74,4 +75,57 @@ private:
 	wxString validatorProc, options;
 };
 
+class pgForeignDataWrapperObjFactory : public pgDatabaseObjFactory
+{
+public:
+	pgForeignDataWrapperObjFactory(const wxChar *tn, const wxChar *ns, const wxChar *nls, wxImage *img, wxImage *imgSm = 0)
+		: pgDatabaseObjFactory(tn, ns, nls, img, imgSm) {}
+	virtual pgCollection *CreateCollection(pgObject *obj);
+};
+
+
+// Object that lives in a foreign data wrapper
+class pgForeignDataWrapperObject : public pgDatabaseObject
+{
+public:
+	pgForeignDataWrapperObject(pgForeignDataWrapper *newForeignDataWrapper, pgaFactory &factory, const wxString &newName = wxEmptyString) : pgDatabaseObject(factory, newName)
+	{
+		SetForeignDataWrapper(newForeignDataWrapper);
+	}
+	pgForeignDataWrapperObject(pgForeignDataWrapper *newForeignDataWrapper, int newType, const wxString &newName = wxT("")) : pgDatabaseObject(newType, newName)
+	{
+		SetForeignDataWrapper(newForeignDataWrapper);
+	}
+
+	bool CanDrop();
+	bool CanEdit() { return true; }
+	bool CanCreate();
+
+	void SetForeignDataWrapper(pgForeignDataWrapper *newForeignDataWrapper);
+	virtual pgForeignDataWrapper *GetForeignDataWrapper() const
+	{
+		return fdw;
+	}
+	pgSet *ExecuteSet(const wxString &sql);
+	wxString ExecuteScalar(const wxString &sql);
+	bool ExecuteVoid(const wxString &sql);
+
+
+protected:
+	virtual void SetContextInfo(frmMain *form);
+
+	pgForeignDataWrapper *fdw;
+};
+
+
+
+// collection of pgForeignDataWrapperObject
+class pgForeignDataWrapperObjCollection : public pgCollection
+{
+public:
+	pgForeignDataWrapperObjCollection(pgaFactory *factory, pgForeignDataWrapper *fdw);
+	wxString GetTranslatedMessage(int kindOfMessage) const;
+	virtual bool CanCreate();
+};
+
 #endif
diff --git a/pgadmin/include/schema/pgForeignServer.h b/pgadmin/include/schema/pgForeignServer.h
new file mode 100644
index 0000000..4fe9a70
--- /dev/null
+++ b/pgadmin/include/schema/pgForeignServer.h
@@ -0,0 +1,68 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin III - PostgreSQL Tools
+// RCS-ID:      $Id$
+// Copyright (C) 2002 - 2010, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+// pgForeignServer.h PostgreSQL Foreign Server
+//
+//////////////////////////////////////////////////////////////////////////
+
+#ifndef PGFOREIGNSERVER_H
+#define PGFOREIGNSERVER_H
+
+#include "pgForeignDataWrapper.h"
+
+class pgCollection;
+
+class pgForeignServerFactory : public pgForeignDataWrapperObjFactory
+{
+public:
+    pgForeignServerFactory();
+    virtual dlgProperty *CreateDialog(frmMain *frame, pgObject *node, pgObject *parent);
+    virtual pgObject *CreateObjects(pgCollection *obj, ctlTree *browser, const wxString &restr=wxEmptyString);
+};
+extern pgForeignServerFactory foreignServerFactory;
+
+
+class pgForeignServer : public pgForeignDataWrapperObject
+{
+public:
+    pgForeignServer(pgForeignDataWrapper *newForeignDataWrapper, 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; }
+	bool CanCreate() { return true; }
+
+    wxString GetFdw() const { return fdw; }
+    void iSetFdw(const wxString& s) { fdw = s; }
+    wxString GetType() const { return type; }
+    void iSetType(const wxString& s) { type = s; }
+    wxString GetVersion() const { return version; }
+    void iSetVersion(const wxString& s) { version = s; }
+    wxString GetOptions() const { return options; }
+    wxString GetCreateOptions();
+    void iSetOptions(const wxString& s) { options=s; }
+
+    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 true; }
+    bool HasReferences() { return true; }
+
+private:
+    wxString fdw, type, version, options;
+};
+
+class pgForeignServerCollection : public pgForeignDataWrapperObjCollection
+{
+public:
+	pgForeignServerCollection(pgaFactory *factory, pgSchema *sch);
+	wxString GetTranslatedMessage(int kindOfMessage) const;
+};
+
+#endif
diff --git a/pgadmin/include/utils/misc.h b/pgadmin/include/utils/misc.h
index b301a1f..49ecb05 100644
--- a/pgadmin/include/utils/misc.h
+++ b/pgadmin/include/utils/misc.h
@@ -208,6 +208,7 @@ enum
 	PGM_DATABASE,
 	PGM_EXCLUDE,
 	PGM_FOREIGNKEY,
+	PGM_FOREIGNSERVER,
 	PGM_FUNCTION,
 	PGM_INDEX,
 	PGM_OPCLASS,
diff --git a/pgadmin/schema/module.mk b/pgadmin/schema/module.mk
index 8ee4381..bbcd106 100644
--- a/pgadmin/schema/module.mk
+++ b/pgadmin/schema/module.mk
@@ -30,6 +30,7 @@ pgadmin3_SOURCES += \
         $(subdir)/pgDomain.cpp \
         $(subdir)/pgForeignDataWrapper.cpp \
         $(subdir)/pgForeignKey.cpp \
+        $(subdir)/pgForeignServer.cpp \
         $(subdir)/pgFunction.cpp \
         $(subdir)/pgGroup.cpp \
         $(subdir)/pgIndex.cpp \
diff --git a/pgadmin/schema/pgCollection.cpp b/pgadmin/schema/pgCollection.cpp
index 498537c..66dacc8 100644
--- a/pgadmin/schema/pgCollection.cpp
+++ b/pgadmin/schema/pgCollection.cpp
@@ -25,6 +25,7 @@
 pgCollection::pgCollection(pgaFactory *factory)
 	: pgObject(*factory)
 {
+	fdw = 0;
 	job = 0;
 	schema = 0;
 	database = 0;
diff --git a/pgadmin/schema/pgForeignDataWrapper.cpp b/pgadmin/schema/pgForeignDataWrapper.cpp
index 491da98..f221872 100644
--- a/pgadmin/schema/pgForeignDataWrapper.cpp
+++ b/pgadmin/schema/pgForeignDataWrapper.cpp
@@ -16,6 +16,7 @@
 #include "pgAdmin3.h"
 #include "utils/misc.h"
 #include "schema/pgForeignDataWrapper.h"
+#include "schema/pgForeignServer.h"
 
 
 pgForeignDataWrapper::pgForeignDataWrapper(const wxString &newName)
@@ -57,6 +58,18 @@ wxString pgForeignDataWrapper::GetSql(ctlTree *browser)
 
 void pgForeignDataWrapper::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane)
 {
+	if (!expandedKids)
+	{
+		expandedKids = true;
+
+		browser->RemoveDummyChild(this);
+
+		// Log
+		wxLogInfo(wxT("Adding child object to foreign data wrapper %s"), GetIdentifier().c_str());
+
+		browser->AppendCollection(this, foreignServerFactory);
+	}
+
 	if (properties)
 	{
 		CreateListColumns(properties);
@@ -85,6 +98,17 @@ pgObject *pgForeignDataWrapper::Refresh(ctlTree *browser, const wxTreeItemId ite
 
 
 
+wxMenu *pgForeignDataWrapper::GetNewMenu()
+{
+	wxMenu *menu = pgObject::GetNewMenu();
+	if (database->GetCreatePrivilege())
+	{
+		foreignServerFactory.AppendMenu(menu);
+	}
+	return menu;
+}
+
+
 pgObject *pgForeignDataWrapperFactory::CreateObjects(pgCollection *collection, ctlTree *browser, const wxString &restriction)
 {
 	wxString sql;
@@ -153,6 +177,89 @@ wxString pgForeignDataWrapper::GetCreateOptions()
 }
 
 
+///////////////////////////////////////////////////////////////
+
+void pgForeignDataWrapperObject::SetForeignDataWrapper(pgForeignDataWrapper *newForeignDataWrapper)
+{
+	fdw = newForeignDataWrapper;
+	database = fdw->GetDatabase();
+}
+
+bool pgForeignDataWrapperObject::CanDrop()
+{
+	return true; //fdw->GetCreatePrivilege();
+}
+
+
+bool pgForeignDataWrapperObject::CanCreate()
+{
+	return true; //fdw->GetCreatePrivilege();
+}
+
+
+void pgForeignDataWrapperObject::SetContextInfo(frmMain *form)
+{
+}
+
+
+pgSet *pgForeignDataWrapperObject::ExecuteSet(const wxString &sql)
+{
+	return fdw->GetDatabase()->ExecuteSet(sql);
+}
+
+wxString pgForeignDataWrapperObject::ExecuteScalar(const wxString &sql)
+{
+	return fdw->GetDatabase()->ExecuteScalar(sql);
+}
+
+
+bool pgForeignDataWrapperObject::ExecuteVoid(const wxString &sql)
+{
+	return fdw->GetDatabase()->ExecuteVoid(sql);
+}
+
+
+/////////////////////////////////////////////////////
+
+pgForeignDataWrapperObjCollection::pgForeignDataWrapperObjCollection(pgaFactory *factory, pgForeignDataWrapper *newfdw)
+	: pgCollection(factory)
+{
+	fdw = newfdw;
+	database = fdw->GetDatabase();
+	server = database->GetServer();
+	iSetOid(fdw->GetOid());
+}
+
+
+wxString pgForeignDataWrapperObjCollection::GetTranslatedMessage(int kindOfMessage) const
+{
+	wxString message = wxEmptyString;
+
+	switch (kindOfMessage)
+	{
+		case RETRIEVINGDETAILS:
+			message = _("Retrieving details on foreign data wrappers");
+			break;
+		case REFRESHINGDETAILS:
+			message = _("Refreshing foreign data wrappers");
+			break;
+	}
+
+	return message;
+}
+
+bool pgForeignDataWrapperObjCollection::CanCreate()
+{
+	return GetDatabase()->GetCreatePrivilege();
+}
+
+
+pgCollection *pgForeignDataWrapperObjFactory::CreateCollection(pgObject *obj)
+{
+	return new pgForeignDataWrapperObjCollection(GetCollectionFactory(), (pgForeignDataWrapper *)obj);
+}
+
+
 ///////////////////////////////////////////////////
 
 #include "images/foreigndatawrapper.pngc"
diff --git a/pgadmin/schema/pgForeignServer.cpp b/pgadmin/schema/pgForeignServer.cpp
new file mode 100644
index 0000000..aca3000
--- /dev/null
+++ b/pgadmin/schema/pgForeignServer.cpp
@@ -0,0 +1,229 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// pgAdmin III - PostgreSQL Tools
+// RCS-ID:      $Id$
+// Copyright (C) 2002 - 2010, The pgAdmin Development Team
+// This software is released under the PostgreSQL Licence
+//
+// pgForeignServer.cpp - Foreign Server class
+//
+//////////////////////////////////////////////////////////////////////////
+
+// wxWindows headers
+#include <wx/wx.h>
+
+// App headers
+#include "pgAdmin3.h"
+#include "utils/misc.h"
+#include "schema/pgForeignServer.h"
+#include "schema/pgDatatype.h"
+
+
+pgForeignServer::pgForeignServer(pgForeignDataWrapper *newForeignDataWrapper, const wxString& newName)
+: pgForeignDataWrapperObject(newForeignDataWrapper, foreignServerFactory, newName)
+{
+}
+
+
+wxString pgForeignServer::GetTranslatedMessage(int kindOfMessage) const
+{
+	wxString message = wxEmptyString;
+
+	switch (kindOfMessage)
+	{
+		case RETRIEVINGDETAILS:
+			message = _("Retrieving details on foreign server");
+			message += wxT(" ") + GetName();
+			break;
+		case REFRESHINGDETAILS:
+			message = _("Refreshing foreign server");
+			message += wxT(" ") + GetName();
+			break;
+		case DROPINCLUDINGDEPS:
+			message = wxString::Format(_("Are you sure you wish to drop foreign server \"%s\" including all objects that depend on it?"),
+			                           GetFullIdentifier().c_str());
+			break;
+		case DROPEXCLUDINGDEPS:
+			message = wxString::Format(_("Are you sure you wish to drop foreign server \"%s?\""),
+			                           GetFullIdentifier().c_str());
+			break;
+		case DROPCASCADETITLE:
+			message = _("Drop foreign server cascaded?");
+			break;
+		case DROPTITLE:
+			message = _("Drop foreign server?");
+			break;
+	}
+
+	return message;
+}
+
+
+bool pgForeignServer::DropObject(wxFrame *frame, ctlTree *browser, bool cascaded)
+{
+    wxString sql=wxT("DROP SERVER ") + GetQuotedFullIdentifier();
+    if (cascaded)
+        sql += wxT(" CASCADE");
+    return GetDatabase()->ExecuteVoid(sql);
+}
+
+
+wxString pgForeignServer::GetSql(ctlTree *browser)
+{
+    if (sql.IsNull())
+    {
+        sql = wxT("-- Server: ") + GetQuotedFullIdentifier() + wxT("\n\n")
+            + wxT("-- DROP SERVER ") + GetQuotedFullIdentifier() + wxT(";")
+            + wxT("\n\nCREATE SERVER ") + GetName();
+
+        if (!GetType().IsEmpty())
+            sql += wxT("\n  TYPE ") + qtDbString(GetType());
+
+        if (!GetVersion().IsEmpty())
+            sql += wxT("\n  VERSION ") + qtDbString(GetVersion());
+
+        if (!GetOptions().IsEmpty())
+            sql += wxT("\n  OPTIONS (") + GetCreateOptions() + wxT(")");
+
+        sql += wxT(";\n")
+            +  GetOwnerSql(8, 4, wxT("SERVER ") + GetName())
+            +  GetGrant(wxT("U"), wxT("FOREIGN SERVER ") + GetQuotedFullIdentifier());
+    }
+    return sql;
+}
+
+
+void pgForeignServer::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(_("ACL"), GetAcl());
+        properties->AppendItem(_("Foreign Data Wrapper"), GetFdw());
+        properties->AppendItem(_("Type"), GetType());
+        properties->AppendItem(_("Version"), GetVersion());
+        properties->AppendItem(_("Options"), GetOptions());
+    }
+}
+
+
+
+pgObject *pgForeignServer::Refresh(ctlTree *browser, const wxTreeItemId item)
+{
+    pgObject *fs=0;
+    pgCollection *coll=browser->GetParentCollection(item);
+    if (coll)
+        fs = foreignServerFactory.CreateObjects(coll, 0, wxT("\n WHERE srv.oid=") + GetOidStr());
+
+    return fs;
+}
+
+
+////////////////////////////////////////////////////
+
+
+pgObject *pgForeignServerFactory::CreateObjects(pgCollection *collection, ctlTree *browser, const wxString &restriction)
+{
+    wxString sql;
+    pgForeignServer *fs=0;
+
+    sql = wxT("SELECT srv.oid, srvname, srvtype, srvversion, srvacl, fdw.fdwname as fdwname, description, ")
+        wxT("array_to_string(srvoptions, ',') AS srvoptions, ")
+        wxT("pg_get_userbyid(srvowner) as srvowner\n")
+        wxT("  FROM pg_foreign_server srv\n")
+        wxT("  LEFT OUTER JOIN pg_foreign_data_wrapper fdw on fdw.oid=srvfdw\n")
+        wxT("  LEFT OUTER JOIN pg_description des ON des.objoid=srv.oid AND des.objsubid=0\n")
+        + restriction + wxT("\n")
+        wxT(" ORDER BY srvname");
+    pgSet *foreignservers = collection->GetDatabase()->ExecuteSet(sql);
+    if (foreignservers)
+    {
+        while (!foreignservers->Eof())
+        {
+            fs = new pgForeignServer(collection->GetForeignDataWrapper(), foreignservers->GetVal(wxT("srvname")));
+            fs->iSetOid(foreignservers->GetOid(wxT("oid")));
+            fs->iSetOwner(foreignservers->GetVal(wxT("srvowner")));
+            fs->iSetFdw(foreignservers->GetVal(wxT("fdwname")));
+            fs->iSetAcl(foreignservers->GetVal(wxT("srvacl")));
+            fs->iSetComment(foreignservers->GetVal(wxT("description")));
+            fs->iSetType(foreignservers->GetVal(wxT("srvtype")));
+            fs->iSetVersion(foreignservers->GetVal(wxT("srvversion")));
+            fs->iSetOptions(foreignservers->GetVal(wxT("srvoptions")));
+
+            if (browser)
+            {
+                browser->AppendObject(collection, fs);
+			    foreignservers->MoveNext();
+            }
+            else
+                break;
+        }
+
+		delete foreignservers;
+    }
+
+    return fs;
+}
+
+
+wxString pgForeignServer::GetCreateOptions()
+{
+    wxString options_create = wxEmptyString;
+    wxString opt;
+    wxString val;
+
+    wxStringTokenizer tkz_options(options, wxT(","));
+    while (tkz_options.HasMoreTokens())
+    {
+        wxStringTokenizer tkz_option(tkz_options.GetNextToken(), wxT("="));
+        opt = tkz_option.GetNextToken();
+        val = tkz_option.GetNextToken();
+
+        if (!options_create.IsEmpty())
+            options_create += wxT(",");
+
+        options_create += opt + wxT(" '") + val + wxT("'");
+    }
+
+    return options_create;
+}
+
+
+/////////////////////////////
+
+wxString pgForeignServerCollection::GetTranslatedMessage(int kindOfMessage) const
+{
+	wxString message = wxEmptyString;
+
+	switch (kindOfMessage)
+	{
+		case RETRIEVINGDETAILS:
+			message = _("Retrieving details on foreign servers");
+			break;
+		case REFRESHINGDETAILS:
+			message = _("Refreshing foreign servers");
+			break;
+	}
+
+	return message;
+}
+
+///////////////////////////////////////////////////
+
+#include "images/foreignserver.pngc"
+#include "images/foreignserver-sm.pngc"
+#include "images/foreignservers.pngc"
+
+pgForeignServerFactory::pgForeignServerFactory() 
+: pgForeignDataWrapperObjFactory(__("Foreign Server"), __("New Foreign Server..."),
+__("Create a new Foreign Server."), foreignserver_png_img, foreignserver_sm_png_img)
+{
+}
+
+
+pgForeignServerFactory foreignServerFactory;
+static pgaCollectionFactory cf(&foreignServerFactory, __("Foreign Servers"), foreignservers_png_img);
diff --git a/pgadmin/schema/pgObject.cpp b/pgadmin/schema/pgObject.cpp
index 4c9e7c5..0d008cf 100644
--- a/pgadmin/schema/pgObject.cpp
+++ b/pgadmin/schema/pgObject.cpp
@@ -40,6 +40,7 @@
 #include "schema/pgCheck.h"
 #include "schema/pgIndexConstraint.h"
 #include "schema/pgForeignKey.h"
+#include "schema/pgForeignServer.h"
 #include "schema/pgRule.h"
 #include "schema/pgRole.h"
 #include "schema/pgCast.h"
@@ -118,6 +119,8 @@ wxString pgObject::GetTranslatedMessage(int kindOfMessage) const
 		message = ((gpExtTable *)this)->GetTranslatedMessage(kindOfMessage);
 	else if (type == wxT("ForeignKey"))
 		message = ((pgForeignKey *)this)->GetTranslatedMessage(kindOfMessage);
+	else if (type == wxT("ForeignServer"))
+		message = ((pgForeignServer *)this)->GetTranslatedMessage(kindOfMessage);
 	else if (type == wxT("FTS Configuration"))
 		message = ((pgTextSearchConfiguration *)this)->GetTranslatedMessage(kindOfMessage);
 	else if (type == wxT("FTS Dictionary"))
diff --git a/pgadmin/ui/dlgForeignServer.xrc b/pgadmin/ui/dlgForeignServer.xrc
new file mode 100644
index 0000000..9aea897
--- /dev/null
+++ b/pgadmin/ui/dlgForeignServer.xrc
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<resource>
+  <object class="wxDialog" name="dlgForeignServer">
+    <title></title>
+    <size>220,250d</size>
+    <style>wxDEFAULT_DIALOG_STYLE|wxCAPTION|wxSYSTEM_MENU|wxRESIZE_BORDER|wxRESIZE_BOX|wxTHICK_FRAME</style>
+    <object class="wxFlexGridSizer">
+      <cols>1</cols>
+      <growablecols>0</growablecols>
+      <growablerows>0</growablerows>
+      <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>8</rows>
+                <vgap>5</vgap>
+                <hgap>5</hgap>
+                <growablerows>6</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="wxTextCtrl" name="txtName">
+                    <size>135,-1d</size>
+                  </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">
+                    <size>135,-1d</size>
+                  </object>
+                  <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxStaticText" name="stOwner">
+                    <label>Owner</label>
+                  </object>
+                  <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="ctlComboBox" name="cbOwner">
+                    <size>135,-1d</size>
+                    <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="stForeignDataWrapper">
+                    <label>Foreign Data Wrapper</label>
+                  </object>
+                  <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="ctlComboBox" name="cbForeignDataWrapper">
+                    <size>135,-1d</size>
+                    <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="stType">
+                    <label>Type</label>
+                  </object>
+                  <flag>wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                  <border>4</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxTextCtrl" name="txtType">
+                    <size>135,-1d</size>
+                  </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="wxTextCtrl" name="txtVersion">
+                    <size>135,-1d</size>
+                  </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">
+                    <size>135,-1d</size>
+                    <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/>
+                    <size>135,-1d</size>
+                    <style>wxCB_READONLY|wxCB_DROPDOWN</style>
+                  </object>
+                  <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxALL</flag>
+                  <border>4</border>
+                </object>
+              </object>
+            </object>
+          </object>
+          <object class="notebookpage">
+            <label>Options</label>
+            <object class="wxPanel" name="pnlOptions">
+              <object class="wxFlexGridSizer">
+                <cols>1</cols>
+                <rows>3</rows>
+                <growablerows>0</growablerows>
+                <growablecols>0</growablecols>
+                <object class="sizeritem">
+                  <object class="wxListCtrl" name="lstOptions">
+                    <pos>70,15d</pos>
+                    <style>wxLC_REPORT|wxLC_SINGLE_SEL</style>
+                  </object>
+                  <option>80</option>
+                  <flag>wxALL|wxEXPAND</flag>
+                  <border>5</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxFlexGridSizer">
+                    <cols>2</cols>
+                    <rows>2</rows>
+                    <vgap>5</vgap>
+                    <hgap>5</hgap>
+                    <growablecols>1</growablecols>
+                    <object class="sizeritem">
+                      <object class="wxStaticText" name="stOption">
+                        <label>Option</label>
+                      </object>
+                      <flag>wxALIGN_CENTRE_VERTICAL</flag>
+                    </object>
+                    <object class="sizeritem">
+                      <object class="wxTextCtrl" name="txtOption">
+                        <size>135,-1d</size>
+                      </object>
+                      <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                      <border>4</border>
+                      <flag>wxEXPAND|wxALIGN_CENTRE_VERTICAL</flag>
+                    </object>
+                    <object class="sizeritem">
+                      <object class="wxStaticText" name="stValue">
+                        <label>Value</label>
+                      </object>
+                      <flag>wxALIGN_CENTRE_VERTICAL</flag>
+                    </object>
+                    <object class="sizeritem">
+                      <object class="wxTextCtrl" name="txtValue">
+                        <size>135,-1d</size>
+                      </object>
+                      <flag>wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>
+                      <border>4</border>
+                      <flag>wxEXPAND|wxALIGN_CENTRE_VERTICAL</flag>
+                    </object>
+                  </object>
+                  <flag>wxALL|wxEXPAND|wxALIGN_BOTTOM|wxALIGN_CENTRE_HORIZONTAL</flag>
+                  <border>5</border>
+                </object>
+                <object class="sizeritem">
+                  <object class="wxFlexGridSizer">
+                    <cols>2</cols>
+                    <rows>1</rows>
+                    <object class="sizeritem">
+                      <object class="wxButton" name="wxID_REMOVE">
+                        <label>Remove</label>
+                        <pos>13,58d</pos>
+                      </object>
+                      <flag>wxALL|wxALIGN_RIGHT</flag>
+                      <border>2</border>
+                    </object>
+                    <object class="sizeritem">
+                      <object class="wxButton" name="wxID_ADD">
+                        <label>Add/Change</label>
+                        <pos>13,78d</pos>
+                      </object>
+                      <flag>wxALL|wxALIGN_RIGHT</flag>
+                      <border>2</border>
+                    </object>
+                  </object>
+                  <flag>wxALIGN_RIGHT</flag>
+                </object>
+              </object>
+            </object>
+          </object>
+        </object>
+        <flag>wxALL|wxGROW|wxALIGN_CENTRE</flag>
+        <border>3</border>
+      </object>
+      <object class="spacer">
+        <size>2,2d</size>
+      </object>
+      <object class="sizeritem">
+        <object class="wxFlexGridSizer">
+          <cols>7</cols>
+          <growablecols>2</growablecols>
+          <object class="spacer">
+            <size>3,3d</size>
+          </object>
+          <object class="sizeritem">
+            <object class="wxButton" name="wxID_HELP">
+              <label>Help</label>
+            </object>
+          </object>
+          <object class="spacer">
+            <size>3,3d</size>
+          </object>
+          <object class="sizeritem">
+            <object class="wxButton" name="wxID_OK">
+              <label>&amp;OK</label>
+              <default>1</default>
+            </object>
+          </object>
+          <object class="spacer">
+            <size>3,3d</size>
+          </object>
+          <object class="sizeritem">
+            <object class="wxButton" name="wxID_CANCEL">
+              <label>&amp;Cancel</label>
+            </object>
+          </object>
+          <object class="spacer">
+            <size>3,3d</size>
+          </object>
+        </object>
+        <flag>wxTOP|wxLEFT|wxRIGHT|wxGROW</flag>
+      </object>
+      <object class="spacer">
+        <size>3,3d</size>
+      </object>
+      <object class="sizeritem">
+        <object class="wxStatusBar" name="unkStatusBar">
+          <style>wxST_SIZEGRIP</style>
+        </object>
+        <flag>wxGROW|wxALIGN_CENTRE</flag>
+        <border>3</border>
+      </object>
+    </object>
+  </object>
+</resource>
diff --git a/pgadmin/ui/module.mk b/pgadmin/ui/module.mk
index 9e2e3d9..79da290 100644
--- a/pgadmin/ui/module.mk
+++ b/pgadmin/ui/module.mk
@@ -28,6 +28,7 @@ TMP_ui += \
 	$(srcdir)/ui/dlgFindReplace.xrc \
 	$(srcdir)/ui/dlgForeignDataWrapper.xrc \
 	$(srcdir)/ui/dlgForeignKey.xrc \
+	$(srcdir)/ui/dlgForeignServer.xrc \
 	$(srcdir)/ui/dlgFunction.xrc \
 	$(srcdir)/ui/dlgGroup.xrc \
 	$(srcdir)/ui/dlgHbaConfig.xrc \
-- 
1.7.1

