Index: include/images/module.mk
===================================================================
--- include/images/module.mk	(revision 7506)
+++ include/images/module.mk	(working copy)
@@ -92,6 +92,8 @@
 	$(srcdir)/include/images/forward.xpm \
 	$(srcdir)/include/images/function.xpm \
 	$(srcdir)/include/images/functions.xpm \
+        $(srcdir)/include/images/gqbAdd.xpm \
+        $(srcdir)/include/images/gqbRemove.xpm \
 	$(srcdir)/include/images/group.xpm \
 	$(srcdir)/include/images/groups.xpm \
 	$(srcdir)/include/images/help.xpm \
Index: include/gqb/module.mk
===================================================================
--- include/gqb/module.mk	(revision 7506)
+++ include/gqb/module.mk	(working copy)
@@ -22,6 +22,7 @@
     $(srcdir)/include/gqb/gqbGridOrderTable.h \
     $(srcdir)/include/gqb/gqbGridProjTable.h \
     $(srcdir)/include/gqb/gqbGridRestTable.h \
+    $(srcdir)/include/gqb/gqbGridJoinTable.h \
     $(srcdir)/include/gqb/gqbModel.h \
     $(srcdir)/include/gqb/gqbObject.h \
     $(srcdir)/include/gqb/gqbObjectCollection.h \
Index: include/gqb/gqbViewPanels.h
===================================================================
--- include/gqb/gqbViewPanels.h	(revision 7506)
+++ include/gqb/gqbViewPanels.h	(working copy)
@@ -15,9 +15,11 @@
 #include <wx/minifram.h>
 
 // App headers
+#include "gqb/gqbViewController.h"
 #include "gqb/gqbGridProjTable.h"
 #include "gqb/gqbGridRestTable.h"
 #include "gqb/gqbGridOrderTable.h"
+#include "gqb/gqbGridJoinTable.h"
 
 enum gridButtons
 {
@@ -28,6 +30,9 @@
     GQB_COLS_ADD_BUTTON_ID,
     GQB_COLS_DROP_BUTTON_ID,
 
+    GQB_JOIN_COLS_ADD_BUTTON_ID,
+    GQB_JOIN_COLS_DELETE_BUTTON_ID,
+
     GQB_ORDER_DROP_BUTTON_ID,
     GQB_ORDER_DROP_ALL_BUTTON_ID,
     GQB_ORDER_ADD_ALL_BUTTON_ID,
@@ -77,7 +82,9 @@
     gqbColsTree(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style);
     wxTreeItemId& createRoot(wxString &Name);
     wxTreeItemId& getRootNode(){return rootNode;}
-    void refreshTree(gqbModel *model);
+    void refreshTree(gqbModel *model, gqbQueryObject *doNotInclude=NULL);
+    virtual void DeleteAllItems();
+    ~gqbColsTree() { DeleteAllItems(); }
 
 private:
     wxTreeItemId rootNode;
@@ -93,7 +100,7 @@
 {
 public:
     gqbColsPopUp(wxWindow* parent, wxWindowID id, wxString title, wxPoint pos, const wxSize size);
-    void refreshTree(gqbModel *_model);
+    virtual void refreshTree(gqbModel *_model);
     void OnPopUpOKClick(wxCommandEvent& event);
     void OnPopUpTreeClick(wxTreeEvent& event);
     void OnPopUpTreeDoubleClick(wxTreeEvent& event);
@@ -102,7 +109,7 @@
     void setUsedCell(wxGrid* grid, int row, int col){usedGrid=grid; _row=row; _col=col;};
     void focus();
 
-private:
+protected:
     int _row,_col;
     wxGrid *usedGrid;
     gqbColsTree *colsTree;
@@ -112,14 +119,40 @@
 
 };
 
+class gqbJoinsPanel;
+
+class gqbJoinsPopUp: public gqbColsPopUp
+{
+public:
+    gqbJoinsPopUp(
+        gqbJoinsPanel* parent, wxWindowID id, wxString title, wxPoint pos,
+        const wxSize size, gqbQueryJoin* _join, bool isSource,
+        gqbGridJoinTable* _gmodel);
+    void OnPopUpOKClick(wxCommandEvent& event);
+    void OnPopUpTreeClick(wxTreeEvent& event);
+    void OnPopUpTreeDoubleClick(wxTreeEvent& event);
+
+    // This should be called through OnPopUpOKClick & OnPopUpTreeDoubleClick
+    void updateJoin();
+
+    virtual void refreshTree(gqbModel* _model);
+
+private:
+    gqbQueryJoin *join; // Not owned, shouldn't be deletedat this class
+    gqbQueryObject *selectedTbl; //Not owned, shouldn't be deletedat this class
+    gqbColumn *selectedCol; //Not owned, shouldn't be deletedat this class
+    bool isSource;
+    gqbGridJoinTable *gModel; //Not owned, shouldn't be deletedat this class
+};
+
 //
 //   Criterias Panel
 //
 
-class wxRestrictionGrid: public wxGrid
+class gqbCustomGrid: public wxGrid
 {
 public:
-    wxRestrictionGrid(wxWindow* parent, wxWindowID id);
+    gqbCustomGrid(wxWindow* parent, wxWindowID id);
     void ComboBoxEvent(wxGridEvent& event);
     void RevertSel();
 
@@ -150,6 +183,31 @@
 
 };
 
+class gqbJoinsPanel: public wxPanel
+{
+public:
+    gqbJoinsPanel(wxWindow* parent, gqbModel *_model, gqbGridJoinTable *_gmodel, gqbController *_controller);
+    void OnCellLeftClick(wxGridEvent& ev);
+    void refreshTree(gqbModel *_model);
+    void OnButtonAdd(wxCommandEvent&);
+    void OnButtonDrop(wxCommandEvent&);
+    void SetGridColsSize();
+    void updateView(gqbQueryObject *tbl);
+    void updatedJoinType(gqbQueryJoin *join);
+
+private:
+    wxBitmapButton *buttonAdd, *buttonDrop;
+    wxBitmap addBitmap, dropBitmap;
+    void showColsPopUp(int row, int col, wxPoint pos);
+    wxGrid *joinsGrid;
+    gqbModel *model;              // Not owned shouldn't be deleted at this class
+    gqbJoinsPopUp *joinsPopUp;    // It will be automatically deleted
+    gqbGridJoinTable *gModel;     // Not owned shouldn't be deleted at this class
+    gqbController *controller;    // Not owned shouldn't be deleted at this class
+    DECLARE_EVENT_TABLE()
+
+};
+
 //
 // Order by Panel
 //
Index: include/gqb/gqbViewController.h
===================================================================
--- include/gqb/gqbViewController.h	(revision 7506)
+++ include/gqb/gqbViewController.h	(working copy)
@@ -27,6 +27,7 @@
 #include "gqb/gqbGridProjTable.h"
 #include "gqb/gqbGridRestTable.h"
 #include "gqb/gqbGridOrderTable.h"
+#include "gqb/gqbGridJoinTable.h"
 #include "gqb/gqbBrowser.h"
 
 class gqbView;
@@ -52,6 +53,15 @@
     DECLARE_EVENT_TABLE()
 };
 
+// This enum is useful to select particular page from the tabs
+enum tabsIndex
+{
+    ti_colsGridPanel = 0,
+    ti_criteriaPanel,
+    ti_orderPanel,
+    ti_joinsPanel
+};
+
 class gqbController: public wxObject
 {
 public:
@@ -109,8 +119,11 @@
     wxPanel* getColsGridPanel(){ return (wxPanel*)projectionPanel; };
     wxPanel* getCriteriaPanel(){ return (wxPanel*)criteriaPanel; };
     wxPanel* getOrderPanel(){ return (wxPanel*)orderPanel; };
+    wxPanel* getJoinsPanel() { return joinsPanel; }
     void newTableAdded(gqbQueryObject *item);
     bool clickOnJoin (gqbQueryJoin *join, wxPoint &pt, wxPoint &origin, wxPoint &dest);
+    void updateTable(gqbQueryObject *table);
+    void updateJoin(gqbQueryJoin *join);
 
 	// Functions for all gqb extra Panels (projection, criteria..)
     void emptyPanelsData();
@@ -124,9 +137,10 @@
 																// if change the way objects were draw changes too.
     gqbIteratorBase *iterator;									//include here for reuse of iterator, should be 
 																// delete when class destroy
-    wxPanel *projectionPanel, *criteriaPanel, *orderPanel;
+    wxPanel *projectionPanel, *criteriaPanel, *orderPanel, *joinsPanel;
     gqbGridProjTable *gridTable;								// Data model for the columns grid internals
     gqbGridRestTable *restrictionsGridTable;					// Data model for restricions grid internals
+    gqbGridJoinTable *joinsGridTable;                            // Data model for joins grid internals
                           
     gqbGridOrderTable *orderByLGridTable, *orderByRGridTable;	// Data model for order by grid internals
     wxSize canvasSize;
@@ -144,7 +158,6 @@
     wxMenu *m_rightJoins, *m_rightTables;
     void OnMenuJoinDelete(wxCommandEvent& event);
     void OnMenuTableDelete(wxCommandEvent& event);
-    void OnMenuJoinSetType(wxCommandEvent& event);
     void OnMenuTableSetAlias(wxCommandEvent& event);
     wxArrayString joinTypeChoices;
     DECLARE_EVENT_TABLE()
Index: include/gqb/gqbArrayCollection.h
===================================================================
--- include/gqb/gqbArrayCollection.h	(revision 7506)
+++ include/gqb/gqbArrayCollection.h	(working copy)
@@ -59,6 +59,7 @@
     void insertAtIndex(gqbObject *item, int index);
     void deleteAll();
     void removeAll();
+    gqbObject *& operator[](size_t index) { return gqbArray[index]; }
 
 private:
     gqbObjsArray gqbArray;
Index: pgAdmin3.vcproj
===================================================================
--- pgAdmin3.vcproj	(revision 7506)
+++ pgAdmin3.vcproj	(working copy)
@@ -1286,6 +1286,14 @@
 					>
 				</File>
 				<File
+					RelativePath=".\include\images\gqbAdd.xpm"
+					>
+				</File>
+				<File
+					RelativePath=".\include\images\gqbRemove.xpm"
+					>
+				</File>
+				<File
 					RelativePath=".\include\images\group.xpm"
 					>
 				</File>
@@ -2414,6 +2422,10 @@
 					>
 				</File>
 				<File
+					RelativePath=".\include\gqb\gqbGridJoinTable.h"
+					>
+				</File>
+				<File
 					RelativePath=".\include\gqb\gqbGridProjTable.h"
 					>
 				</File>
@@ -3587,6 +3599,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\gqb\gqbGridJoinTable.cpp"
+				>
+			</File>
+			<File
 				RelativePath=".\gqb\gqbGridProjTable.cpp"
 				>
 			</File>
Index: gqb/gqbView.cpp
===================================================================
--- gqb/gqbView.cpp	(revision 7506)
+++ gqb/gqbView.cpp	(working copy)
@@ -45,7 +45,6 @@
 EVT_ERASE_BACKGROUND(gqbView::onEraseBackGround)  //This erase flicker create by wxStaticText when erasing background but this is not needed
 EVT_KEY_DOWN(gqbView::OnKeyDown)
 EVT_MENU(GQB_RMJ_DELETE,	gqbView::OnMenuJoinDelete)
-EVT_MENU(GQB_RMJ_SETTYPE,	gqbView::OnMenuJoinSetType)
 EVT_MENU(GQB_RMT_DELETE,	gqbView::OnMenuTableDelete)
 EVT_MENU(GQB_RMT_SETALIAS,	gqbView::OnMenuTableSetAlias)
 END_EVENT_TABLE()
@@ -95,6 +94,10 @@
     this->restrictionsGridTable = new gqbGridRestTable(model->getRestrictions());
     this->criteriaPanel = new gqbCriteriaPanel(controller->getTabs(),model,restrictionsGridTable);
 
+    // Create Joins Panel
+    this->joinsGridTable = new gqbGridJoinTable(this->model);
+    this->joinsPanel = new gqbJoinsPanel(controller->getTabs(), model, joinsGridTable, controller);
+
     // Create Order by Panel
     this->orderByLGridTable = new gqbGridOrderTable(1,model->getOrdByAvailColumns(),model->getOrdByAvailParents(),NULL);
     this->orderByRGridTable = new gqbGridOrderTable(2,model->getOrdByColumns(), model->getOrdByParents(),model->getOrdByKind());
@@ -162,7 +165,6 @@
             if(!m_rightJoins)
             {
                 m_rightJoins = new wxMenu;
-                m_rightJoins->Append(GQB_RMJ_SETTYPE, _("&Set Join Type"));
                 m_rightJoins->Append(GQB_RMJ_DELETE, _("&Delete Join"));
             }
             cTempSelected=NULL;
@@ -177,6 +179,7 @@
 {
     if(jTempSelected)
     {
+        this->joinsGridTable->removeJoin(joinSelected);
         controller->removeJoin(jTempSelected);
         jTempSelected=NULL;
         this->Refresh();
@@ -184,46 +187,6 @@
 }
 
 
-void gqbView::OnMenuJoinSetType(wxCommandEvent& WXUNUSED(event))
-{
-// Because a bug that scrolled automatically the panel of the view if this dialog is called, then assign
-// as his parent the main container of the view, and void the bug
-    if(jTempSelected)
-    {
-        wxSingleChoiceDialog dialog(controller->getDialogParent(),
-            _("Select the kind of Join"),
-            _("Please select a type of Join for relation, e.g. = "),
-            joinTypeChoices,
-            NULL,
-            wxOK | wxCANCEL| wxCENTRE);
-        dialog.SetSelection(0);
-        if (dialog.ShowModal() == wxID_OK)
-        {
-            if(dialog.GetStringSelection().Contains(wxT(" = ")))
-            {
-                jTempSelected->setKindofJoin(_equally);
-            }
-            else if(dialog.GetStringSelection().Contains(wxT(" > ")))
-            {
-                jTempSelected->setKindofJoin(_greater);
-            }
-            else if(dialog.GetStringSelection().Contains(wxT(" < ")))
-            {
-                jTempSelected->setKindofJoin(_lesser);
-            }
-            else if(dialog.GetStringSelection().Contains(wxT(" >= ")))
-            {
-                jTempSelected->setKindofJoin(_equgreater);
-            }
-            else if(dialog.GetStringSelection().Contains(wxT(" <= ")))
-            {
-                jTempSelected->setKindofJoin(_equlesser);
-            }
-        }
-    }
-}
-
-
 void gqbView::OnMenuTableDelete(wxCommandEvent& WXUNUSED(event))
 {
     if(cTempSelected)
@@ -246,8 +209,12 @@
             _("Please enter an alias for the table."),
             wxT(""),
             wxOK | wxCANCEL| wxCENTRE);
+        dialog.SetValue(cTempSelected->getAlias());
         if (dialog.ShowModal() == wxID_OK)
+        {
             cTempSelected->setAlias(dialog.GetValue());
+            joinsPanel->Refresh();
+        }
         cTempSelected=NULL;
         this->Refresh();
     }
@@ -277,42 +244,19 @@
             _("Please enter an alias for the table."),
                 wxT(""),
                 wxOK | wxCANCEL| wxCENTRE);
+            dialog.SetValue(t->getAlias());
             if (dialog.ShowModal() == wxID_OK)
+            {
                 t->setAlias(dialog.GetValue());
+                joinsPanel->Refresh();
+            }
         }
         else if(anySelected->getType()==GQB_JOIN)
         {
             gqbQueryJoin *j = (gqbQueryJoin *) anySelected;
-            wxSingleChoiceDialog dialog(controller->getDialogParent(),
-                _("Select the kind of join"),
-                _("Please select a type of join between the relations."),
-                joinTypeChoices,
-                NULL,
-                wxOK | wxCANCEL| wxCENTRE);
-            dialog.SetSelection(0);
-            if (dialog.ShowModal() == wxID_OK)
-            {
-                if(dialog.GetStringSelection().Contains(wxT(" = ")))
-                {
-                    j->setKindofJoin(_equally);
-                }
-                else if(dialog.GetStringSelection().Contains(wxT(" > ")))
-                {
-                    j->setKindofJoin(_greater);
-                }
-                else if(dialog.GetStringSelection().Contains(wxT(" < ")))
-                {
-                    j->setKindofJoin(_lesser);
-                }
-                else if(dialog.GetStringSelection().Contains(wxT(" >= ")))
-                {
-                    j->setKindofJoin(_equgreater);
-                }
-                else if(dialog.GetStringSelection().Contains(wxT(" <= ")))
-                {
-                    j->setKindofJoin(_equlesser);
-                }
-            }
+
+            controller->getTabs()->ChangeSelection(ti_joinsPanel);
+            this->joinsGridTable->selectJoin(j);
         }
     }
     this->Refresh();
@@ -454,6 +398,9 @@
 		if(mode==pt_normal)
         {
             changeTOpressed=false;
+            anySelected=controller->getModelSelected(pos, collectionSelected, joinSelected, false);
+            if (anySelected && anySelected->getType() == GQB_JOIN)
+                this->joinsGridTable->selectJoin((gqbQueryJoin *)anySelected);
         }                                         
         // Pointer is used to add joins
 		else if(mode==pt_join)
@@ -490,6 +437,7 @@
                     // GQB-TODO: Allow other type of joins
                     gqbQueryJoin *qj=controller->addJoin(joinSource,joinSCol,joinDest,joinDCol,_equally);
                     graphBehavior->calcAnchorPoint(qj);
+                    this->joinsGridTable->AppendJoin(qj);
                 }
                 // Let the temporary join line to be draw again [Don't destroy anything because all object where own by other objects this are just pointers]
                 joinSource=NULL;
@@ -546,6 +494,7 @@
     {
         if(collectionSelected)
         {
+            this->joinsGridTable->removeJoins(collectionSelected);
             controller->removeTableFromModel(collectionSelected,gridTable,orderByLGridTable,orderByRGridTable);
             collectionSelected=NULL;
             this->Refresh();
@@ -553,6 +502,7 @@
 
         if(joinSelected)
         {
+            this->joinsGridTable->removeJoin(joinSelected);
             controller->removeJoin(joinSelected);
             joinSelected=NULL;
             this->Refresh();
@@ -641,6 +591,7 @@
 void gqbView::emptyPanelsData()
 {
     gridTable->emptyTableData();
+    this->joinsGridTable->emptyTableData();
 }
 
 
@@ -656,3 +607,39 @@
         orderByLGridTable->GetView()->ProcessTableMessage( msg );
     }
 }
+
+void gqbView::updateTable(gqbQueryObject *queryTable)
+{
+    if (queryTable->getHaveJoins())
+    {
+        gqbIteratorBase *j=queryTable->createJoinsIterator();
+        while (j->HasNext())
+        {
+            gqbQueryJoin *tmp= (gqbQueryJoin *)j->Next();
+            graphBehavior->calcAnchorPoint(tmp);
+        }
+        delete j;
+    }
+
+    // Update position of anchor points of Joins that come from others tables
+    if (queryTable->getHaveRegJoins())
+    {
+        gqbIteratorBase *r=queryTable->createRegJoinsIterator();
+        while (r->HasNext())
+        {
+            gqbQueryJoin *tmp= (gqbQueryJoin *)r->Next();
+            graphBehavior->calcAnchorPoint(tmp);
+        }
+        delete r;
+    }
+    this->Refresh();
+}
+
+void gqbView::updateJoin(gqbQueryJoin *join)
+{
+    if (join)
+    {
+        graphBehavior->calcAnchorPoint(join);
+        this->Refresh();
+    }
+}
Index: gqb/gqbViewPanels.cpp
===================================================================
--- gqb/gqbViewPanels.cpp	(revision 7506)
+++ gqb/gqbViewPanels.cpp	(working copy)
@@ -25,6 +25,7 @@
 #include "gqb/gqbGridProjTable.h"
 #include "gqb/gqbGridRestTable.h"
 #include "gqb/gqbGridOrderTable.h"
+#include "gqb/gqbGridJoinTable.h"
 
 // Images
 #include "images/gqbUp.xpm"
@@ -41,7 +42,13 @@
 #include "images/table-sm.xpm"
 #include "images/column-sm.xpm"
 #include "images/view-sm.xpm"
+#include "images/gqbAdd.xpm"
+#include "images/gqbRemove.xpm"
 
+// Get available ID for Criteria & Joins Panel
+long CRITERIA_PANEL_RESTRICTION_GRID_ID = ::wxNewId();
+long JOINS_PANEL_GRID_ID = ::wxNewId();
+
 //
 //    View Columns Grid Panel Class.
 //
@@ -383,10 +390,50 @@
 }
 
 
-void gqbColsTree::refreshTree(gqbModel * model)
+// Override the DeleteAllItems virtual function
+// Needs to set null as item-data, otherwise they will delete
+// the gqbQueryObject(s) and gqbColumn(s), while deleting these
+// items
+void gqbColsTree::DeleteAllItems()
 {
+    wxTreeItemId tableId;
+    wxTreeItemIdValue tableCookie;
+    wxTreeItemId rootId = this->GetRootItem();
+
+    if ( this->GetChildrenCount(rootId, false) != 0 )
+    {
+        wxTreeItemId lastTableId = this->GetLastChild(rootId);
+        tableId = this->GetFirstChild(rootId, tableCookie);
+        while ( true )
+        {
+            this->SetItemData(tableId, NULL);
+            wxTreeItemIdValue colCookie;
+            wxTreeItemId colId = this->GetFirstChild(tableId, colCookie);
+            wxTreeItemId lastColId = this->GetLastChild(tableId);
+            if ( this->GetChildrenCount(tableId, false) != 0 )
+            {
+                while ( true )
+                {
+                    this->SetItemData(colId, NULL);
+                    if ( colId != lastColId )
+                        colId = this->GetNextSibling(colId);
+                    else
+                        break;                    
+                }
+            }
+            if ( lastTableId != tableId )
+                tableId = this->GetNextSibling(tableId);
+            else
+                break;
+        }
+    }
+    wxTreeCtrl::DeleteAllItems();
+}
+
+void gqbColsTree::refreshTree(gqbModel * model, gqbQueryObject *doNotInclude)
+{
     // This remove and delete data inside tree's node
-	this->DeleteAllItems();                       
+    this->DeleteAllItems();
     wxString a=_("Select column");
     createRoot(a);
     this->Expand(rootNode);
@@ -396,26 +443,29 @@
     while(iterator->HasNext())
     {
         gqbQueryObject *tmpTable= (gqbQueryObject *)iterator->Next();
+
+        if (doNotInclude && tmpTable == doNotInclude)
+            continue;
 		
-		int iconIndex;
-		if (tmpTable->parent->getType() == GQB_TABLE)
-			iconIndex = 1;
-		else // Must be a view
-			iconIndex = 3;
+        int iconIndex;
+        if (tmpTable->parent->getType() == GQB_TABLE)
+            iconIndex = 1;
+        else // Must be a view
+            iconIndex = 3;
 
         if(tmpTable->getAlias().length()>0)
         {
-            parent=this->AppendItem(rootNode, tmpTable->getAlias() , iconIndex, iconIndex, NULL);
+            parent=this->AppendItem(rootNode, tmpTable->getAlias() , iconIndex, iconIndex, tmpTable);
         }
         else
         {
-            parent=this->AppendItem(rootNode, tmpTable->getName() , iconIndex, iconIndex, NULL);
+            parent=this->AppendItem(rootNode, tmpTable->getName() , iconIndex, iconIndex, tmpTable);
         }
         gqbIteratorBase *colsIterator = tmpTable->parent->createColumnsIterator();
         while(colsIterator->HasNext())
         {
             gqbColumn *tmpColumn= (gqbColumn *)colsIterator->Next();
-            this->AppendItem(parent, tmpColumn->getName() , 2, 2,NULL);
+            this->AppendItem(parent, tmpColumn->getName() , 2, 2, tmpColumn);
         }
         delete colsIterator;
     }
@@ -546,13 +596,11 @@
     gModel=gridModel;
     colsPopUp=NULL;
 
-    // GQB-TODO: add real ID not 321
-    // wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxTE_DONTWRAP,wxT(""));
-    this->restrictionsGrid = new wxRestrictionGrid(this, 321);
+    this->restrictionsGrid = new gqbCustomGrid(this, CRITERIA_PANEL_RESTRICTION_GRID_ID);
     restrictionsGrid->SetTable(gModel, true, wxGrid::wxGridSelectCells);
     this->restrictionsGrid->SetSelectionMode(wxGrid::wxGridSelectRows);
 
-    this->Connect(321, wxEVT_GRID_CELL_LEFT_CLICK, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &gqbCriteriaPanel::OnCellLeftClick);
+    this->Connect(CRITERIA_PANEL_RESTRICTION_GRID_ID, wxEVT_GRID_CELL_LEFT_CLICK, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &gqbCriteriaPanel::OnCellLeftClick);
     // GQB-TODO: in a future implement OnMouseWheel
 
     addBitmap= wxBitmap(gqbAddRest_xpm);
@@ -633,7 +681,7 @@
 void gqbCriteriaPanel::OnCellLeftClick(wxGridEvent& event)
 {
     wxObject *object = event.GetEventObject();
-    wxRestrictionGrid *grid = wxDynamicCast( object, wxRestrictionGrid );
+    gqbCustomGrid *grid = wxDynamicCast( object, gqbCustomGrid );
 
     // Only show editor y case of column 1
     if(event.GetCol()==1)
@@ -718,7 +766,7 @@
 //
 //  View Selection Criteria Panel Class's Grid.
 //
-wxRestrictionGrid::wxRestrictionGrid(wxWindow* parent, wxWindowID id):
+gqbCustomGrid::gqbCustomGrid(wxWindow* parent, wxWindowID id):
 wxGrid(parent, id, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxTE_BESTWRAP,wxT("")),
 m_selTemp(NULL)
 {
@@ -737,7 +785,7 @@
 }
 
 
-void wxRestrictionGrid::RevertSel()
+void gqbCustomGrid::RevertSel()
 {
     if (m_selTemp)
     {
@@ -748,7 +796,7 @@
 }
 
 
-void wxRestrictionGrid::ComboBoxEvent(wxGridEvent& event)
+void gqbCustomGrid::ComboBoxEvent(wxGridEvent& event)
 {
 
     // This forces the cell to go into edit mode directly
@@ -772,7 +820,7 @@
     }
 
     // hack to prevent selection from being lost when click combobox
-    if (event.GetCol() == 0 && this->IsInSelection(event.GetRow(), event.GetCol()))
+    if (this->IsInSelection(event.GetRow(), event.GetCol()))
     {
         this->m_selTemp = this->m_selection;
         this->m_selection = NULL;
@@ -1266,3 +1314,310 @@
     }
     event.Skip();
 }
+
+// Popup window for gqbJoinsPanel
+//
+gqbJoinsPopUp::gqbJoinsPopUp(
+                             gqbJoinsPanel* parent, wxWindowID id, wxString title,
+                             wxPoint pos, const wxSize size, gqbQueryJoin *_join,
+                             bool isSource, gqbGridJoinTable* _gmodel)
+:gqbColsPopUp(parent, id, title, pos, size)
+{
+    this->editTree->SetEditable(false);
+
+    // Handles different events for Ok button, single mouse click, double mouse click
+    this->Connect(QR_TREE_OK, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) &gqbJoinsPopUp::OnPopUpOKClick);
+    this->Connect(QR_TREE, wxEVT_COMMAND_TREE_ITEM_ACTIVATED, (wxObjectEventFunction) (wxEventFunction) (wxTreeEventFunction) &gqbJoinsPopUp::OnPopUpTreeDoubleClick);
+    this->Connect(QR_TREE, wxEVT_COMMAND_TREE_SEL_CHANGED, (wxObjectEventFunction) (wxEventFunction) (wxTreeEventFunction) &gqbJoinsPopUp::OnPopUpTreeClick);
+
+    this->selectedTbl = NULL;
+    this->selectedCol = NULL;
+    this->join = _join;
+    this->isSource = isSource;
+    this->gModel = _gmodel;
+}
+
+void gqbJoinsPopUp::refreshTree(gqbModel *_model)
+{
+    model=_model;
+    if(colsTree && _model)
+    {
+        // Do not include already included Table
+        // For self join, other entity for the same table should be used with alias
+        if ( join )
+            colsTree->refreshTree(model, isSource ? join->getDestQTable() : join->getSourceQTable());
+        else
+            colsTree->refreshTree(model);
+    }
+}
+
+// single mouse click on tree
+void  gqbJoinsPopUp::OnPopUpTreeClick(wxTreeEvent& event)
+{
+    if( colsTree )
+    {
+        wxTreeItemId itemId = event.GetItem();
+        wxTreeItemId itemIdParent =  colsTree->GetItemParent(itemId);
+
+        if(!colsTree->ItemHasChildren(itemId) && (colsTree->GetRootItem()!=itemId))
+        {
+            selectedCol = (gqbColumn *)colsTree->GetItemData(itemId);
+            selectedTbl = (gqbQueryObject *)colsTree->GetItemData(itemIdParent);
+            this->editTree->SetValue(qtIdent(colsTree->GetItemText(itemIdParent)) + wxT(".") + qtIdent(colsTree->GetItemText(itemId)));
+        }
+        else
+        {
+            selectedCol = NULL;
+            selectedTbl = NULL;
+        }
+    }
+}
+
+
+void gqbJoinsPopUp::OnPopUpOKClick(wxCommandEvent& event)
+{
+    if( colsTree && selectedCol && selectedTbl )
+    {
+        // This should update the selected Join with the new values.
+        updateJoin();
+    }
+    
+    this->MakeModal(false);
+    this->Hide();
+    this->GetParent()->Refresh();
+    this->join = NULL;
+    this->selectedCol = NULL;
+    this->selectedTbl = NULL;
+}
+
+
+// Update the view fo this query table, involved in
+// the whole operation
+void gqbJoinsPanel::updateView(gqbQueryObject *table)
+{
+    if (table)
+        controller->getView()->updateTable(table);
+}
+
+void gqbJoinsPopUp::updateJoin()
+{
+    if ((isSource ? join->getSCol() : join->getDCol()) != selectedCol)
+    {
+        // Create a new join with the existing data
+        // Replace it in the gqbJoinTable with the existing one
+        // Unregister the join, if exists
+        gqbQueryObject *srcTbl = ( isSource ? selectedTbl : join->getSourceQTable() );
+        gqbQueryObject *destTbl = ( isSource ? join->getDestQTable() : selectedTbl );
+        gqbColumn *srcCol = ( isSource ? selectedCol : join->getSCol() );
+        gqbColumn *destCol = ( isSource ? join->getDCol() : selectedCol );
+        type_Join joinType = join->getKindofJoin();
+
+        gqbQueryJoin *newJoin = NULL;
+        if( srcTbl && destTbl )
+        {
+            newJoin = srcTbl->addJoin(srcTbl, destTbl, srcCol, destCol, joinType);
+            ((gqbJoinsPanel *)GetParent())->updateView(newJoin->getSourceQTable());
+        }
+        else
+            newJoin = new gqbQueryJoin(srcTbl, destTbl, srcCol, destCol, joinType);
+
+        gModel->ReplaceJoin(join, newJoin);
+
+        if (join->getSourceQTable() && join->getDestQTable())
+        {
+            // This will remove the join object too
+            gqbQueryObject* srcObj = join->getSourceQTable();
+            srcObj->removeJoin(join, true);
+        }
+        else
+        {
+            delete join;
+        }
+        join = newJoin;
+    }
+}
+
+
+void  gqbJoinsPopUp::OnPopUpTreeDoubleClick(wxTreeEvent& event)
+{
+    if(colsTree)
+    {
+        wxTreeItemId itemId = event.GetItem();
+        wxTreeItemId itemIdParent =  colsTree->GetItemParent(itemId);
+        if(!colsTree->ItemHasChildren(itemId) && (colsTree->GetRootItem()!=itemId))
+        {
+            selectedCol = (gqbColumn *)colsTree->GetItemData(itemId);
+            selectedTbl = (gqbQueryObject *)colsTree->GetItemData(itemIdParent);
+
+            updateJoin();
+
+            this->MakeModal(false);
+            this->Hide();
+            this->GetParent()->Refresh();
+            this->join = NULL;
+            this->selectedCol = NULL;
+            this->selectedTbl = NULL;
+        }
+    }
+}
+
+//
+//    View Selection Joins Panel Class.
+//
+
+BEGIN_EVENT_TABLE(gqbJoinsPanel, wxPanel)
+EVT_BUTTON(GQB_JOIN_COLS_ADD_BUTTON_ID, gqbJoinsPanel::OnButtonAdd)
+EVT_BUTTON(GQB_JOIN_COLS_DELETE_BUTTON_ID, gqbJoinsPanel::OnButtonDrop)
+END_EVENT_TABLE()
+
+gqbJoinsPanel::gqbJoinsPanel(wxWindow* parent, gqbModel *_model, gqbGridJoinTable* _gmodel, gqbController *_controller):
+wxPanel(parent, wxID_ANY)
+{
+    model=_model;
+    gModel=_gmodel;
+    controller=_controller;
+    joinsPopUp=NULL;
+
+    this->joinsGrid = new gqbCustomGrid(this, JOINS_PANEL_GRID_ID);
+    joinsGrid->CreateGrid(0, 5, wxGrid::wxGridSelectRows);
+    joinsGrid->SetTable(gModel, true, wxGrid::wxGridSelectCells);
+    this->joinsGrid->SetSelectionMode(wxGrid::wxGridSelectRows);
+
+    this->Connect(JOINS_PANEL_GRID_ID, wxEVT_GRID_CELL_LEFT_CLICK, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &gqbJoinsPanel::OnCellLeftClick);
+    // GQB-TODO: in a future implement OnMouseWheel
+
+    addBitmap= wxBitmap(gqbAdd_xpm);
+    dropBitmap= wxBitmap(gqbRemove_xpm);
+    buttonAdd= new wxBitmapButton( this, GQB_JOIN_COLS_ADD_BUTTON_ID,  addBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, wxT("Add"));
+    buttonDrop= new wxBitmapButton( this, GQB_JOIN_COLS_DELETE_BUTTON_ID,  dropBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, wxT("Remove"));
+
+    wxBoxSizer *horizontalSizer = new wxBoxSizer( wxHORIZONTAL );
+    horizontalSizer->Add(joinsGrid,
+        1,                                        // make vertically stretchable
+        wxEXPAND |                                // make horizontally stretchable
+        wxALL,                                    //   and make border all around
+        3 );                                     // set border width to 10
+
+    wxBoxSizer *buttonsSizer = new wxBoxSizer( wxVERTICAL );
+
+    buttonsSizer->Add(
+        this->buttonAdd,
+        0,                                        // make horizontally unstretchable
+        wxALL,                                    // make border all around (implicit top alignment)
+        10 );                                     // set border width to 10
+
+    buttonsSizer->Add(
+        this->buttonDrop,
+        0,                                        // make horizontally unstretchable
+        wxALL,                                    // make border all around (implicit top alignment)
+        10 );                                     // set border width to 10
+
+    horizontalSizer->Add(
+        buttonsSizer,
+        0,                                        // make vertically unstretchable
+        wxALIGN_CENTER );                         // no border and centre horizontally
+
+    this->SetSizer(horizontalSizer);
+}
+
+
+void gqbJoinsPanel::showColsPopUp(int row, int col, wxPoint pos)
+{
+    if( joinsPopUp )
+    {
+        joinsPopUp->Destroy();
+        joinsPopUp = NULL;
+    }
+    joinsPopUp = new gqbJoinsPopUp(this,-1,wxT("Select Column"),wxDefaultPosition,wxDefaultSize, this->gModel->GetJoin(row), ( col == 0  ? true : false ), this->gModel);
+    
+    refreshTree(model);
+
+    // Set initial Value
+    joinsPopUp->setEditText(joinsGrid->GetCellValue(row,col));
+
+    // Set Position for Pop Up Tree
+    // Position of wxNotebook
+    wxPoint p=this->GetParent()->GetPosition();
+    p.x+=pos.x;
+    p.y+=pos.y;
+    wxPoint p2=this->GetPosition();
+
+    // Position of panel inside wxNotebook
+    p.x+=p2.x;
+    p.y+=p2.y+40;
+    joinsPopUp->SetPosition(p);
+    joinsPopUp->Show();
+    joinsPopUp->MakeModal(true);
+    joinsPopUp->focus();
+    joinsPopUp->setUsedCell(joinsGrid,row,col);
+}
+
+
+void gqbJoinsPanel::refreshTree(gqbModel *_model)
+{
+    model=_model;
+    if(joinsPopUp && model)
+        joinsPopUp->refreshTree(model);
+}
+
+
+void gqbJoinsPanel::OnCellLeftClick(wxGridEvent& event)
+{
+    wxObject *object = event.GetEventObject();
+    gqbCustomGrid *grid = wxDynamicCast( object, gqbCustomGrid );
+
+    // Only show editor y case of column 1
+    if(event.GetCol()==1)
+    {
+        grid->ComboBoxEvent(event);
+    } else if(event.GetCol()==0 || event.GetCol()==2)
+    {
+        // Allow mini browser frame to be visible to user
+        wxRect cellSize=grid->CellToRect(event.GetRow(), event.GetCol());
+        wxPoint p = event.GetPosition();
+        joinsGrid->CalcUnscrolledPosition(p.x,p.y,&p.x,&p.y);
+
+        // Number 17 is button's width at cellRender function [nButtonWidth]
+        if((grid->GetRowLabelSize()+cellSize.GetRight())-(p.x) <= 17 )
+        {
+            p = event.GetPosition();
+            showColsPopUp(event.GetRow(), event.GetCol(),p);
+        }
+    }
+    event.Skip();
+}
+
+
+void gqbJoinsPanel::OnButtonAdd(wxCommandEvent&)
+{
+    this->gModel->AppendJoin( NULL );
+}
+
+
+void gqbJoinsPanel::OnButtonDrop(wxCommandEvent&)
+{
+    if(joinsGrid->GetGridCursorRow()>=0)
+    {
+        gqbQueryObject *updateTbl = gModel->DeleteRow(joinsGrid->GetGridCursorRow());
+        if (updateTbl)
+            controller->getView()->updateTable(updateTbl);
+    }
+    joinsGrid->Refresh();
+}
+
+
+void gqbJoinsPanel::SetGridColsSize()
+{
+    // After sizers determine the width of Grid then calculate the % space for each column about 33% each one
+    int size=(int)((joinsGrid->GetSize().GetWidth() - joinsGrid->GetRowLabelSize())*0.3);
+    joinsGrid->SetColSize(0,size);
+    joinsGrid->SetColSize(1,size);
+    joinsGrid->SetColSize(2,size);
+}
+
+void gqbJoinsPanel::updatedJoinType(gqbQueryJoin *join)
+{
+    controller->getView()->updateJoin(join);
+}
+
+
Index: gqb/module.mk
===================================================================
--- gqb/module.mk	(revision 7506)
+++ gqb/module.mk	(working copy)
@@ -20,6 +20,7 @@
 	$(srcdir)/gqb/gqbGridOrderTable.cpp \
 	$(srcdir)/gqb/gqbGridProjTable.cpp \
 	$(srcdir)/gqb/gqbGridRestTable.cpp \
+        $(srcdir)/gqb/gqbGridJoinTable.cpp \
 	$(srcdir)/gqb/gqbModel.cpp \
 	$(srcdir)/gqb/gqbObject.cpp \
 	$(srcdir)/gqb/gqbObjectCollection.cpp \
Index: gqb/gqbQueryObjs.cpp
===================================================================
--- gqb/gqbQueryObjs.cpp	(revision 7506)
+++ gqb/gqbQueryObjs.cpp	(working copy)
@@ -23,6 +23,8 @@
 #include "gqb/gqbObjectCollection.h"
 #include "gqb/gqbViewPanels.h"
 
+const wxString wxEmptyStr = wxEmptyString;
+
 //
 // Collections of Tables inside a Query, data structured used for query storage & later generation of SQL sentence
 //
@@ -348,6 +350,8 @@
 
 const wxString& gqbQueryJoin::getSourceTable()
 {
+    if (!owner)
+        return wxEmptyStr;
     gqbTable *s=(gqbTable*)&sCol->getOwner();
     return s->getName();
 }
@@ -355,6 +359,8 @@
 
 const wxString& gqbQueryJoin::getDestTable()
 {
+    if (!destination)
+        return wxEmptyStr;
     gqbTable *d=(gqbTable*)&dCol->getOwner();
     return d->getName();
 }
@@ -362,12 +368,16 @@
 
 const wxString& gqbQueryJoin::getSourceCol()
 {
+    if (!sCol)
+        return wxEmptyStr;
     return sCol->getName();
 }
 
 
 const wxString& gqbQueryJoin::getDestCol()
 {
+    if (!dCol)
+        return wxEmptyStr;
     return dCol->getName();
 }
 
Index: gqb/gqbController.cpp
===================================================================
--- gqb/gqbController.cpp	(revision 7506)
+++ gqb/gqbController.cpp	(working copy)
@@ -54,9 +54,10 @@
     view->SetScrollbars( 10, 10, 127, 80 );
     gqbContainer->SplitVertically(browserPanel,view);
 
-    tabs->AddPage(view->getColsGridPanel(), _("Columns"));
-    tabs->AddPage(view->getCriteriaPanel(), _("Criteria"));
-    tabs->AddPage(view->getOrderPanel(), _("Ordering"));
+    tabs->InsertPage(ti_colsGridPanel, view->getColsGridPanel(), _("Columns"));
+    tabs->InsertPage(ti_criteriaPanel, view->getCriteriaPanel(), _("Criteria"));
+    tabs->InsertPage(ti_orderPanel, view->getOrderPanel(), _("Ordering"));
+    tabs->InsertPage(ti_joinsPanel, view->getJoinsPanel(), _("Joins"));
     gqbMainContainer->SplitHorizontally(gqbContainer,tabs);
 
     // Fix Sash resize bug
@@ -536,6 +537,7 @@
     ((gqbGridPanel *)view->getColsGridPanel())->SetGridColsSize();
     ((gqbCriteriaPanel *)view->getCriteriaPanel())->SetGridColsSize();
     ((gqbOrderPanel *)view->getOrderPanel())->SetGridColsSize();
+    ((gqbJoinsPanel *)view->getJoinsPanel())->SetGridColsSize();
 }
 
 
