Index: pgadmin/include/frm/menu.h =================================================================== --- pgadmin/include/frm/menu.h (revision 7397) +++ pgadmin/include/frm/menu.h (working copy) @@ -108,7 +108,12 @@ QUERY_COMPLETE=MNU_MACROS_MANAGE+100, // This is a dummy menu item - MNU_DUMMY=QUERY_COMPLETE+1000 + MNU_DUMMY=QUERY_COMPLETE+1000, + + //Menu Test + MNU_TEST, + MNU_TEST2, + MNU_TABLES_BROWSER }; #endif Index: pgadmin/include/frm/frmQuery.h =================================================================== --- pgadmin/include/frm/frmQuery.h (revision 7397) +++ pgadmin/include/frm/frmQuery.h (working copy) @@ -19,6 +19,8 @@ // wxAUI #include +#include +#include #include #define FRMQUERY_PERPSECTIVE_VER wxT("$Rev$") @@ -33,6 +35,11 @@ #endif #endif + +//GQB headers +#include "gqb/gqbViewController.h" +#include "gqb/gqbModel.h" + class ExplainCanvas; class ctlSQLResult; @@ -68,6 +75,16 @@ wxTimer timer; wxLongLong elapsedQuery, startTimeQuery; + //gqb Added + void OnTest(wxCommandEvent& event); + void OnTest2(wxCommandEvent& event); + void OnTest3(wxNotebookEvent& event); + wxNotebook *sqlNotebook; + gqbModel *model; + gqbController *controller; + bool firstTime; + + // Our connection pgConn *conn; @@ -121,6 +138,7 @@ void OnToggleDatabaseBar(wxCommandEvent& event); void OnToggleToolBar(wxCommandEvent& event); void OnToggleOutputPane(wxCommandEvent& event); + //void OnToggleTablesBrowser(wxCommandEvent& event); void OnAuiUpdate(wxAuiManagerEvent& event); void OnDefaultView(wxCommandEvent& event); @@ -178,7 +196,9 @@ CTL_SQLQUERY=331, CTL_SQLRESULT, CTL_MSGRESULT, - CTL_MSGHISTORY + CTL_MSGHISTORY, + CTL_NTBKCENTER, + CTL_COLSGRID }; /////////////////////////////////////////////////////// Index: pgadmin/include/module.mk =================================================================== --- pgadmin/include/module.mk (revision 7397) +++ pgadmin/include/module.mk (working copy) @@ -30,5 +30,6 @@ include $(srcdir)/include/parser/module.mk include $(srcdir)/include/schema/module.mk include $(srcdir)/include/slony/module.mk +include $(srcdir)/include/gqb/module.mk include $(srcdir)/include/utils/module.mk Index: pgadmin/include/gqb/gqbModel.h =================================================================== --- pgadmin/include/gqb/gqbModel.h (revision 0) +++ pgadmin/include/gqb/gqbModel.h (revision 0) @@ -0,0 +1,41 @@ +#ifndef GQBMODEL_H +#define GQBMODEL_H + +// wxWindows headers +#include + +// GQB headers +#include + +#define MAXRECTANGLES 10 + +class gqbModel : public wxObject +{ + public: + gqbModel(); + ~gqbModel(); + void emptyAll(); + //Tables + void addTable(gqbTable *table); + void deleteTable(gqbQueryObject *table); + gqbIteratorBase* createQueryIterator(); + int tablesCount(); + //Projection Panel + gqbObjsArray* getOrderedColumns(){return &colsPosition;}; + gqbObjsArray* getColumnsParents(){return &colsParents;}; + wxArrayString* getColumnsAlias(){return columnsAlias;}; + //Restrictions Panel + gqbQueryRestriction* addRestriction(); //TODO: delete if not use this function + gqbRestrictions* getRestrictions(){return restrictions;}; + + private: + //query objects [tables] with joins inside + gqbQueryObjs *queryCollection; + //projection Panel + gqbObjsArray colsPosition; //Here store position of the columns at Select projection clause [Select c1,c2,c3...,cn from...] + gqbObjsArray colsParents; //Because above array only store a column object cannot be recovered the object that store it (gqbQueryObject) [remember can be use same table twice on a query]. + wxArrayString *columnsAlias; + //restrictions Panel + gqbRestrictions *restrictions; +}; +#endif Index: pgadmin/include/gqb/gqbSchema.h =================================================================== --- pgadmin/include/gqb/gqbSchema.h (revision 0) +++ pgadmin/include/gqb/gqbSchema.h (revision 0) @@ -0,0 +1,33 @@ +#ifndef GQBSCHEMA_H +#define GQBSCHEMA_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +//GQB headers +#include +#include + +class gqbSchema : public gqbObject +{ + public: + gqbSchema(gqbObject *parent, wxString *name, type_gqbObject type); + void createObjects(gqbBrowser *_tablesBrowser, pgConn *_conn, OID oidVal, wxTreeItemId parentNode, int _indexImage); + + private: + pgConn *conn; + wxString NumToStr(OID value); + void createTables(pgConn *conn, gqbBrowser *tablesBrowser, wxTreeItemId parentNode, OID oidVal, int _indexImage); +}; +#endif Index: pgadmin/include/gqb/gqbUp.xpm =================================================================== --- pgadmin/include/gqb/gqbUp.xpm (revision 0) +++ pgadmin/include/gqb/gqbUp.xpm (revision 0) @@ -0,0 +1,49 @@ +/* XPM */ +const char * gqbUp_xpm[] = { +"13 8 38 1", +" c None", +". c #8BB161", +"+ c #5A9B13", +"@ c #CCDFA3", +"# c #BAD381", +"$ c #A5C55A", +"% c #B6D178", +"& c #BAD383", +"* c #9EC24F", +"= c #96BC3D", +"- c #9BBF43", +"; c #B4CF70", +"> c #BAD483", +", c #9FC251", +"' c #96BD3E", +") c #94BB38", +"! c #92B931", +"~ c #97BC38", +"{ c #B1CD69", +"] c #BAD485", +"^ c #9FC353", +"/ c #97BD40", +"( c #95BB39", +"_ c #92BA33", +": c #90B82C", +"< c #8EB726", +"[ c #94BB2F", +"} c #AFCC64", +"| c #CEE0A7", +"1 c #B2CE71", +"2 c #B0CD6C", +"3 c #AECB67", +"4 c #ADCB62", +"5 c #ABC95E", +"6 c #AAC85A", +"7 c #A9C856", +"8 c #AFCC63", +"9 c #C5DA8D", +" .+. ", +" .+@+. ", +" .+#$%+. ", +" .+&*=-;+. ", +" .+>,')!~{+. ", +".+]^/(_:<[}+.", +"+|#123456789+", +".+++++++++++."}; Index: pgadmin/include/gqb/gqbDatabase.h =================================================================== --- pgadmin/include/gqb/gqbDatabase.h (revision 0) +++ pgadmin/include/gqb/gqbDatabase.h (revision 0) @@ -0,0 +1,39 @@ +#ifndef GQBDATABASE_H +#define GQBDATABASE_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +//GQB headers +#include +#include +#include + +class gqbDatabase : public gqbObject +{ + public: + gqbDatabase(wxString *name, type_gqbObject type); + //TODO: change to private later + void createObjects(gqbBrowser *_tablesBrowser, pgConn *_conn); + + private: + pgConn *conn; + enum typeSchema + { + GQB_CATALOG, + GQB_OTHER + }; + void createSchemas(pgConn *conn, gqbBrowser *tablesBrowser, wxTreeItemId parentNode,typeSchema MetaType, int indexImage); +}; +#endif Index: pgadmin/include/gqb/gqbEvents.h =================================================================== --- pgadmin/include/gqb/gqbEvents.h (revision 0) +++ pgadmin/include/gqb/gqbEvents.h (revision 0) @@ -0,0 +1,16 @@ +#ifndef GQBEVENTS_H +#define GQBEVENTS_H + +enum gqb_Events +{ + GQB_COLSTREE, + GQB_BROWSER = 1000 + +}; + +enum gqb_rMenus +{ + GQB_RMJ_DELETE, + GQB_RMT_DELETE = 2000 +}; +#endif Index: pgadmin/include/gqb/gqbObject.h =================================================================== --- pgadmin/include/gqb/gqbObject.h (revision 0) +++ pgadmin/include/gqb/gqbObject.h (revision 0) @@ -0,0 +1,48 @@ +#ifndef GQBOBJECT_H +#define GQBOBJECT_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +enum type_gqbObject +{ + _gqbDatabase, + _gqbSchema, + _gqbTable, + _gqbColumn, + _gqbQueryObj, + _gqbQuery, + _gqbJoin, + _gqbRestriction +}; + +//Create Array Objects used as base for gqbCollections +class gqbObject : public wxTreeItemData +{ + public: + gqbObject(wxString *name, type_gqbObject type); + virtual ~gqbObject(); + void setName(wxString *name); + const wxString& getName(); + void setOwner(wxTreeItemData *owner); + const wxTreeItemData& getOwner(); + void setType(type_gqbObject name); + const type_gqbObject getType(); + + private: + wxString *Name; + wxTreeItemData *Owner; + type_gqbObject Type; +}; +#endif Index: pgadmin/include/gqb/gqbDownBottom.xpm =================================================================== --- pgadmin/include/gqb/gqbDownBottom.xpm (revision 0) +++ pgadmin/include/gqb/gqbDownBottom.xpm (revision 0) @@ -0,0 +1,46 @@ +/* XPM */ +const char * gqbDownBottom_xpm[] = { +"13 8 35 1", +" c None", +". c #8BB161", +"+ c #5A9B13", +"@ c #CEE0A7", +"# c #BAD381", +"$ c #B2CE71", +"% c #B0CD6C", +"& c #AECB67", +"* c #ADCB62", +"= c #ABC95E", +"- c #AAC85A", +"; c #A9C856", +"> c #AFCC63", +", c #C5DA8D", +"' c #BAD485", +") c #9FC353", +"! c #97BD40", +"~ c #95BB39", +"{ c #92BA33", +"] c #90B82C", +"^ c #8EB726", +"/ c #94BB2F", +"( c #AFCC64", +"_ c #BAD483", +": c #9FC251", +"< c #96BD3E", +"[ c #94BB38", +"} c #92B931", +"| c #97BC38", +"1 c #B1CD69", +"2 c #BAD383", +"3 c #9EC24F", +"4 c #96BC3D", +"5 c #9BBF43", +"6 c #B4CF70", +".+++++++++++.", +"+@#$%&*=-;>,+", +".+')!~{]^/(+.", +" .+_:<[}|1+. ", +" .+23456+. ", +".+++++++++++.", +"+@#$%&*=-;>,+", +".+++++++++++."}; Index: pgadmin/include/gqb/gqbJoinCursor.xpm =================================================================== --- pgadmin/include/gqb/gqbJoinCursor.xpm (revision 0) +++ pgadmin/include/gqb/gqbJoinCursor.xpm (revision 0) @@ -0,0 +1,38 @@ +/* XPM */ +const char * gqbJoinCursor_xpm[] = { +"32 32 3 1", +" c None", +". c #000000", +"+ c #FFFFFF", +". ", +".. ", +".+. ", +".++. ", +".+++. ", +".++++. ", +".++.... ", +".+. ", +".. ... ", +". . ", +" . ", +" ... ", +" ... .++. ", +" . ......++. ", +" . . .++. ", +" ... . ... ", +" .++. . . ", +" .++...... . ", +" .++. . ", +" ... . ", +" . . ", +" . . ", +" . . ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" ", +" "}; Index: pgadmin/include/gqb/gqbGraphSimple.h =================================================================== --- pgadmin/include/gqb/gqbGraphSimple.h (revision 0) +++ pgadmin/include/gqb/gqbGraphSimple.h (revision 0) @@ -0,0 +1,47 @@ +#ifndef GQBGRAPHSIMPLE_H +#define GQBGRAPHSIMPLE_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#include "wx/dcbuffer.h" +//GQB headers +#include +#include + +//Create Array Objects used as base for gqbCollections +class gqbGraphSimple : public gqbGraphBehavior +{ + public: + gqbGraphSimple(); + void drawTable(wxBufferedDC& bdc, wxPoint *origin, gqbQueryObject *queryTable); + void drawTempJoinLine(wxBufferedDC& bdc, wxPoint &origin, wxPoint &end); + void calcAnchorPoint(gqbQueryJoin *join); + void drawJoin(wxBufferedDC& bdc, wxPoint& origin, wxPoint& dest, wxPoint& anchorUsed, bool selected); + void UpdatePosObject(gqbQueryObject *queryTable, int x, int y, int cursorAdjustment); + gqbColumn* getColumnAtPosition(wxPoint *clickPoint, gqbQueryObject *queryTable, int sensibility=17); + bool clickOnJoin(gqbQueryJoin *join, wxPoint &pt, wxPoint &origin, wxPoint &dest); + int getTitleRowHeight(); + private: + wxFont normalFont, TableTitleFont; + wxBrush BackgroundLayer1, BackgroundLayer2, BackgroundTitle, selectedBrush; + int minTableWidth, minTableHeight; + int rowHeight, rowLeftMargin, rowRightMargin, rowTopMargin, lineClickThreshold; + wxPen selectedPen; + wxBitmap imgSelBoxEmpty,imgSelBoxSelected; + bool insideLine(wxPoint &pt, wxPoint &p1, wxPoint &p2, int threshold); + double distanceToLine(wxPoint pt, wxPoint p1, wxPoint p2); + +}; +#endif Index: pgadmin/include/gqb/module.mk =================================================================== --- pgadmin/include/gqb/module.mk (revision 0) +++ pgadmin/include/gqb/module.mk (revision 0) @@ -0,0 +1,37 @@ +####################################################################### +# +# pgAdmin III - PostgreSQL Tools +# $Id: module.mk 6929 2008-01-01 23:54:26Z dpage $ +# Copyright (C) 2002 - 2008, The pgAdmin Development Team +# This software is released under the Artistic Licence +# +# module.mk - pgadmin/include/gqb/ Makefile fragment +# +####################################################################### + +pgadmin3_SOURCES += \ + $(srcdir)/include/gqb/gqbArrayCollection.h \ + $(srcdir)/include/gqb/gqbBrowser.h \ + $(srcdir)/include/gqb/gqbCollection.h \ + $(srcdir)/include/gqb/gqbCollectionBase.h \ + $(srcdir)/include/gqb/gqbColumn.h \ + $(srcdir)/include/gqb/gqbDatabase.h \ + $(srcdir)/include/gqb/gqbEvents.h \ + $(srcdir)/include/gqb/gqbGraphBehaviour.h \ + $(srcdir)/include/gqb/gqbGraphSimple.h \ + $(srcdir)/include/gqb/gqbGridTable.h \ + $(srcdir)/include/gqb/gqbModel.h \ + $(srcdir)/include/gqb/gqbObject.h \ + $(srcdir)/include/gqb/gqbObjectCollection.h \ + $(srcdir)/include/gqb/gqbQueryObjs.h \ + $(srcdir)/include/gqb/gqbSchema.h \ + $(srcdir)/include/gqb/gqbTable.h \ + $(srcdir)/include/gqb/gqbViewController.h \ + $(srcdir)/include/gqb/gqbViewPanels.h \ + $(srcdir)/include/gqb/gqbColNotSel.h \ + $(srcdir)/include/gqb/gqbColSel.h \ + $(srcdir)/include/gqb/gqbRestGridTable.h + +EXTRA_DIST += \ + $(srcdir)/include/gqb/module.mk + Index: pgadmin/include/gqb/gqbJoin.xpm =================================================================== --- pgadmin/include/gqb/gqbJoin.xpm (revision 0) +++ pgadmin/include/gqb/gqbJoin.xpm (revision 0) @@ -0,0 +1,78 @@ +/* XPM */ +const char * gqbJoin_xpm[] = { +"16 12 63 1", +" c None", +". c #9B9B9C", +"+ c #808080", +"@ c #C0C0C2", +"# c #949395", +"$ c #F9F9F9", +"% c #DFDFE1", +"& c #A6A6A6", +"* c #767676", +"= c #DEDEE0", +"- c #DADADD", +"; c #E2E2E2", +"> c #A1A1A2", +", c #B2B2B4", +"' c #707071", +") c #767677", +"! c #757475", +"~ c #D3D3D3", +"{ c #929292", +"] c #F8F8F8", +"^ c #DEDDE0", +"/ c #7A7A7A", +"( c #858586", +"_ c #A6A6A8", +": c #A1A1A3", +"< c #CCCBCF", +"[ c #B2B1B4", +"} c #828282", +"| c #474747", +"1 c #F6F6F6", +"2 c #A0A0A0", +"3 c #CDCDCD", +"4 c #757576", +"5 c #69696A", +"6 c #9B9A9D", +"7 c #D8D8DB", +"8 c #C8C8CB", +"9 c #555556", +"0 c #F0F0F0", +"a c #DCDBDE", +"b c #7C7C7C", +"c c #ABABAB", +"d c #838284", +"e c #A8A7AA", +"f c #A5A5A8", +"g c #C6C6C9", +"h c #5C5C5E", +"i c #EDEDED", +"j c #DBDADD", +"k c #F7F7F7", +"l c #8C8C8E", +"m c #D0CFD3", +"n c #5D5D5F", +"o c #EAEAEA", +"p c #616062", +"q c #D4D4D7", +"r c #E8E8E8", +"s c #DAD9DC", +"t c #CBCBCD", +"u c #B7B7BA", +"v c #B7B7B9", +"w c #C8C8CA", +"x c #D4D3D6", +" ", +" .+@ ", +" #$% ", +" @&*$= ", +" -;> ,')!~{]^ ", +" =$/( _:<[}|1^ ", +" =$234 56 7890a ", +" =]bcdefg hij ", +" =k|lm no- ", +" =1pq nrs ", +" qtu vwx ", +" "}; Index: pgadmin/include/gqb/gqbViewPanels.h =================================================================== --- pgadmin/include/gqb/gqbViewPanels.h (revision 0) +++ pgadmin/include/gqb/gqbViewPanels.h (revision 0) @@ -0,0 +1,152 @@ +#ifndef GQBVIEWPANELS_H +#define GQBVIEWPANELS_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + + +#include +#include "gqb/gqbGridTable.h" +#include "gqb/gqbRestGridTable.h" + +enum gridColsButton{ + buttonUp_ID, + buttonUpTop_ID, + downUp_ID, + downUpBottom_ID, + addButton_ID, + dropButton_ID +}; + + +// +// +// Projection Panel +// +// + +class gqbGridPanel: public wxPanel +{ +DECLARE_EVENT_TABLE() +public: + gqbGridPanel(wxWindow* parent, wxWindowID id, gqbGridTable *gridModel); + ~gqbGridPanel(); + wxBitmapButton *buttonUp, *buttonDown, *buttonUpTop, *buttonDownBottom; + wxBitmap upBitmap, upTopBitmap, downBitmap, downBottomBitmap; + //Events for wxGrid + void OnGridSelectCell( wxGridEvent& ev ); + void OnGridRangeSelected( wxGridRangeSelectEvent& ev ); + void OnButtonUp(wxCommandEvent&); + void OnButtonUpTop(wxCommandEvent&); + void OnButtonDown(wxCommandEvent&); + void OnButtonDownBottom(wxCommandEvent&); +private: + bool allowSelCells; + int selTop,selBottom; //Range Selection of wxGrid, -1 it's value not set. + wxGrid *colsGrid; //Columns Grid used for order of columns in sentence & single row functions + gqbGridTable *gModel; + +}; + +// +// +// Panels reusable components +// +// + +class gqbColsTree : public wxTreeCtrl +{ +public: + 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); +private: + wxTreeItemId rootNode; +}; + + + +enum { + QRAll = 9100, + QRAllMenuAdd, + QRAllMenuRemAll, + QRSubMenuAdd, + QRSubMenuDel, + QRTreeOk, + QRTree, + QRComboBox +}; + +class gqbColsPopUp: public wxMiniFrame +{ + public: + gqbColsPopUp(wxWindow* parent, wxWindowID id, wxString title, wxPoint pos, const wxSize size); + void refreshTree(gqbModel *_model); + void OnPopUpOKClick(wxCommandEvent& event); + void OnPopUpTreeClick(wxTreeEvent& event); + void OnPopUpTreeDoubleClick(wxTreeEvent& event); + void setEditText(wxString text); + wxString getEditText(){return editTree->GetValue();}; + void setUsedCell(wxGrid* grid, int row, int col){usedGrid=grid; _row=row; _col=col;}; + void focus(); + private: + int _row,_col; + wxGrid *usedGrid; + gqbColsTree *colsTree; + wxTextCtrl *editTree; + wxButton *buttonTree; + gqbModel *model; //Not owned shouldn't be deleted at this class + +}; + +// +// +// Criterias Panel +// +// + +class wxRestrictionGrid: public wxGrid +{ +public: + wxRestrictionGrid(wxWindow* parent, wxWindowID id); + void ComboBoxEvent(wxGridEvent& event); + void RevertSel(); +private: + wxGridSelection *m_selTemp; + +}; + +class gqbCriteriaPanel: public wxPanel +{ +DECLARE_EVENT_TABLE() + public: + gqbCriteriaPanel(wxWindow* parent, gqbModel *_model, gqbRestGridTable *gridModel); + void OnCellLeftClick(wxGridEvent& ev); + void refreshTree(gqbModel *_model); + void OnButtonAdd(wxCommandEvent&); + void OnButtonDrop(wxCommandEvent&); + private: + wxBitmapButton *buttonAdd, *buttonDrop; + wxBitmap addBitmap, dropBitmap; + void showColsPopUp(int row, int col, wxPoint pos); + gqbRestGridTable *gModel; + wxGrid *restrictionsGrid; //Columns Grid used for order of columns in sentence & single row functions + gqbModel *model; //Not owned shouldn't be deleted at this class + gqbColsPopUp *colsPopUp; + +}; + +#endif Index: pgadmin/include/gqb/gqbViewController.h =================================================================== --- pgadmin/include/gqb/gqbViewController.h (revision 0) +++ pgadmin/include/gqb/gqbViewController.h (revision 0) @@ -0,0 +1,120 @@ +#ifndef GQBCONTROLLER_H +#define GQBCONTROLLER_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#include "wx/dcbuffer.h" +#include "wx/notebook.h" +#include "wx/splitter.h" + + +#include "gqb/gqbObject.h" +#include "gqb/gqbModel.h" +#include "gqb/gqbQueryObjs.h" +#include "gqb/gqbGraphBehavior.h" +#include +#include +#include +#include "gqb/gqbBrowser.h" + +class gqbView; + +enum pointerMode +{ + pt_normal, + pt_join +}; + +class gqbController: public wxObject +{ + + public: + gqbController(gqbModel *_model, wxWindow *gqbParent, wxNotebook *gridParent, wxSize size); + ~gqbController(); + void addTableToModel(gqbTable *table); + gqbQueryJoin* addJoin(gqbQueryObject *sTable, gqbColumn *sColumn, gqbQueryObject *dTable, gqbColumn *dColumn, type_Join kind); + void removeJoin(gqbQueryJoin *join); + void removeTableFromModel(gqbQueryObject *table, gqbGridTable *gridTable); + void unsetModelSelected(bool queryTable); + void processColumnInModel(gqbQueryObject *table, gqbColumn *column, gqbGridTable *gridTable); + void setPointerMode(pointerMode pm); //Find selected table with their coordinates point + gqbView* getView(){return view;}; + void nullView() {view=NULL;}; + gqbObject* getModelSelected(wxPoint &pt, gqbQueryObject *lastSelected, gqbQueryJoin *lastJoinSelected, bool mark); + wxString generateSQL(); + wxSplitterWindow* getViewContainer(){return gqbContainer;}; + void setSashPosition(int pos){gqbContainer->SetSashPosition(pos,true);}; + gqbBrowser* getTablesBrowser(){return tablesBrowser;}; + void emptyModel(); + gqbQueryRestriction* addRestriction(); + protected: + gqbView *view; //owned by caller application shouldn't be destroy by this class + wxWindow *pparent; //TODO: deberia ser privada no se porque no funciona [la estoy usando?] + gqbModel *model; //owned by caller application shouldn't be destroy by this class + wxSplitterWindow *gqbContainer; //container of canvas & tables browser. + gqbBrowser *tablesBrowser; //tables Browser Tree +}; + +class gqbView: public wxScrolledWindow +{ + + DECLARE_EVENT_TABLE() + + public: +//gqbView(wxWindow *gqbParent, wxSize size); + gqbView(wxWindow *gqbParent, wxNotebook *gridParent, wxSize size, gqbController *controller, gqbModel *model); + ~gqbView(); + void drawAll(wxBufferedDC& bdc); + void setPointerMode(pointerMode pm); +//Events for wxScrolledWindow + void onPaint(wxPaintEvent& event); + void onMotion(wxMouseEvent& event); + void onDoubleClick(wxMouseEvent& event); + void onRightClick(wxMouseEvent& event); + void onErase(wxEraseEvent& event); + void onEraseBackGround(wxEraseEvent& event); + void OnKeyDown(wxKeyEvent& event); + wxPanel* getColsGridPanel(){ return (wxPanel*)projectionPanel; }; + wxPanel* getCriteriaPanel(){ return (wxPanel*)criteriaPanel; }; + bool clickOnJoin (gqbQueryJoin *join, wxPoint &pt, wxPoint &origin, wxPoint &dest); +//Functions for all gqb extra Panels (projection, criteria..) + void emptyPanelsData(); + + private: + gqbController *controller; //owned by caller application shouldn't be destroy by this class + gqbModel *model; //owned by caller application shouldn't be destroy by this class + gqbGraphBehavior *graphBehavior; //This points to the Graph behavior for objects, 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; + gqbGridTable *gridTable; //Data model for the columns grid internals + gqbRestGridTable *restrictionsGridTable; + wxSize canvasSize; + bool changeTOpressed; + gqbQueryObject *collectionSelected, *joinSource, *joinDest, *cTempSelected; //just a point to the selected item on the collection, shouldn't be destroy inside this class + gqbQueryJoin *joinSelected, *jTempSelected; + gqbColumn *joinSCol, *joinDCol; + int pressed, selected, refreshRate; + wxPoint pos, jpos; //Position of the last event of the mouse & the first event of a join event + pointerMode mode; //pointer is used as normally or as in joins by example + wxImage joinCursorImage; + wxCursor joinCursor; + wxMenu *m_rightJoins, *m_rightTables; + void OnMenuJoinDelete(wxCommandEvent& event); + void OnMenuTableDelete(wxCommandEvent& event); + + +}; + +#endif Index: pgadmin/include/gqb/gqbColNotSel.xpm =================================================================== --- pgadmin/include/gqb/gqbColNotSel.xpm (revision 0) +++ pgadmin/include/gqb/gqbColNotSel.xpm (revision 0) @@ -0,0 +1,49 @@ +/* XPM */ +const char * gqbColNotSel_xpm[] = { +"16 16 30 1", +" c None", +". c #9B9B9B", +"+ c #555555", +"@ c #FDFEFE", +"# c #FBFEFE", +"$ c #F9FCFE", +"% c #F7FBFE", +"& c #F4FAFD", +"* c #F2FAFC", +"= c #FCFEFE", +"- c #FAFDFE", +"; c #F7FBFD", +"> c #F5FBFD", +", c #F3FAFC", +"' c #F0F9FC", +") c #F8FCFE", +"! c #F6FBFD", +"~ c #F3FAFD", +"{ c #F2F9FD", +"] c #EFF8FC", +"^ c #F9FDFE", +"/ c #F7FCFD", +"( c #F4FBFD", +"_ c #EDF7FB", +": c #EEF8FC", +"< c #ECF7FB", +"[ c #F6FCFD", +"} c #F2F9FC", +"| c #EDF8FB", +"1 c #EAF7FB", +" ", +" ", +" ", +" ", +".++++++. ", +"+@#$%&*+ ", +"+=-;>,'+ ", +"+-)!~{]+ ", +"+^/(,'_+ ", +"+)>~':<+ ", +"+[&}]|1+ ", +".++++++. ", +" ", +" ", +" ", +" "}; Index: pgadmin/include/gqb/gqbGraphBehavior.h =================================================================== --- pgadmin/include/gqb/gqbGraphBehavior.h (revision 0) +++ pgadmin/include/gqb/gqbGraphBehavior.h (revision 0) @@ -0,0 +1,40 @@ +#ifndef GQBGRAPHBEHAVIOR_H +#define GQBGRAPHBEHAVIOR_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#include "wx/dcbuffer.h" +//GQB headers +#include + +//Interface class for drawing of objects in canvas +class gqbGraphBehavior : public wxObject +{ + public: +//Important: The drawTable function always should store the width & height of the graphic +//representation of the table inside the gqbQueryObject for use of controller. + virtual void drawTable(wxBufferedDC& bdc, wxPoint *origin, gqbQueryObject *queryTable)=0; + virtual void drawTempJoinLine(wxBufferedDC& bdc, wxPoint &origin, wxPoint &end)=0; + virtual void drawJoin(wxBufferedDC& bdc, wxPoint& origin, wxPoint& dest, wxPoint& anchorUsed, bool selected)=0; + virtual void calcAnchorPoint(gqbQueryJoin *join)=0; + virtual void UpdatePosObject(gqbQueryObject *queryTable, int x, int y, int cursorAdjustment)=0; + //TODO find a way to not hard code the 17 default value + virtual gqbColumn* getColumnAtPosition(wxPoint *clickPoint, gqbQueryObject *queryTable, int sensibility=17)=0; + virtual bool clickOnJoin(gqbQueryJoin *join, wxPoint &pt, wxPoint &origin, wxPoint &dest)=0; + virtual int getTitleRowHeight()=0; + private: + +}; +#endif Index: pgadmin/include/gqb/gqbObjectCollection.h =================================================================== --- pgadmin/include/gqb/gqbObjectCollection.h (revision 0) +++ pgadmin/include/gqb/gqbObjectCollection.h (revision 0) @@ -0,0 +1,45 @@ +#ifndef GQBOBJECTCOLLECTION_H +#define GQBOBJECTCOLLECTION_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +//GQB headers +#include +#include +#include + +//Create Collections of gqbObjects +class gqbObjectCollection : public gqbObject +{ + public: + gqbObjectCollection(wxString *name, type_gqbObject type); + virtual ~gqbObjectCollection(); + protected: + void addObject(gqbObject *object); + void removeObject(gqbObject *object); + gqbIteratorBase* createIterator(); + int countObjects(); + gqbObject* getObjectAtIndex(int index); + bool existsObject(gqbObject *object); + int indexObject(gqbObject *object); + void insertObjectAt(gqbObject *object, int index); + int getCount(); + void removeAll(); //Remove all objects from collection without deleting each one. + void deleteAll(); //Remove and Delete all objects from collection. + private: + gqbCollection *objectsCollection; + gqbArrayCollection *implementation; //TODO: DEBO Eliminar esto (que gqbArrayCollection este dentro de la clase) pero como? +}; +#endif Index: pgadmin/include/gqb/gqbQueryObjs.h =================================================================== --- pgadmin/include/gqb/gqbQueryObjs.h (revision 0) +++ pgadmin/include/gqb/gqbQueryObjs.h (revision 0) @@ -0,0 +1,150 @@ +#ifndef GQBQUERYOBJS_H +#define GQBQUERYOBJS_H + +// wxWindows headers +#include +#include +#include "wx/hyperlink.h" + +#include +#include +#include + +#define MAXRECTANGLES 10 + +class gqbQueryObject; +class gqbQueryJoin; + +//TODO: Add all kinds of joins +enum type_Join +{ + _equally, + _lesser, + _greater +}; + +//Collection of main Query Objects [Tables] +class gqbQueryObjs : public gqbObjectCollection +{ + public: + gqbQueryObjs(wxString *name); //No destructor, the base destructor destroy collection the unique dynamic object in this class + void addTable(gqbQueryObject *mtable); //Uses alias to only allow operations I want to do it. + void removeTable(gqbQueryObject *mtable); + gqbIteratorBase* createQueryIterator(); + int tablesCount(); + void removeAllQueryObjs(); + private: + +}; + +//Collection of main Table Objects [Columns] have joins too but in a new variable +class gqbQueryObject : public gqbObjectCollection +{ + public: + gqbQueryObject(gqbTable *table); + ~gqbQueryObject(); + gqbTable *parent; + wxPoint position; + void setSelected(bool value); + bool getSelected(); + void setWidth(int value); + int getWidth(); + void setHeight(int value); + int getHeight(); + void removeColumn(gqbColumn *column); //Used only as synonym for gqbObjectCollection removeObject + void addColumn(gqbColumn *column); //Used only as synonym for gqbObjectCollection addObject + int getColumnIndex(gqbColumn *column); + bool existsColumn(gqbColumn *column); + gqbIteratorBase* createQueryTableIterator(); + gqbIteratorBase* createJoinsIterator(); + gqbIteratorBase* createRegJoinsIterator(); + gqbQueryJoin* addJoin(gqbQueryObject *owner, gqbQueryObject *observable, gqbColumn *source, gqbColumn *destination, type_Join kind); + void removeJoin(gqbQueryJoin *join, bool unRegister); + void registerJoin(gqbQueryJoin *join); + void unregisterJoin(gqbQueryJoin *join, bool removeIt); + bool getHaveJoins(); + bool getHaveRegJoins(); + void setAlias(wxString name){alias=name;}; + wxString getAlias(){return alias;}; + private: + bool selected; + wxString alias; + int width; + int height; + bool haveJoins, haveRegisteredJoins; + gqbCollection *joinsCollection, *registeredCollection; + //TODO: DEBO Eliminar esto (que gqbArrayCollection este dentro de la clase) pero como? + gqbArrayCollection *implementationj, *implementationr ; + +}; + +//A Join Object +class gqbQueryJoin : public gqbObject +{ + public: + gqbQueryJoin(gqbQueryObject *_owner, gqbQueryObject *_destination, gqbColumn *sourceCol, gqbColumn *destCol, type_Join joinKind); + void setKindofJoin(type_Join join); + type_Join getKindofJoin(); + gqbQueryObject* getSourceQTable(); + gqbQueryObject* getDestQTable(); + gqbColumn* getDCol(); + gqbColumn* getSCol(); + const wxString& getSourceTable(); + const wxString& getDestTable(); + const wxString& getSourceCol(); + const wxString& getDestCol(); + void setSourceAnchor(wxPoint pt); + void setDestAnchor(wxPoint pt); + wxPoint& getSourceAnchor(); + wxPoint& getDestAnchor(); + void setSelected(bool value); + bool getSelected(); + void setAnchorsUsed(wxPoint pt); + wxPoint& getAnchorsUsed(); + private: + bool selected; + type_Join kindofJoin; + gqbColumn *sCol, *dCol; + gqbQueryObject *owner, *destination; + wxPoint sAnchor, dAnchor; //The source/destination anchor points of the join (for same join) + wxPoint anchorsUsed; +}; + + +//A Restriction Object +class gqbQueryRestriction : public gqbObject{ +public: + gqbQueryRestriction(); + wxString& getLeft(){return leftPart;}; + wxString& getRestriction(){return restriction;}; + wxString& getValue_s(){return value_s;}; + wxString& getConnector(){return connector;}; + void setLeft(const wxString& value){leftPart=value;}; + void setRestriction(const wxString& value){restriction=value;}; + void setValue_s(const wxString& value){value_s=value;}; + void setConnector(const wxString& value){connector=value;}; +private: + wxString leftPart; + wxString restriction; + wxString value_s; + wxString connector; +}; + + +//Collection of restrictions for a where clause +class gqbRestrictions : public gqbObjectCollection{ +public: + gqbRestrictions(); + ~gqbRestrictions(); + void addRestriction(gqbQueryRestriction *r); //Uses alias to only allow operations I want to do it. + void removeRestriction(gqbQueryRestriction *r); + void deleteAllRestrictions(); + gqbIteratorBase* createRestrictionsIterator(); + void addRestrictionAt(gqbQueryRestriction *r, int index); + int restrictionsCount(); + gqbQueryRestriction* getRestrictionAt(int index); + +}; + +#endif + Index: pgadmin/include/gqb/gqbBrowser.h =================================================================== --- pgadmin/include/gqb/gqbBrowser.h (revision 0) +++ pgadmin/include/gqb/gqbBrowser.h (revision 0) @@ -0,0 +1,37 @@ +#ifndef GQBBROWSER_H +#define GQBBROWSER_H + +// wxWindows headers +#include +//#include + +typedef unsigned long OID; + +class gqbController; + +class gqbBrowser : public wxTreeCtrl +{ + public: + gqbBrowser(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, gqbController *_controller); + ~gqbBrowser(); + wxTreeItemId& createRoot(wxString &Name); + wxTreeItemId& getCatalogRootNode(){return catalogsNode;} + wxTreeItemId& getTablesRootNode(){return schemasNode;} + void refreshTables(pgConn *connection); + + private: + enum typeSchema //TODO: DELETE from here should be locate at gqbDatabase + { + GQB_CATALOG, + GQB_OTHER + }; + + wxTreeItemId rootNode,catalogsNode,schemasNode; + void OnItemActivated(wxTreeEvent& event); + wxString NumToStr(OID value); + gqbController *controller; //Allow access to controller functions like add table to model + wxImageList* imageList; + + DECLARE_EVENT_TABLE() +}; +#endif Index: pgadmin/include/gqb/gqbDown.xpm =================================================================== --- pgadmin/include/gqb/gqbDown.xpm (revision 0) +++ pgadmin/include/gqb/gqbDown.xpm (revision 0) @@ -0,0 +1,49 @@ +/* XPM */ +const char * gqbDown_xpm[] = { +"13 8 38 1", +" c None", +". c #8BB161", +"+ c #5A9B13", +"@ c #CEE0A7", +"# c #BAD381", +"$ c #B2CE71", +"% c #B0CD6C", +"& c #AECB67", +"* c #ADCB62", +"= c #ABC95E", +"- c #AAC85A", +"; c #A9C856", +"> c #AFCC63", +", c #C5DA8D", +"' c #BAD485", +") c #9FC353", +"! c #97BD40", +"~ c #95BB39", +"{ c #92BA33", +"] c #90B82C", +"^ c #8EB726", +"/ c #94BB2F", +"( c #AFCC64", +"_ c #BAD483", +": c #9FC251", +"< c #96BD3E", +"[ c #94BB38", +"} c #92B931", +"| c #97BC38", +"1 c #B1CD69", +"2 c #BAD383", +"3 c #9EC24F", +"4 c #96BC3D", +"5 c #9BBF43", +"6 c #B4CF70", +"7 c #A5C55A", +"8 c #B6D178", +"9 c #CCDFA3", +".+++++++++++.", +"+@#$%&*=-;>,+", +".+')!~{]^/(+.", +" .+_:<[}|1+. ", +" .+23456+. ", +" .+#78+. ", +" .+9+. ", +" .+. "}; Index: pgadmin/include/gqb/gqbUpTop.xpm =================================================================== --- pgadmin/include/gqb/gqbUpTop.xpm (revision 0) +++ pgadmin/include/gqb/gqbUpTop.xpm (revision 0) @@ -0,0 +1,46 @@ +/* XPM */ +const char * gqbUpTop_xpm[] = { +"13 8 35 1", +" c None", +". c #8BB161", +"+ c #5A9B13", +"@ c #CEE0A7", +"# c #BAD381", +"$ c #B2CE71", +"% c #B0CD6C", +"& c #AECB67", +"* c #ADCB62", +"= c #ABC95E", +"- c #AAC85A", +"; c #A9C856", +"> c #AFCC63", +", c #C5DA8D", +"' c #BAD383", +") c #9EC24F", +"! c #96BC3D", +"~ c #9BBF43", +"{ c #B4CF70", +"] c #BAD483", +"^ c #9FC251", +"/ c #96BD3E", +"( c #94BB38", +"_ c #92B931", +": c #97BC38", +"< c #B1CD69", +"[ c #BAD485", +"} c #9FC353", +"| c #97BD40", +"1 c #95BB39", +"2 c #92BA33", +"3 c #90B82C", +"4 c #8EB726", +"5 c #94BB2F", +"6 c #AFCC64", +".+++++++++++.", +"+@#$%&*=-;>,+", +".+++++++++++.", +" ..+')!~{+.. ", +" .+]^/(_:<+. ", +".+[}|123456+.", +"+@#$%&*=-;>,+", +".+++++++++++."}; Index: pgadmin/include/gqb/gqbCollectionBase.h =================================================================== --- pgadmin/include/gqb/gqbCollectionBase.h (revision 0) +++ pgadmin/include/gqb/gqbCollectionBase.h (revision 0) @@ -0,0 +1,50 @@ +#ifndef GQBCOLLECTIONFACTORY_H +#define GQBCOLLECTIONFACTORY_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +//GQB headers +#include + +//This class it's like an interface (but with not all advantages of this at runtime) +//If in a future I just don't want to use an array, simple implement this abstract class again +//with the new data structure. + +class gqbIteratorBase : wxObject +{ + public: + gqbIteratorBase() {}; + virtual gqbObject* Next() = 0; + virtual bool HasNext() = 0; + virtual void ResetIterator() = 0; +}; +// OR probably let to this class to +class gqbCollectionBase : wxObject //TODO: Change to the class because probably it's not adapted to the actual use of this class +{ + public: + gqbCollectionBase() {}; + virtual ~gqbCollectionBase() {}; + virtual void addItem(gqbObject *item) = 0; + virtual void removeItem(gqbObject *item) = 0; + virtual gqbObject* getItemAt(int index) = 0; + virtual gqbIteratorBase* createIterator() = 0; + virtual int count() = 0; + virtual bool existsObject(gqbObject *item) = 0; + virtual int getIndex(gqbObject *item) = 0; + virtual void insertAtIndex(gqbObject *item, int index) = 0; + virtual void deleteAll()=0; + virtual void removeAll()=0; //remove all items from collection without deleting. +}; +#endif Index: pgadmin/include/gqb/gqbGenerateSQL.xpm =================================================================== --- pgadmin/include/gqb/gqbGenerateSQL.xpm (revision 0) +++ pgadmin/include/gqb/gqbGenerateSQL.xpm (revision 0) @@ -0,0 +1,117 @@ +/* XPM */ +const char * gqbGenerateSQL_xpm[] = { +"16 12 102 2", +" c None", +". c #666565", +"+ c #414243", +"@ c #545455", +"# c #696766", +"$ c #616262", +"% c #79858E", +"& c #6888A2", +"* c #577FA0", +"= c #5C81A0", +"- c #748CA0", +"; c #717579", +"> c #959494", +", c #686766", +"' c #7B92A4", +") c #40729B", +"! c #2E638E", +"~ c #316590", +"{ c #2F6490", +"] c #5B85A7", +"^ c #7B8288", +"/ c #686868", +"( c #7C8C98", +"_ c #346993", +": c #326691", +"< c #2F648F", +"[ c #336791", +"} c #2C618D", +"| c #5882A4", +"1 c #838486", +"2 c #5B5A59", +"3 c #6D92B1", +"4 c #6A90AF", +"5 c #7C9DB8", +"6 c #3C6D95", +"7 c #7598B5", +"8 c #7B9DB8", +"9 c #43739A", +"0 c #678EAD", +"a c #386B95", +"b c #798894", +"c c #7D7D7D", +"d c #5D5D5E", +"e c #5382A8", +"f c #C2D2DE", +"g c #94B0C6", +"h c #6F94B2", +"i c #9EB7CB", +"j c #89A7BF", +"k c #94B0C5", +"l c #AFC4D4", +"m c #356993", +"n c #768FA5", +"o c #2A2A2A", +"p c #606161", +"q c #5482A8", +"r c #C7D6E1", +"s c #87A5BE", +"t c #A4BBCE", +"u c #96B1C6", +"v c #86A5BE", +"w c #C1D1DE", +"x c #638CAC", +"y c #7993A7", +"z c #2B2A2B", +"A c #61605F", +"B c #7196B4", +"C c #5C86A7", +"D c #386A93", +"E c #6089A9", +"F c #9FB8CC", +"G c #45749B", +"H c #678FAE", +"I c #82909C", +"J c #7E7E7E", +"K c #6B6B6A", +"L c #8998A4", +"M c #30658F", +"N c #306590", +"O c #346891", +"P c #356892", +"Q c #2C628D", +"R c #5782A4", +"S c #8E9091", +"T c #727170", +"U c #889EB1", +"V c #3F7099", +"W c #2E638F", +"X c #5E87A9", +"Y c #8E969B", +"Z c #6F6F6F", +"` c #8E9AA3", +" . c #7292AC", +".. c #5C83A4", +"+. c #6187A6", +"@. c #829BAF", +"#. c #868B8F", +"$. c #9E9E9E", +"%. c #777675", +"&. c #525354", +"*. c #656565", +"=. c #7D7B7A", +" . + @ # ", +" $ % & * = - ; > ", +" , ' ) ! ~ ~ { ] ^ ", +" / ( _ ! : < ! [ } | 1 ", +" 2 3 4 5 6 7 8 9 0 a b c ", +" d e f g h i j k l m n o ", +" p q h r s t u v w x y z ", +" A B C 0 D E F G 4 H I J ", +" K L m M [ N O P Q R S ", +" T U V ! ~ ~ W X Y ", +" Z ` ...+.@.#.$. ", +" %.&.*.=. "}; Index: pgadmin/include/gqb/gqbTable.h =================================================================== --- pgadmin/include/gqb/gqbTable.h (revision 0) +++ pgadmin/include/gqb/gqbTable.h (revision 0) @@ -0,0 +1,40 @@ +#ifndef GQBTABLE_H +#define GQBTABLE_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +//GQB headers +#include +#include +#include +class gqbColumn; + +//Create Array Objects used as base for gqbCollections +class gqbTable : public gqbObjectCollection +{ + public: + gqbTable(gqbObject *parent, wxString *name, type_gqbObject type); + void createObjects(gqbBrowser *_tablesBrowser, pgConn *_conn, OID oidVal, wxTreeItemId parentNode); + gqbIteratorBase* createColumnsIterator(); + int countCols(); + gqbColumn* getColumnAtIndex(int index); + int indexColumn(gqbColumn *col); + private: + wxString NumToStr(OID value); + void addColumn(gqbColumn *column); //Used only as synonym for gqbObjectCollection addObject + void createColumns(pgConn *conn, gqbBrowser *tablesBrowser, wxTreeItemId parentNode, OID oidVal); + +}; +#endif Index: pgadmin/include/gqb/gqbArrayCollection.h =================================================================== --- pgadmin/include/gqb/gqbArrayCollection.h (revision 0) +++ pgadmin/include/gqb/gqbArrayCollection.h (revision 0) @@ -0,0 +1,51 @@ +#ifndef GQBARRAYCOLLECTION_H +#define GQBARRAYCOLLECTION_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" +#include "gqb/gqbCollectionBase.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +WX_DEFINE_ARRAY_PTR(gqbObject *, gqbObjsArray); + +class gqbArrayIterator : public gqbIteratorBase +{ + public: + gqbArrayIterator(gqbObjsArray *gqbPtrsArray); + gqbObject* Next(); + bool HasNext(); + void ResetIterator(); + private: + int position; + gqbObjsArray *internalArray; +}; + +//Create Array Objects used as base for gqbCollections +class gqbArrayCollection : public gqbCollectionBase +{ + public: + ~gqbArrayCollection(); + void addItem(gqbObject *item); + void removeItem(gqbObject *item); + gqbIteratorBase* createIterator(); + gqbObject* getItemAt(int index); + int count(); + bool existsObject(gqbObject *item); + int getIndex(gqbObject *item); + void insertAtIndex(gqbObject *item, int index); + void deleteAll(); + void removeAll(); + private: + gqbObjsArray gqbArray; +}; +#endif Index: pgadmin/include/gqb/gqbCollection.h =================================================================== --- pgadmin/include/gqb/gqbCollection.h (revision 0) +++ pgadmin/include/gqb/gqbCollection.h (revision 0) @@ -0,0 +1,39 @@ +#ifndef GQBCOLLECTION_H +#define GQBCOLLECTION_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#include "gqb/gqbObject.h" +#include "gqb/gqbCollectionBase.h" + +class gqbCollection : public wxObject +{ + public: + gqbCollection(gqbCollectionBase *collectionBase); + virtual ~gqbCollection(); + void addItem(gqbObject *item); + void removeItem(gqbObject *item); + void deleteAll(); + void removeAll(); + int count(); + bool existsObject(gqbObject *item); + int getIndex(gqbObject *item); + gqbObject* getItemAt(int index); + void insertAtIndex(gqbObject *item, int index); + gqbIteratorBase* createIterator(); + private: + gqbCollectionBase *collection; +}; +#endif Index: pgadmin/include/gqb/gqbRestGridTable.h =================================================================== --- pgadmin/include/gqb/gqbRestGridTable.h (revision 0) +++ pgadmin/include/gqb/gqbRestGridTable.h (revision 0) @@ -0,0 +1,120 @@ +#ifndef GQBRESTGRIDTABLE_H +#define GQBRESTGRIDTABLE_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#include + +//GQB headers +#include "gqb/gqbModel.h" +#include "gqb/gqbArrayCollection.h" + + + +#include "wx/laywin.h" + + +class gqbRestGridTable : public wxGridTableBase +{ + public: + gqbRestGridTable(gqbRestrictions *_restrictions); + ~gqbRestGridTable(); + int GetNumberRows(); + int GetNumberCols(); + bool IsEmptyCell( int row, int col ); + wxString GetValue( int row, int col ); + wxString GetColLabelValue( int col); + void SetValue( int row, int col, const wxString& value ); + void AppendItem(gqbQueryRestriction *item); + void emptyTableData(); + bool DeleteRows(size_t pos, size_t numRows); +private: + gqbRestrictions *restrictions; +}; + + +// +// Cell rendering utilities classes +// + +class wxGridCellComboBoxRenderer : public wxGridCellStringRenderer +{ +public: + wxGridCellComboBoxRenderer(wxLayoutAlignment border = wxLAYOUT_NONE) : + m_border(border) {} + virtual void Draw(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + const wxRect& rect, + int row, int col, + bool isSelected); + virtual wxGridCellRenderer *Clone() const + { return new wxGridCellComboBoxRenderer; } +private: + wxLayoutAlignment m_border; +}; + +class wxGridCellButtonRenderer : public wxGridCellStringRenderer +{ +public: + wxGridCellButtonRenderer(wxLayoutAlignment border = wxLAYOUT_NONE) : + m_border(border) {} + virtual void Draw(wxGrid& grid, + wxGridCellAttr& attr, + wxDC& dc, + const wxRect& rect, + int row, int col, + bool isSelected); + virtual wxGridCellRenderer *Clone() const + { return new wxGridCellComboBoxRenderer; } +private: + wxLayoutAlignment m_border; +}; + + +//Shows a wxGridCellChoiceEditor of cell's wide +class dxGridCellSizedChoiceEditor : public wxGridCellChoiceEditor +{ +public: + dxGridCellSizedChoiceEditor(const wxArrayString& choices, + bool allowOthers = false); + dxGridCellSizedChoiceEditor(size_t count = 0, + const wxString choices[] = NULL, + bool allowOthers = false); + + ~dxGridCellSizedChoiceEditor() {} + + virtual wxGridCellEditor* Clone() const; + virtual void Show(bool show, wxGridCellAttr *attr = (wxGridCellAttr +*)NULL); + +protected: + int m_maxWide; + + DECLARE_NO_COPY_CLASS(dxGridCellSizedChoiceEditor) + +}; + + + +//TODO: don't use gqbObjsArray, use a new one in the model because violating MVC Pattern + +//TODO: this is not needed the one in gqbArrayCollections works her ????? +//WX_DEFINE_ARRAY_PTR(gqbObject *, gqbObjsArray); this is not + +//Create the Data Model that will be used by wxGrid Component + +#endif + Index: pgadmin/include/gqb/gqbGridTable.h =================================================================== --- pgadmin/include/gqb/gqbGridTable.h (revision 0) +++ pgadmin/include/gqb/gqbGridTable.h (revision 0) @@ -0,0 +1,58 @@ +#ifndef GQBGRIDTABLE_H +#define GQBGRIDTABLE_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#include + +//GQB headers +#include "gqb/gqbModel.h" +#include "gqb/gqbArrayCollection.h" + + + +//TODO: don't use gqbObjsArray, use a new one in the model because violating MVC Pattern + +//TODO: this is not needed the one in gqbArrayCollections works her ????? +//WX_DEFINE_ARRAY_PTR(gqbObject *, gqbObjsArray); this is not + +//Create the Data Model that will be used by wxGrid Component +class gqbGridTable : public wxGridTableBase +{ + public: + gqbGridTable(gqbObjsArray *position, gqbObjsArray *parent, wxArrayString *alias); //gqbModel *_model, wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name); + virtual ~gqbGridTable(); + int GetNumberRows(); + int GetNumberCols(); + bool IsEmptyCell( int row, int col ); + wxString GetValue( int row, int col ); + void SetValue( int row, int col, const wxString& value ); + void* GetValueAsCustom( int row, int col, const wxString& typeName ); + void SetValueAsCustom( int row, int col, const wxString& typeName, void* value ); + wxString GetColLabelValue( int col); + //wxString GetTypeName( int row, int col ); + bool removeRow(gqbObject *itemTable, gqbObject *itemColumn); + void removeAllRows(gqbObject *itemTable); + void changesPositions(int spos, int dpos); + void changesRangeOnePos(int topPos, int bottomPos, int newTop); + void AppendItem(int col, gqbObject *item); + void emptyTableData(); + private: + gqbObjsArray *colsPosition; //Here store position of the columns at Select projection clause [Select c1,c2,c3...,cn from...] + gqbObjsArray *colsParents; //Because above array only store a column object cannot be recovered the object that store it (gqbQueryObject) [remember can be use same table twice on a query]. + wxArrayString *columnsAlias; +}; +#endif + Index: pgadmin/include/gqb/gqbColumn.h =================================================================== --- pgadmin/include/gqb/gqbColumn.h (revision 0) +++ pgadmin/include/gqb/gqbColumn.h (revision 0) @@ -0,0 +1,30 @@ +#ifndef GQBCOLUMN_H +#define GQBCOLUMN_H + +#include "pgAdmin3.h" + +// wxWindows headers +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +//GQB headers +#include +#include + +//Create Array Objects used as base for gqbCollections +class gqbColumn : public gqbObject +{ + public: + gqbColumn(gqbObject *parent, wxString *name, type_gqbObject type); + private: + +}; +#endif Index: pgadmin/include/gqb/gqbColSel.xpm =================================================================== --- pgadmin/include/gqb/gqbColSel.xpm (revision 0) +++ pgadmin/include/gqb/gqbColSel.xpm (revision 0) @@ -0,0 +1,63 @@ +/* XPM */ +const char * gqbColSel_xpm[] = { +"16 16 44 1", +" c None", +". c #9B9B9B", +"+ c #555555", +"@ c #FDFEFE", +"# c #FBFEFE", +"$ c #F9FCFE", +"% c #F7FBFE", +"& c #F1F6F9", +"* c #ECF6FA", +"= c #575757", +"- c #FCFEFE", +"; c #FAFDFE", +"> c #F7FBFD", +", c #F1F9FC", +"' c #DEB2B4", +") c #D8A6AC", +"! c #5E5B5C", +"~ c #F9FBFC", +"{ c #EDD1D3", +"] c #EDE7E9", +"^ c #E2CCCD", +"/ c #CD6163", +"( c #D19196", +"_ c #605F60", +": c #F3E6E6", +"< c #D67072", +"[ c #D68587", +"} c #D1787B", +"| c #CB7579", +"1 c #D6D7DD", +"2 c #6A7072", +"3 c #F5F8F9", +"4 c #DDA6A8", +"5 c #CD4E50", +"6 c #CA6265", +"7 c #D6C3C9", +"8 c #E2F1F7", +"9 c #656A6C", +"0 c #F2FAFC", +"a c #E9E6EB", +"b c #D2959A", +"c c #D5AFB4", +"d c #E6F1F5", +"e c #EAF7FB", +" ", +" ", +" ", +" ", +".++++++. ", +"+@#$%&*= ", +"+-;>,')! ", +"+~{]^/(_ ", +"+:<[}|12 ", +"+3456789 ", +"+0abcde+ ", +".++++++. ", +" ", +" ", +" ", +" "}; Index: pgadmin/frm/frmQuery.cpp =================================================================== --- pgadmin/frm/frmQuery.cpp (revision 7397) +++ pgadmin/frm/frmQuery.cpp (working copy) @@ -16,10 +16,16 @@ #include #include #include +#include +#include +#include // wxAUI #include + +//#include ONLY TO DEBUG MEMORY LEAKS + // App headers #include "frm/frmMain.h" #include "frm/frmQuery.h" @@ -32,6 +38,7 @@ #include "schema/pgDatabase.h" #include "schema/pgTable.h" #include "schema/pgView.h" +#include "schema/pgServer.h" #include "dlg/dlgSelectConnection.h" #include "dlg/dlgAddFavourite.h" #include "dlg/dlgManageFavourites.h" @@ -61,11 +68,22 @@ #include "images/query_explain.xpm" #include "images/query_cancel.xpm" #include "images/help.xpm" +#include "gqb/gqbJoin.xpm" +#include "gqb/gqbGenerateSQL.xpm" #define CTRLID_CONNECTION 4200 #define CTRLID_DATABASELABEL 4201 +//GQB headers +#include "gqb/gqbViewController.h" +#include "gqb/gqbModel.h" +#include "gqb/gqbViewPanels.h" + + + + + BEGIN_EVENT_TABLE(frmQuery, pgFrame) EVT_ERASE_BACKGROUND( frmQuery::OnEraseBackground) EVT_SIZE( frmQuery::OnSize) @@ -122,8 +140,14 @@ // These fire when the queries complete EVT_MENU(QUERY_COMPLETE, frmQuery::OnQueryComplete) + + EVT_MENU(MNU_TEST, frmQuery::OnTest) + //EVT_MENU(MNU_TEST2, frmQuery::OnTest2) + EVT_NOTEBOOK_PAGE_CHANGED(CTL_NTBKCENTER, frmQuery::OnTest3) END_EVENT_TABLE() +// EVT_MENU(MNU_TABLES_BROWSER, frmQuery::OnToggleTablesBrowser) + frmQuery::frmQuery(frmMain *form, const wxString& _title, pgConn *_conn, const wxString& query, const wxString& file) : pgFrame(NULL, _title), timer(this) @@ -220,6 +244,7 @@ viewMenu->Append(MNU_OUTPUTPANE, _("&Output pane\tCtrl-Alt-O"), _("Show or hide the output pane."), wxITEM_CHECK); viewMenu->Append(MNU_SCRATCHPAD, _("S&cratch pad\tCtrl-Alt-S"), _("Show or hide the scratch pad."), wxITEM_CHECK); viewMenu->Append(MNU_TOOLBAR, _("&Tool bar\tCtrl-Alt-T"), _("Show or hide the tool bar."), wxITEM_CHECK); + //viewMenu->Append(MNU_TABLES_BROWSER, _("Tables &Browser\tCtrl-Alt-N"), _("Show or hide the tables browser pad."), wxITEM_CHECK); viewMenu->AppendSeparator(); viewMenu->Append(MNU_SHOWINDENTGUIDES, _("&Indent guides"), _("Enable or disable display of indent guides"), wxITEM_CHECK); viewMenu->Append(MNU_SHOWLINEENDS, _("&Line ends"), _("Enable or disable display of line ends"), wxITEM_CHECK); @@ -233,6 +258,9 @@ wxMenu *helpMenu=new wxMenu(); helpMenu->Append(MNU_CONTENTS, _("&Help"), _("Open the helpfile.")); helpMenu->Append(MNU_HELP, _("&SQL Help\tF1"), _("Display help on SQL commands.")); + helpMenu->Append(MNU_TEST, _("&Create SQL from GQB"), _("Create SQL sentences from GQB Model")); + //helpMenu->Append(MNU_TEST2, _("&Change Pointer Mode"), _("Change between Columns selections & Joins Creations")); + menuBar->Append(helpMenu, _("&Help")); @@ -294,6 +322,8 @@ toolBar->AddSeparator(); toolBar->AddTool(MNU_HELP, _("Help"), wxBitmap(help_xpm), _("Display help on SQL commands."), wxITEM_NORMAL); + toolBar->AddTool(MNU_TEST, _("vsqlExecute"), wxBitmap(gqbGenerateSQL_xpm), _("Create Query From Graphical Query Builder Model"), wxITEM_NORMAL); + //toolBar->AddTool(MNU_TEST2, _("vsqlExecute"), wxBitmap(gqbJoin_xpm), _("Change between Columns Selection and Joins Creation"), wxITEM_CHECK); toolBar->Realize(); // Add the database selection bar @@ -301,57 +331,113 @@ cbConnection->Append(conn->GetName(), (void*)conn); cbConnection->Append(_(""), (void*)0); + + //Create SQL editor notebook + sqlNotebook = new wxNotebook(this, CTL_NTBKCENTER, wxDefaultPosition, wxDefaultSize); + //this->Connect(CTL_NTBKCENTER, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, (wxObjectEventFunction) (wxEventFunction) (wxNotebookEventFunction) &frmQuery::OnTest3); + // Query box - sqlQuery = new ctlSQLBox(this, CTL_SQLQUERY, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxSIMPLE_BORDER | wxTE_RICH2); + sqlQuery = new ctlSQLBox(sqlNotebook, CTL_SQLQUERY, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxSIMPLE_BORDER | wxTE_RICH2); sqlQuery->SetDatabase(conn); sqlQuery->SetMarginWidth(1, 16); SetEOLModeDisplay(sqlQuery->GetEOLMode()); - // Results pane - outputPane = new wxNotebook(this, -1, wxDefaultPosition, wxSize(500, 300)); + + + + + + // Results pane + //TODO change number 9999 by a correct one & should use static event instead? + outputPane = new wxNotebook(this, 9999, wxDefaultPosition, wxSize(500, 300)); sqlResult = new ctlSQLResult(outputPane, conn, CTL_SQLRESULT, wxDefaultPosition, wxDefaultSize); explainCanvas = new ExplainCanvas(outputPane); msgResult = new wxTextCtrl(outputPane, CTL_MSGRESULT, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxTE_DONTWRAP); msgResult->SetFont(settings->GetSQLFont()); msgHistory = new wxTextCtrl(outputPane, CTL_MSGHISTORY, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxTE_DONTWRAP); msgHistory->SetFont(settings->GetSQLFont()); + + //Graphical Canvas [Canvas Test #1] + //initialize values + model=new gqbModel(); + controller = new gqbController(model,sqlNotebook, outputPane, wxSize(1500,600)); + firstTime=true; //inform to GQB that the tree of table haven't filled. + + //Setup SQL editor notebook + sqlNotebook->AddPage(sqlQuery, _("SQL Editor")); // NBP_SQLEDTR + //gqbView *view = controller->getView(); + sqlNotebook->AddPage(controller->getViewContainer(), _("Graphical Query Builder")); // NBP_SQLEDTR + sqlNotebook->SetSelection(0); + + + + + outputPane->AddPage(sqlResult, _("Data Output")); outputPane->AddPage(explainCanvas, _("Explain")); outputPane->AddPage(msgResult, _("Messages")); outputPane->AddPage(msgHistory, _("History")); + + /*TEST sizer*/ + + outputPane->AddPage(controller->getView()->getColsGridPanel(), _("Selected Columns")); + //disable because don't works on wxmsw outputPane->GetPage(4)->Hide(); + + outputPane->AddPage(controller->getView()->getCriteriaPanel(), _("Columns Criteria")); + + /*outputPane->AddPage(controller->getView()->getCriteriaPanel(), _("Columns Criteria")); + //diable because don't works on wxmsw outputPane->GetPage(5)->Hide(); + outputPane->SetSelection(0); + */ + + + /*END TEST sizer*/ + + + //outputPane->AddPage(controller->getView()->getColsGrid(), _("Selected Columns")); sqlQuery->Connect(wxID_ANY, wxEVT_SET_FOCUS,wxFocusEventHandler(frmQuery::OnFocus)); sqlResult->Connect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); msgResult->Connect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); msgHistory->Connect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); - // Finally, the scratchpad + // Now, the scratchpad scratchPad = new wxTextCtrl(this, -1, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE | wxHSCROLL); + + + + // Kickstart wxAUI manager.AddPane(toolBar, wxAuiPaneInfo().Name(wxT("toolBar")).Caption(_("Tool bar")).ToolbarPane().Top().LeftDockable(false).RightDockable(false)); manager.AddPane(cbConnection, wxAuiPaneInfo().Name(wxT("databaseBar")).Caption(_("Database bar")).ToolbarPane().Top().LeftDockable(false).RightDockable(false)); - manager.AddPane(sqlQuery, wxAuiPaneInfo().Name(wxT("sqlQuery")).Caption(_("SQL query")).Center().CaptionVisible(false).CloseButton(false).MinSize(wxSize(200,100)).BestSize(wxSize(350,200))); manager.AddPane(outputPane, wxAuiPaneInfo().Name(wxT("outputPane")).Caption(_("Output pane")).Bottom().MinSize(wxSize(200,100)).BestSize(wxSize(550,300))); - manager.AddPane(scratchPad, wxAuiPaneInfo().Name(wxT("scratchPad")).Caption(_("Scratch pad")).Right().MinSize(wxSize(100,100)).BestSize(wxSize(250,200))); + manager.AddPane(scratchPad, wxAuiPaneInfo().Name(wxT("scratchPad")).Caption(_("Scratch pad")).Right().MinSize(wxSize(100,100)).BestSize(wxSize(250,200))); + manager.AddPane(sqlNotebook, wxAuiPaneInfo().Name(wxT("sqlQuery")).Caption(_("SQL query")).Center().CaptionVisible(false).CloseButton(false).MinSize(wxSize(200,100)).BestSize(wxSize(350,200))); - // Now load the layout + /*777 Activate later for final release of GQB avoid right now for debug wxString perspective; settings->Read(wxT("frmQuery/Perspective-") + VerFromRev(FRMQUERY_PERPSECTIVE_VER), &perspective, FRMQUERY_DEFAULT_PERSPECTIVE); manager.LoadPerspective(perspective, true); + */ + + + // and reset the captions for the current language manager.GetPane(wxT("toolBar")).Caption(_("Tool bar")); manager.GetPane(wxT("databaseBar")).Caption(_("Database bar")); manager.GetPane(wxT("sqlQuery")).Caption(_("SQL query")); manager.GetPane(wxT("outputPane")).Caption(_("Output pane")); manager.GetPane(wxT("scratchPad")).Caption(_("Scratch pad")); + //manager.GetPane(wxT("tablesBrowser")).Caption(_("Tables Browser")); // Sync the View menu options viewMenu->Check(MNU_DATABASEBAR, manager.GetPane(wxT("databaseBar")).IsShown()); viewMenu->Check(MNU_TOOLBAR, manager.GetPane(wxT("toolBar")).IsShown()); viewMenu->Check(MNU_OUTPUTPANE, manager.GetPane(wxT("outputPane")).IsShown()); viewMenu->Check(MNU_SCRATCHPAD, manager.GetPane(wxT("scratchPad")).IsShown()); + //viewMenu->Check(MNU_TABLES_BROWSER, manager.GetPane(wxT("tablesBrowser")).IsShown()); // tell the manager to "commit" all the changes just made manager.Update(); @@ -422,6 +508,14 @@ msgResult->SetMaxLength(0L); msgHistory->SetMaxLength(0L); + + + + +/*This should be replaced with a message when activating GQB not at startuo*/ +wxString msg=wxT("Loading GQB Tree info, this should be move to an activation button for gqb"); +wxBusyInfo waiting(msg, this); + } @@ -432,6 +526,17 @@ msgResult->Disconnect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); msgHistory->Disconnect(wxID_ANY, wxEVT_SET_FOCUS, wxFocusEventHandler(frmQuery::OnFocus)); + if(sqlNotebook){ + delete sqlNotebook; + controller->nullView(); //to avoid bug on *nix when deleting controller + } + if(controller) + delete controller; + if(model) + delete model; + /*if(tablesBrowser) + delete tablesBrowser;*/ + if (mainForm) mainForm->RemoveFrame(this); @@ -478,6 +583,16 @@ manager.Update(); } +/* +void frmQuery::OnToggleTablesBrowser(wxCommandEvent& event){ + if (viewMenu->IsChecked(MNU_TABLES_BROWSER)) + manager.GetPane(wxT("tablesBrowser")).Show(true); + else + manager.GetPane(wxT("tablesBrowser")).Show(false); + manager.Update(); +} +*/ + void frmQuery::OnToggleDatabaseBar(wxCommandEvent& event) { if (viewMenu->IsChecked(MNU_DATABASEBAR)) @@ -760,6 +875,15 @@ sqlResult->SetConnection(conn); title = wxT("Query - ") + cbConnection->GetValue(); setExtendedTitle(); + + //Refresh GQB Tree if used + if(conn && !firstTime) + { + wxString msg = wxT("Retrieving tables from database ")+conn->GetDbname(); + wxBusyInfo waiting(msg, this); + controller->getTablesBrowser()->refreshTables(conn); + controller->getView()->Refresh(); + } } } @@ -857,6 +981,66 @@ } + +void frmQuery::OnTest(wxCommandEvent& event){ + +//Not RELATED to GQB, other test... +//tablesBrowser->DeleteAllItems();; +//wxString query=wxT("nada por ahora"); + +//Generate Sentence +sqlQuery->ClearAll(); +sqlQuery->AddText(controller->generateSQL()); +sqlNotebook->SetSelection(0); + +} + +void frmQuery::OnTest2(wxCommandEvent& event){ + +//Change pointer mode +static int x=1; +if(x==1){ + controller->setPointerMode(pt_join); + x=0; +}else{ + controller->setPointerMode(pt_normal); + x=1; +} +} + +void frmQuery::OnTest3(wxNotebookEvent& event){ +/* +//disable because don't works on wxmsw + if(sqlNotebook && sqlNotebook->GetPageCount()>=2){ + wxWindow *now = sqlNotebook->GetCurrentPage(); + wxWindow *gqb = sqlNotebook->GetPage(1); + if(now==gqb){ + outputPane->GetPage(4)->Show(); + outputPane->GetPage(5)->Show(); + }else{ + outputPane->GetPage(4)->Hide(); + outputPane->GetPage(5)->Hide(); + } + } + */ +if(sqlNotebook) + if (sqlNotebook->GetPageCount()>=2) + if(firstTime) + { + // Create a server object and connect it. + wxString msg= wxT("Retrieving tables from database ") + conn->GetDbname(); + wxBusyInfo waiting(msg, this); + controller->getTablesBrowser()->refreshTables(conn); + firstTime=false; + //TODO: adjust the size too when the sash is moved, when the scrollbar appears there is a little mistake at the end because is cover + wxSize s = sqlNotebook->GetSize(); + s.SetWidth(200); + controller->getTablesBrowser()->SetSize(s); + controller->setSashPosition(controller->getTablesBrowser()->GetSize().GetWidth()); + } +} + + void frmQuery::OnSetFocus(wxFocusEvent& event) { sqlQuery->SetFocus(); Index: pgadmin/Makefile.am =================================================================== --- pgadmin/Makefile.am (revision 7397) +++ pgadmin/Makefile.am (working copy) @@ -39,6 +39,7 @@ include $(srcdir)/include/module.mk include $(srcdir)/schema/module.mk include $(srcdir)/slony/module.mk +include $(srcdir)/gqb/module.mk include $(srcdir)/ui/module.mk include $(srcdir)/utils/module.mk Index: pgadmin/gqb/gqbDatabase.cpp =================================================================== --- pgadmin/gqb/gqbDatabase.cpp (revision 0) +++ pgadmin/gqb/gqbDatabase.cpp (revision 0) @@ -0,0 +1,178 @@ +// App headers +#include "pgAdmin3.h" + +// wxWindows headers +#include +#include "wx/regex.h" + +//GQB headers +#include +#include +#include +#include "schema/pgSchema.h" + +gqbDatabase::gqbDatabase(wxString *name, type_gqbObject type=_gqbDatabase): +gqbObject(name,type) +{ + this->setType(_gqbDatabase); + this->setName(name); + this->setOwner(NULL); + conn=NULL; +} + + +void gqbDatabase::createObjects(gqbBrowser *_tablesBrowser, pgConn *_conn) +{ + + wxString rootNodeString = wxString(_conn->GetDbname()); +//Create Root Node + _tablesBrowser->createRoot(rootNodeString); + +//fillBrowser + createSchemas(_conn,_tablesBrowser,_tablesBrowser->getCatalogRootNode(),GQB_CATALOG,5); + createSchemas(_conn,_tablesBrowser,_tablesBrowser->getTablesRootNode(),GQB_OTHER,1); +} + + +//Use database connection to create all objects inside tree +void gqbDatabase::createSchemas(pgConn *conn, gqbBrowser *tablesBrowser, wxTreeItemId parentNode,typeSchema MetaType, int indexImage) +{ + +//Search Schemas and insert it + wxString restr = wxT(" WHERE "); + + if (MetaType != GQB_CATALOG) + { + restr += wxT("NOT "); + } + restr += wxT("((nspname = 'pg_catalog' and (SELECT count(*) FROM pg_class WHERE relname = 'pg_class' AND relnamespace = nsp.oid) > 0) OR\n"); + restr += wxT("(nspname = 'pgagent' and (SELECT count(*) FROM pg_class WHERE relname = 'pga_job' AND relnamespace = nsp.oid) > 0) OR\n"); + restr += wxT("(nspname = 'information_schema' and (SELECT count(*) FROM pg_class WHERE relname = 'tables' AND relnamespace = nsp.oid) > 0) OR\n"); + restr += wxT("(nspname LIKE '_%' and (SELECT count(*) FROM pg_proc WHERE proname='slonyversion' AND pronamespace = nsp.oid) > 0) OR\n"); + restr += wxT("(nspname = 'dbo' and (SELECT count(*) FROM pg_class WHERE relname = 'systables' AND relnamespace = nsp.oid) > 0) OR\n"); + restr += wxT("(nspname = 'sys' and (SELECT count(*) FROM pg_class WHERE relname = 'all_tables' AND relnamespace = nsp.oid) > 0)) AND nspname!='information_schema'\n"); + + if (conn->EdbMinimumVersion(8, 2)) + restr += wxT(" AND nsp.nspparent = 0\n"); + +/* TODO: research if this it's needed in the gqb Tree +if (!conn->GetSchemaRestriction().IsEmpty()) + restr += wxT(" AND nspname NOT IN (") + collection->GetDatabase()->GetSchemaRestriction() + wxT(")");*/ + + wxString sql; + + if (MetaType == GQB_CATALOG) + { + sql = wxT("SELECT 2 AS nsptyp,\n") + wxT(" nsp.nspname, nsp.oid, pg_get_userbyid(nspowner) AS namespaceowner, nspacl, description,") + wxT(" FALSE as cancreate\n") + wxT(" FROM pg_namespace nsp\n") + wxT(" LEFT OUTER JOIN pg_description des ON des.objoid=nsp.oid\n") + + restr + + wxT(" ORDER BY 1, nspname"); + } + else + { + if (conn->BackendMinimumVersion(8, 1)) + { + sql = wxT("SELECT CASE WHEN nspname LIKE E'pg\\\\_temp\\\\_%' THEN 1\n") + wxT(" WHEN (nspname LIKE E'pg\\\\_%') THEN 0\n"); + } + else + { + sql = wxT("SELECT CASE WHEN nspname LIKE 'pg\\\\_temp\\\\_%' THEN 1\n") + wxT(" WHEN (nspname LIKE 'pg\\\\_%') THEN 0\n"); + } + sql += wxT(" ELSE 3 END AS nsptyp,\n") + wxT(" nsp.nspname, nsp.oid, pg_get_userbyid(nspowner) AS namespaceowner, nspacl, description,") + wxT(" has_schema_privilege(nsp.oid, 'CREATE') as cancreate\n") + wxT(" FROM pg_namespace nsp\n") + wxT(" LEFT OUTER JOIN pg_description des ON des.objoid=nsp.oid\n") + + restr + + wxT(" ORDER BY 1, nspname"); + } + + pgSet *schemas = conn->ExecuteSet(sql); + wxTreeItemId parent; + + if (schemas) + { + while (!schemas->Eof()) + { + wxString name=schemas->GetVal(wxT("nspname")); + long nsptyp=schemas->GetLong(wxT("nsptyp")); + + wxStringTokenizer tokens(settings->GetSystemSchemas(), wxT(",")); + while (tokens.HasMoreTokens()) + { + wxRegEx regex(tokens.GetNextToken()); + if (regex.Matches(name)) + { + nsptyp = SCHEMATYP_USERSYS; + break; + } + } + + if (nsptyp <= SCHEMATYP_USERSYS && MetaType != GQB_CATALOG && !settings->GetShowSystemObjects()) + { + schemas->MoveNext(); + continue; + } + + if (MetaType == PGM_CATALOG) + { +/* TODO:Remove after use all usefeul code +catalog = new pgCatalog(name); +catalog->iSetSchemaTyp(nsptyp); +catalog->iSetDatabase(collection->GetDatabase()); +catalog->iSetComment(schemas->GetVal(wxT("description"))); +catalog->iSetOid(schemas->GetOid(wxT("oid"))); +catalog->iSetOwner(schemas->GetVal(wxT("namespaceowner"))); +catalog->iSetAcl(schemas->GetVal(wxT("nspacl"))); +catalog->iSetCreatePrivilege(false);*/ + +//Create Schema Object + wxString *tmpname=new wxString(name); + gqbSchema *schema = new gqbSchema(this, tmpname, _gqbSchema); + int index=-1; + parent=tablesBrowser->AppendItem(parentNode, name , indexImage, indexImage,schema); + schema->createObjects(tablesBrowser,conn,schemas->GetOid(wxT("oid")),parent,5); + schemas->MoveNext(); + } + else + { + +/* TODO:Remove after use all useful code +schema = new pgSchema(name); +schema->iSetSchemaTyp(nsptyp); +schema->iSetDatabase(collection->GetDatabase()); +schema->iSetComment(schemas->GetVal(wxT("description"))); +schema->iSetOid(schemas->GetOid(wxT("oid"))); +schema->iSetOwner(schemas->GetVal(wxT("namespaceowner"))); +schema->iSetAcl(schemas->GetVal(wxT("nspacl"))); +schema->iSetCreatePrivilege(schemas->GetBool(wxT("cancreate")));*/ + +//Create Schema Object + wxString *tmpname=new wxString(name); + gqbSchema *schema = new gqbSchema(this, tmpname, _gqbSchema); + parent=tablesBrowser->AppendItem(parentNode, name , indexImage, indexImage,schema); + int iconIndex=-1; + //TODO: temporary fix replace this with a better one option + if(schema->getName().Contains(wxT("pg_catalog"))) + iconIndex=6; + else + iconIndex=2; + //Create tables inside this schema. + schema->createObjects(tablesBrowser,conn,schemas->GetOid(wxT("oid")),parent,iconIndex); + + schemas->MoveNext(); + +/* } + else + break;*/ + } + } + + delete schemas; + } +} Index: pgadmin/gqb/gqbObject.cpp =================================================================== --- pgadmin/gqb/gqbObject.cpp (revision 0) +++ pgadmin/gqb/gqbObject.cpp (revision 0) @@ -0,0 +1,57 @@ +// App headers +#include "pgAdmin3.h" + +// wxWindows headers +#include +#include + +//TODO: research if will be more useful to use & or * in returning functions (getters). + +gqbObject::gqbObject(wxString *name, type_gqbObject type) +{ + this->Type=type; + this->Name=name; +} + + +gqbObject::~gqbObject() +{ + if(Name) //Owner it's just a pointer to an object, please don't delete the object that hold it, should destroy it. + delete Name; +} + + +void gqbObject::setName(wxString *name) +{ + this->Name=name; +} + + +const wxString& gqbObject::getName() +{ + return (*Name); +} + + +void gqbObject::setOwner(wxTreeItemData *owner) +{ + this->Owner=owner; +} + + +const wxTreeItemData& gqbObject::getOwner() +{ + return (*Owner); +} + + +void gqbObject::setType(type_gqbObject tname) +{ + this->Type=tname; +} + + +const type_gqbObject gqbObject::getType() +{ + return this->Type; +} Index: pgadmin/gqb/gqbView.cpp =================================================================== --- pgadmin/gqb/gqbView.cpp (revision 0) +++ pgadmin/gqb/gqbView.cpp (revision 0) @@ -0,0 +1,495 @@ +/* +1. READ MODEL STATE FROM gqbModel TO CREATE THE GRAPHIC REPRESENTATION OF THE QUERY +2. USE THE CONTROLLER TO CHANGE THE MODEL WITH THE USER INPUT +*/ +#include "pgAdmin3.h" + +// wxWindows headers +#include +#include "wx/dcbuffer.h" +#include "wx/generic/gridctrl.h" +#include + +// GQB headers +#include "gqb/gqbModel.h" +#include "gqb/gqbEvents.h" +#include "gqb/gqbViewController.h" +#include "gqb/gqbQueryObjs.h" +#include "gqb/gqbGraphSimple.h" +#include "gqb/gqbViewPanels.h" +#include "gqb/gqbObject.h" +#include "gqb/gqbObjectCollection.h" + +#include "gqb/gqbJoinCursor.xpm" + + +BEGIN_EVENT_TABLE(gqbView, wxScrolledWindow) +EVT_PAINT(gqbView::onPaint) +EVT_MOTION(gqbView::onMotion) +EVT_LEFT_DOWN(gqbView::onMotion) +EVT_RIGHT_DOWN(gqbView::onRightClick) +EVT_LEFT_UP(gqbView::onMotion) +EVT_LEFT_DCLICK(gqbView::onDoubleClick) +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_RMT_DELETE,gqbView::OnMenuTableDelete) +END_EVENT_TABLE() + +gqbView::gqbView(wxWindow *gqbParent, wxNotebook *gridParent, wxSize size, gqbController *controller, gqbModel *model) +: wxScrolledWindow(gqbParent, wxID_ANY, wxPoint(201,0), size, +wxHSCROLL | wxVSCROLL | wxBORDER | wxRETAINED) +{ + this->controller=controller; + this->model=model; + pressed=-1; + selected=-1; + changeTOpressed=false; + canvasSize=size; + collectionSelected=NULL; + joinSelected=NULL; + joinSource=NULL; + joinDest=NULL; + joinSCol=NULL; + joinDCol=NULL; + refreshRate=3; + iterator=NULL; + mode=pt_normal; + joinCursorImage = wxBitmap(gqbJoinCursor_xpm).ConvertToImage(); + joinCursor= wxCursor(joinCursorImage); + m_rightJoins=NULL; + m_rightTables=NULL; + jTempSelected=NULL; + cTempSelected=NULL; + + //Assign default graphic behavior [skin of forms inside model] + this->graphBehavior = new gqbGraphSimple(); + + //Create Projection Panel + this->gridTable = new gqbGridTable(this->model->getOrderedColumns(),this->model->getColumnsParents(),this->model->getColumnsAlias()); //TODO: move model to grid panel constructor + this->projectionPanel = new gqbGridPanel(gridParent,-1,gridTable); + + //Create Restrictions Panel + this->restrictionsGridTable = new gqbRestGridTable(model->getRestrictions()); + this->criteriaPanel = new gqbCriteriaPanel(gridParent,model,restrictionsGridTable); + +} + +gqbView::~gqbView() +{ + if(graphBehavior) + delete graphBehavior; + if(iterator) + delete iterator; + + + if(m_rightTables) + delete m_rightTables; + + if(m_rightJoins) + delete m_rightJoins; + + /*if(projectionPanel) + delete projectionPanel; + if(criteriaPanel) + delete criteriaPanel;*/ + /* + //TODO: This should be delete here, but raises an exception. Probably the same mistake that view/controller + FIX this and the other error + if(colsGrid) o panelgrid + delete colsGrid; + */ + + +} + + +//Overwrite and disable onEraseBackground Event to avoid Flicker +void gqbView::onEraseBackGround(wxEraseEvent& event) { +} + +//Detect when should be drawn the canvas with the model information +void gqbView::onPaint(wxPaintEvent& event) +{ + wxPaintDC dcc(this); //Prepare Context for Buffered Draw + wxBufferedDC dc(&dcc, canvasSize); + drawAll(dc); //Call Function to draw all + //event.Skip(); +} + +//TODO: remove all possible modification to model from here to controller. + + +void gqbView::onRightClick(wxMouseEvent& event){ +//TODO: Validate Alias + gqbObject *anySelected=NULL; + wxPoint pdc=event.GetPosition(); + pdc.x=event.GetPosition().x; + pdc.y=event.GetPosition().y; + this->CalcUnscrolledPosition(pdc.x,pdc.y,&pdc.x,&pdc.y); + anySelected=controller->getModelSelected(pdc,cTempSelected, jTempSelected, false); + if(anySelected){ + if(anySelected->getType()==_gqbQueryObj){ + if(!m_rightTables){ + m_rightTables = new wxMenu; + m_rightTables->Append(GQB_RMT_DELETE, wxT("&Delete Table")); + } + cTempSelected=(gqbQueryObject *) (gqbObjectCollection *) anySelected; + jTempSelected=NULL; + PopupMenu(m_rightTables, event.GetPosition()); + } + + if(anySelected->getType()==_gqbJoin){ + if(!m_rightJoins){ + m_rightJoins = new wxMenu; + m_rightJoins->Append(GQB_RMJ_DELETE, wxT("&Delete Join")); + } + cTempSelected=NULL; + jTempSelected=(gqbQueryJoin *) anySelected;; + PopupMenu(m_rightJoins, event.GetPosition()); + } + } +} + + +void gqbView::OnMenuJoinDelete(wxCommandEvent& WXUNUSED(event)){ + if(jTempSelected){ + controller->removeJoin(jTempSelected); + jTempSelected=NULL; + this->Refresh(); + } +} + +void gqbView::OnMenuTableDelete(wxCommandEvent& WXUNUSED(event)){ + if(cTempSelected){ + controller->removeTableFromModel(cTempSelected,gridTable); + cTempSelected=NULL; + this->Refresh(); + } +} + + +void gqbView::onDoubleClick(wxMouseEvent& event) +{ +//TODO: Validate Alias + gqbObject *anySelected=NULL; + wxPoint pdc=event.GetPosition(); + pdc.x=event.GetPosition().x; + pdc.y=event.GetPosition().y; + this->CalcUnscrolledPosition(pdc.x,pdc.y,&pdc.x,&pdc.y); + anySelected=controller->getModelSelected(pdc,cTempSelected, jTempSelected, false); + if(anySelected){ + if(anySelected->getType()==_gqbQueryObj){ + gqbQueryObject* t = (gqbQueryObject *) (gqbObjectCollection *) anySelected; + //wxString text=wxT("Write an Alias for table ")+t->getName(); + wxTextEntryDialog dialog(this, + wxT("Enter an Alias for table ")+t->getName()+wxT(" without withespaces"), + wxT("Please enter an Alias for table, e.g. for table Customers may be ctr"), + wxT(""), + wxOK | wxCANCEL); + if (dialog.ShowModal() == wxID_OK) + t->setAlias(dialog.GetValue()); + } + } + this->Refresh(); +} + + +//Manages user input [Mouse click, drag & drop] over the Canvas +void gqbView::onMotion(wxMouseEvent& event) +{ + static int refresh=1; //refresh counter, everytime this values reaches "refreshRate" value then Refresh while dragging +//Discover area where event ocurrs + pos.x=event.GetPosition().x; + pos.y=event.GetPosition().y; + this->CalcUnscrolledPosition(pos.x,pos.y,&pos.x,&pos.y); + gqbObject *anySelected=NULL; + +/*Button Down Event is triggered*/ + if(event.ButtonDown()&& !changeTOpressed) + { + this->SetFocus(); + + + //which kind of button down was? join creation [click on any column at the rigth of checkbox and drag & drop] or table moving [click on title and drag & drop] + anySelected=controller->getModelSelected(pos,collectionSelected, joinSelected, false); + if(anySelected){ + //Anything before just forget about it + changeTOpressed=false; + joinSource=NULL; + joinSCol=NULL; + joinDCol=NULL; + joinDest=NULL; + jpos.x=0; + jpos.y=0; + + if(anySelected->getType()==_gqbQueryObj){ + gqbQueryObject* t = (gqbQueryObject *) (gqbObjectCollection *) anySelected; + //if click on the title area AND don't click on the columns selection checkbox + if( (pos.y-t->position.y <= graphBehavior->getTitleRowHeight())) + controller->setPointerMode(pt_normal);//mode=pt_normal; + else + if(pos.x - t->position.x <= 17) + controller->setPointerMode(pt_normal);//mode=pt_normal; + else + controller->setPointerMode(pt_join);//mode=pt_join; + } + }else{ + anySelected=false; + mode=pt_normal; + } + + + if(mode==pt_normal) //pointer is used to move tables & select/unselect columns + { + //getSelected Item [Mark it as selected if possible] + anySelected=controller->getModelSelected(pos,collectionSelected, joinSelected, true); + changeTOpressed=true; + //Do conversion of type object if any found + if(anySelected){ + if(anySelected->getType()==_gqbQueryObj) + { + collectionSelected = (gqbQueryObject *) (gqbObjectCollection *) anySelected; + joinSelected = NULL; + } + else if(anySelected->getType()==_gqbJoin) + { + joinSelected = (gqbQueryJoin *) anySelected; + collectionSelected = NULL; + } + }else{ + collectionSelected = NULL; + joinSelected = NULL; + } + + + + if(!collectionSelected) //none selected temp unselect all items + { + controller->unsetModelSelected(true); + } + else + { + gqbColumn *col=graphBehavior->getColumnAtPosition(&pos,collectionSelected); + if(col) + { //Add or remove column from model & observers (ex: Grid) (projection part of SQL sentence) + controller->processColumnInModel(collectionSelected,col,gridTable); + } + } + + if(!joinSelected){ + controller->unsetModelSelected(false); + } + + + + } //pointer is used to add joins + else if(mode==pt_join) + { + anySelected=controller->getModelSelected(pos,collectionSelected, joinSelected, false); + + if( (anySelected) && anySelected->getType()==_gqbQueryObj) //even if I get an object check that it isn't a join + joinSource = (gqbQueryObject *)(gqbObjectCollection *) anySelected; + else + joinSource = NULL; + + if(!joinSource) //creation of join starts + { + joinSCol=NULL; + joinDCol=NULL; + jpos.x=0; + jpos.y=0; + } + else + { + joinSCol=graphBehavior->getColumnAtPosition(&pos,joinSource,joinSource->getWidth()); + jpos=pos; +//TODO then draw line between column & pointer + } + } + + this->Refresh(); + } + +/*Button Up Event is triggered*/ + if(event.ButtonUp()) + { + if(mode==pt_normal) //pointer is used to move tables & select/unselect columns + { + changeTOpressed=false; + } //pointer is used to add joins + else if(mode==pt_join) + { + anySelected=controller->getModelSelected(pos,collectionSelected, joinSelected, false); + + if( (anySelected) && anySelected->getType()==_gqbQueryObj){ //even if I get an object check that it isn't a join + joinDest = (gqbQueryObject *)(gqbObjectCollection *) anySelected; + //validate not self joins [in this version tables can be duplicated to create same effect] + if(joinDest==joinSource){ + joinDest=NULL; + } + }else + joinDest = NULL; + + if(!joinDest) //creation of join starts + { + joinSource=NULL; + joinSCol=NULL; + joinDCol=NULL; + joinDest=NULL; + jpos.x=0; + jpos.y=0; + } + else + { + joinDCol=graphBehavior->getColumnAtPosition(&pos,joinDest,joinDest->getWidth()); + if(joinDCol) + { +//TODO: Allow other type of joins + gqbQueryJoin *qj=controller->addJoin(joinSource,joinSCol,joinDest,joinDCol,_equally); + graphBehavior->calcAnchorPoint(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; + joinSCol=NULL; + joinDest=NULL; + joinDCol=NULL; + jpos.x=0; + jpos.y=0; + } + } + + controller->setPointerMode(pt_normal); //when button is up, pointer mode should be only normal + this->Refresh(); + } + +/*Mouse is Dragged while mouse button is down*/ + if (event.Dragging()&&pressed) + { + if(mode==pt_normal) + { + if(collectionSelected) + { + if((pos.x > collectionSelected->position.x+17) || (pos.x < collectionSelected->position.x) ) //TODO: same as gqbGraphBehavior.h [find a way to not hard code the 17 default value] + { + graphBehavior->UpdatePosObject(collectionSelected,pos.x,pos.y,40); + } + + if(refresh%refreshRate==0) //Don't draw too much when dragging table around canvas [lower cpu use] + { + this->Refresh(); + refresh=1; + }else + refresh++; + + } + } + else if(mode==pt_join) + { + if(joinSource && !joinDest) + { + this->Refresh(); + } + + } + } +//this->Refresh(); //this should be change because the model should be who inform to the view (after view register with the model); +//event.Skip(); +} + + +void gqbView::OnKeyDown(wxKeyEvent& event) +{ + if(event.GetKeyCode() == WXK_DELETE) + { + if(collectionSelected) + { + controller->removeTableFromModel(collectionSelected,gridTable); + collectionSelected=NULL; + this->Refresh(); + } + + if(joinSelected) + { + controller->removeJoin(joinSelected); + joinSelected=NULL; + this->Refresh(); + } + } + //event.Skip(); +} + + +void gqbView::drawAll(wxBufferedDC& bdc) +{ + bdc.Clear(); + if(!iterator) + //Get an iterator for the objects (tables/views) in the model. + iterator = this->model->createQueryIterator(); + else + iterator->ResetIterator(); + + //First Draw Tables + while(iterator->HasNext()) + { + gqbQueryObject *tmp= (gqbQueryObject *)iterator->Next(); + wxPoint pt = wxPoint(tmp->position); //Use a copy because I don't want to store the modified version of point after CalcScrolledPosition was called + //adjust coordinates + this->CalcScrolledPosition(pt.x,pt.y,&pt.x,&pt.y); + graphBehavior->drawTable(bdc,&pt,tmp); //graph table + } + + //Later Draw Joins over Tables + iterator->ResetIterator(); + while(iterator->HasNext()) + { + gqbQueryObject *tmp= (gqbQueryObject *)iterator->Next(); + + if(tmp->getHaveJoins()) + { + gqbIteratorBase *joinsIterator = tmp->createJoinsIterator(); + while(joinsIterator->HasNext()) + { + gqbQueryJoin *join = (gqbQueryJoin *) joinsIterator->Next(); + wxPoint o = join->getSourceAnchor(); + wxPoint d = join->getDestAnchor(); + //adjust coordinates origin + this->CalcScrolledPosition(o.x,o.y,&o.x,&o.y); + //adjust coordinates destination + this->CalcScrolledPosition(d.x,d.y,&d.x,&d.y); + graphBehavior->drawJoin(bdc,o,d,join->getAnchorsUsed(), join->getSelected()); + } + delete joinsIterator; + } + + } + + + +//this iterator is delete at destroyer for reuse purposes + + if(joinSource) + { + //Draw temporary line while creating a join + graphBehavior->drawTempJoinLine(bdc,jpos,pos); + } +} + + +void gqbView::setPointerMode(pointerMode pm) +{ + mode=pm; + if(mode==pt_join) + this->SetCursor(joinCursor); + else + this->SetCursor(wxNullCursor); +} + +bool gqbView::clickOnJoin (gqbQueryJoin *join, wxPoint &pt, wxPoint &origin, wxPoint &dest){ + return graphBehavior->clickOnJoin(join,pt,origin,dest); +} + +void gqbView::emptyPanelsData(){ + gridTable->emptyTableData(); +} + Index: pgadmin/gqb/gqbGraphSimple.cpp =================================================================== --- pgadmin/gqb/gqbGraphSimple.cpp (revision 0) +++ pgadmin/gqb/gqbGraphSimple.cpp (revision 0) @@ -0,0 +1,400 @@ +// App headers +#include "pgAdmin3.h" + +// wxWindows headers +#include +#include "wx/dcbuffer.h" + +//GQB headers +#include "gqb/gqbGraphSimple.h" +#include + +#include "gqb/gqbColNotSel.xpm" +#include "gqb/gqbColSel.xpm" + +gqbGraphSimple::gqbGraphSimple() +{ + normalFont = wxFont(8, wxFONTFAMILY_ROMAN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); + TableTitleFont = wxFont(10, wxFONTFAMILY_ROMAN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD); + BackgroundLayer1 = wxBrush(wxColour(112, 112, 112),wxSOLID); + BackgroundLayer2 = wxBrush (wxColour(208, 208, 208),wxSOLID); + BackgroundTitle = wxBrush (wxColour(245, 245, 245),wxSOLID); + minTableWidth=80; + minTableHeight=54; + rowHeight=0; //By default but this it's replaced by font metrics value + rowLeftMargin=14; + rowRightMargin=5; + rowTopMargin=1; + lineClickThreshold=7; + selectedPen=wxPen(wxColour(0,146,195),2,wxSOLID); + selectedBrush=wxBrush(wxColour(0,146,195),wxSOLID); + imgSelBoxEmpty = wxBitmap(gqbColNotSel_xpm); + imgSelBoxSelected = wxBitmap(gqbColSel_xpm); + +} + + +//NOTES:(1) store values of width & height at queryTable. +// (2)Need to set a font for the device context before get font metrics with GetTextExtent +void gqbGraphSimple::drawTable(wxBufferedDC& bdc, wxPoint *origin, gqbQueryObject *queryTable) +{ + long w=0,h=0,height=0,width=0,margin=5; +//Get Value for row Height + if(!rowHeight) + { + bdc.SetFont(TableTitleFont); + bdc.GetTextExtent(wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZ"),&w,&h); + rowHeight=h; + } + +//Get Title Metrics + bdc.SetFont(TableTitleFont); + height+= rowHeight + rowTopMargin; + //Calculate font metrics for table title with/without alias + if(queryTable->getAlias().length()>0) + bdc.GetTextExtent(queryTable->getName()+wxT(" (")+queryTable->getAlias()+wxT(")"),&w,&h); + else + bdc.GetTextExtent(queryTable->getName(),&w,&h); + width= rowLeftMargin + w + rowRightMargin; + +//Get Columns Metrics + bdc.SetFont(normalFont); +//don't use h value from font metrics to get consistency between columns vertical separation (height) + height+=rowHeight*queryTable->parent->countCols()+rowTopMargin*queryTable->parent->countCols(); + gqbIteratorBase *iterator = queryTable->parent->createColumnsIterator(); + while(iterator->HasNext()) + { + gqbColumn *tmp= (gqbColumn *)iterator->Next(); + bdc.GetTextExtent(tmp->getName(),&w,&h); + if((rowLeftMargin + w + rowRightMargin) > width) + width=rowLeftMargin + w + rowRightMargin; + } +//don't delete iterator because will be use below; + +// Set table Size in ObjectModel (Temporary Values for object representation, +// and for this reason the view can modified model without using the controller +// because this values are used by controller when use object's size in internal operations) + if( (height+2) < minTableHeight) + { + queryTable->setHeight(minTableHeight); //+2 from BackgroundLayers addition + height=minTableHeight; + } + else + queryTable->setHeight(height+2); + + if( (width+2) < minTableWidth) + { + queryTable->setWidth(minTableWidth); + width=minTableWidth; + } + else + queryTable->setWidth(width+2); + +//Decorate Table + bdc.SetPen(*wxTRANSPARENT_PEN); +//draw second Layer + bdc.SetBrush(BackgroundLayer2); + bdc.DrawRectangle(wxRect(wxPoint(origin->x,origin->y), wxSize(width+2,height+2))); +//draw third Layer + bdc.SetBrush(BackgroundLayer1); + bdc.DrawRectangle(wxRect(wxPoint(origin->x,origin->y), wxSize(width+1,height+1))); + +//draw real frame layer + bdc.SetBrush(*wxWHITE_BRUSH); + if(queryTable->getSelected()) + { + bdc.SetPen(selectedPen); + } + else + { + bdc.SetPen(*wxBLACK_PEN); + } + bdc.DrawRectangle(wxRect(wxPoint(origin->x,origin->y), wxSize(width,height))); + +//draw title layer + bdc.SetBrush(BackgroundTitle); + bdc.DrawRectangle(wxRect(wxPoint(origin->x,origin->y), wxSize(width,rowHeight+rowTopMargin))); + bdc.SetFont(TableTitleFont); + if(queryTable->getAlias().length()>0) + bdc.DrawText(queryTable->getName()+wxT(" (")+queryTable->getAlias()+wxT(")"),origin->x+margin,origin->y+rowTopMargin); + else + bdc.DrawText(queryTable->getName(),origin->x+margin,origin->y+rowTopMargin); + bdc.SetFont(normalFont); + +//TODO: in a future reuse a little more the iterator creating it inside the Query or Table Object +// and only delete it when delete the query object. + +//Draw Columns + height=rowHeight+rowTopMargin; + iterator->ResetIterator(); + while(iterator->HasNext()) + { + gqbColumn *tmp= (gqbColumn *)iterator->Next(); + if(queryTable->existsColumn(tmp)) + { + bdc.SetTextForeground(* wxRED); + bdc.SetFont(normalFont); + bdc.DrawBitmap(imgSelBoxSelected,origin->x+3,origin->y+height,true); + } + else + { + bdc.SetFont(normalFont); + bdc.DrawBitmap(imgSelBoxEmpty,origin->x+3,origin->y+height,true); + } + bdc.DrawText(tmp->getName(),origin->x+rowLeftMargin,origin->y+height); + bdc.SetTextForeground( *wxBLACK); + height+=rowHeight+rowTopMargin; + } + delete iterator; //now if delete because it's not needed anymore + +} + + +//return a column when a user click on a checkbox [0->16] x point +gqbColumn* gqbGraphSimple::getColumnAtPosition(wxPoint *clickPoint, gqbQueryObject *queryTable, int sensibility) +{ + int countCols=queryTable->parent->countCols(),colPos=-1; + if(countCols>0) //exists any column + { + colPos= (clickPoint->y-queryTable->position.y) /(rowHeight+rowTopMargin); + } + + int x=clickPoint->x-queryTable->position.x; + if( (x>0 && x < sensibility) && colPos > 0) + //Because 0 is title + return queryTable->parent->getColumnAtIndex(colPos-1); + else + return NULL; +} + + +void gqbGraphSimple::drawTempJoinLine(wxBufferedDC& bdc, wxPoint &origin, wxPoint &end) +{ +wxPoint anchorsUsed = wxPoint(0,0); + +if(origin.xorigin y->destination + if(anchorUsed.x==1){ + bdc.DrawRectangle(origin.x,origin.y-4,8,8); + origin2.x+=20; + }else{ + bdc.DrawRectangle(origin.x-8,origin.y-4,8,8); + origin2.x-=20; + } + + if(anchorUsed.y==1){ + bdc.DrawRectangle(dest.x,dest.y-4,8,8); + dest2.x+=20; + }else{ + bdc.DrawRectangle(dest.x-8,dest.y-4,8,8); + dest2.x-=20; + } + + + bdc.DrawLine(origin,origin2); + bdc.DrawLine(dest,dest2); + bdc.DrawLine(origin2,dest2); + +} + + +//Return true if pt click over a threshold of the join, false if not +bool gqbGraphSimple::clickOnJoin(gqbQueryJoin *join, wxPoint &pt, wxPoint &origin, wxPoint &dest){ + + wxPoint origin2=origin; + wxPoint dest2=dest; + + + if(join->getAnchorsUsed().x==1){ + //bdc.DrawRectangle(origin.x,origin.y-4,8,8); + origin2.x+=20; + }else{ + //bdc.DrawRectangle(origin.x-8,origin.y-4,8,8); + origin2.x-=20; + } + + if(join->getAnchorsUsed().y==1){ + //bdc.DrawRectangle(dest.x,dest.y-4,8,8); + dest2.x+=20; + }else{ + //bdc.DrawRectangle(dest.x-8,dest.y-4,8,8); + dest2.x-=20; + } + + + /*bdc.DrawLine(origin,origin2); + bdc.DrawLine(dest,dest2); + bdc.DrawLine(origin2,dest2);*/ + + //Check origin anchor + bool value1=insideLine(pt,origin,origin2,lineClickThreshold); + + //Check dest anchor + bool value2=insideLine(pt,dest,dest2,lineClickThreshold); + + //Check line between both tables + bool value3=insideLine(pt,origin2,dest2,lineClickThreshold); + + if(value1 || value2 || value3) + return true; + else + return false; +} + + +bool gqbGraphSimple::insideLine(wxPoint &pt, wxPoint &p1, wxPoint &p2, int threshold=7){ + bool value=false; + if(distanceToLine(pt,p1,p2)origin y->destination + int sx=join->getSourceQTable()->position.x; + int sy=join->getSourceQTable()->position.y; + int dx=join->getDestQTable()->position.x; + int dy=join->getDestQTable()->position.y; + +//Source + index=join->getSourceQTable()->getColumnIndex(join->getSCol())+1; + if(sxgetSourceQTable()->getWidth(); + use.x=1; + } + else + { + x=sx; + use.x=-1; + } + y=sy+index*(rowHeight+rowTopMargin)+((rowHeight+rowTopMargin)/2); + join->setSourceAnchor(wxPoint(x,y)); + +//Destination + index=join->getDestQTable()->getColumnIndex(join->getDCol())+1; + if(dxgetDestQTable()->getWidth(); + use.y=1; + } + else + { + x=dx; + use.y=-1; + } + y=dy+index*(rowHeight+rowTopMargin)+((rowHeight+rowTopMargin)/2); + join->setDestAnchor(wxPoint(x,y)); + + join->setAnchorsUsed(use); +} + + +//Update position of Object in the query if move table & adjust all other items like joins (own & registered) +void gqbGraphSimple::UpdatePosObject(gqbQueryObject *queryTable, int x, int y, int cursorAdjustment) +{ + x-=cursorAdjustment; //Move Pointer to a better Position; + y-=rowHeight/2; + queryTable->position.x=x; //Update position of table + queryTable->position.y=y; + +//Update position of anchor points of Joins that origin from this table + if(queryTable->getHaveJoins()) + { + gqbIteratorBase *j=queryTable->createJoinsIterator(); + while(j->HasNext()) + { + gqbQueryJoin *tmp= (gqbQueryJoin *)j->Next(); + 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(); + calcAnchorPoint(tmp); + } + delete r; + } +} + +int gqbGraphSimple::getTitleRowHeight() +{ + return rowHeight; +} + Index: pgadmin/gqb/gqbViewPanels.cpp =================================================================== --- pgadmin/gqb/gqbViewPanels.cpp (revision 0) +++ pgadmin/gqb/gqbViewPanels.cpp (revision 0) @@ -0,0 +1,615 @@ +// App headers +#include "pgAdmin3.h" + +// wxWindows headers +#include +#include +#include "wx/generic/gridctrl.h" +#include "wx/hyperlink.h" +#include +#include "wx/imaglist.h" + +#include "gqb/gqbViewPanels.h" + +//images +#include "gqb/gqbUp.xpm" +#include "gqb/gqbUpTop.xpm" +#include "gqb/gqbDown.xpm" +#include "gqb/gqbDownBottom.xpm" + +#include "images/tables.xpm" +#include "images/table.xpm" +#include "images/column.xpm" + +//TODO: Change this images +//#include "images/column.xpm" +#include "images/jobdisabled.xpm" + +// +// View Columns Grid Panel Class. +// + +BEGIN_EVENT_TABLE(gqbGridPanel, wxPanel) +EVT_GRID_SELECT_CELL(gqbGridPanel::OnGridSelectCell) +EVT_GRID_RANGE_SELECT(gqbGridPanel::OnGridRangeSelected) +EVT_BUTTON(buttonUp_ID, gqbGridPanel::OnButtonUp) +EVT_BUTTON(buttonUpTop_ID, gqbGridPanel::OnButtonUpTop) +EVT_BUTTON(downUp_ID, gqbGridPanel::OnButtonDown) +EVT_BUTTON(downUpBottom_ID, gqbGridPanel::OnButtonDownBottom) +END_EVENT_TABLE() + +gqbGridPanel::gqbGridPanel(wxWindow* parent, wxWindowID id = wxID_ANY, gqbGridTable *gridModel=NULL): +wxPanel(parent,-1) +{ + gModel=gridModel; + allowSelCells=true; + selTop=-1; + selBottom=-1; + upBitmap = wxBitmap(gqbUp_xpm); + upTopBitmap = wxBitmap(gqbUpTop_xpm); + downBitmap = wxBitmap(gqbDown_xpm); + downBottomBitmap = wxBitmap(gqbDownBottom_xpm); + + buttonUp = new wxBitmapButton( this, buttonUp_ID, upBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, wxT("Column(s) Up") ); + buttonDown = new wxBitmapButton( this, buttonUpTop_ID, upTopBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, wxT("Column(s) Up") ); + buttonUpTop = new wxBitmapButton( this, downUp_ID, downBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, wxT("Column(s) Up") ); + buttonDownBottom = new wxBitmapButton( this, downUpBottom_ID, downBottomBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, wxT("Column(s) Up") ); + + + this->colsGrid = new wxGrid(this, -1, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxTE_DONTWRAP,wxT("")); + colsGrid->SetTable(gModel,true,wxGrid::wxGridSelectCells); + colsGrid->SetColSize(0,300); + colsGrid->SetColSize(1,300); + colsGrid->SetColSize(2,300); + + /* This should be use? + colsGrid->SetRowSize(0, 60); + colsGrid->SetColSize(0, 120 ); + */ + + + wxBoxSizer *horizontalSizer = new wxBoxSizer( wxHORIZONTAL ); + horizontalSizer->Add(colsGrid, + 1, // make vertically stretchable + wxEXPAND | // make horizontally stretchable + wxALL, // and make border all around + 10 ); // set border width to 10 + + wxBoxSizer *buttonsSizer = new wxBoxSizer( wxVERTICAL ); + + buttonsSizer->Add( + this->buttonUpTop, + 0, // make horizontally unstretchable + wxALL, // make border all around (implicit top alignment) + 10 ); // set border width to 10 + + buttonsSizer->Add( + this->buttonUp, + 0, // make horizontally unstretchable + wxALL, // make border all around (implicit top alignment) + 10 ); // set border width to 10 + + buttonsSizer->Add( + this->buttonDown, + 0, // make horizontally unstretchable + wxALL, // make border all around (implicit top alignment) + 10 ); // set border width to 10 + + buttonsSizer->Add( + this->buttonDownBottom, + 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); +} +gqbGridPanel::~gqbGridPanel(){ + if (buttonUp) + delete buttonUp; + if(buttonDown) + delete buttonDown; + if(buttonUpTop) + delete buttonUpTop; + if(buttonDownBottom) + delete buttonDownBottom; +} + + +void gqbGridPanel::OnGridSelectCell( wxGridEvent& ev ) +{ + if(allowSelCells) + { + if ( ev.Selecting() ){ + selTop=ev.GetRow(); + selBottom=-1; + } + else{ + selTop=-1; + selBottom=-1; + } + } +ev.Skip(); +} + + +void gqbGridPanel::OnGridRangeSelected( wxGridRangeSelectEvent& ev ) +{ + if(allowSelCells) + { + if ( ev.Selecting() ) + { + selTop=ev.GetTopRow(); + selBottom=ev.GetBottomRow(); + } + else + { + selTop=-1; + selBottom=-1; + } + } + ev.Skip(); +} + +void gqbGridPanel::OnButtonUp(wxCommandEvent&){ + //A single row is selected + allowSelCells=false; + if((selTop>=0 && selBottom==-1) || (selTop==selBottom)){ + gModel->changesPositions(selTop,selTop--); + if(selTop<0){ + selTop=0; + } + colsGrid->SelectBlock(selTop,0,selTop,1,false); + colsGrid->SetGridCursor(selTop,0); + selBottom=-1; + }else{ + //A range of rows is selected + if (selTop>=0 && selBottom>=0){ + int newTop=selTop-1; + gModel->changesRangeOnePos(selTop,selBottom,newTop); + if(selTop > 0){ //recalculate new selection area & avoid bad selection area + selTop--; + selBottom--; + } + colsGrid->SelectBlock(selTop,0,selBottom,1,false); + colsGrid->SetGridCursor(selTop,0); + } + } + allowSelCells=true; +} + +void gqbGridPanel::OnButtonUpTop(wxCommandEvent&){ + allowSelCells=false; + if((selTop>=0 && selBottom==-1) || (selTop==selBottom)){ //A Single Row is selected + selBottom=selTop-1; + selTop=0; + gModel->changesRangeOnePos(selTop,selBottom,1); + colsGrid->SelectBlock(0,0,0,1,false); + colsGrid->SetGridCursor(0,0); + //Put variables in correct values now. + selTop=0; + selBottom=-1; + }else{ //A range of rows is selected + int newTop=0; + if (selTop>=0 && selBottom>=0){ + for(int i=selTop;i>0;i--){ //Move all range only one pos the require times to get the top + newTop=selTop-1; + gModel->changesRangeOnePos(selTop,selBottom,newTop); + if(selTop > 0){ //recalculate new selection area & avoid bad selection area + selTop--; + selBottom--; + } + colsGrid->SelectBlock(selTop,0,selBottom,1,false); + colsGrid->SetGridCursor(selTop,0); + } + } + } + allowSelCells=true; +} + +void gqbGridPanel::OnButtonDown(wxCommandEvent&){ + + allowSelCells=false; + if((selTop>=0 && selBottom==-1) || (selTop==selBottom)){ //A single row is selected + gModel->changesPositions(selTop,selTop++); + if(selTop==gModel->GetNumberRows()){ //adjust selection when selected item it's last item. + selTop--; + } + colsGrid->SelectBlock(selTop,0,selTop,1,false); + colsGrid->SetGridCursor(selTop,0); + selBottom=-1; + }else{ //A range of rows is selected + if (selTop>=0 && selBottom>=0){ + int newTop=selTop+1; + gModel->changesRangeOnePos(selTop,selBottom,newTop); + if(selBottom < gModel->GetNumberRows()-1){ //recalculate new selection area & avoid bad selection area + selTop++; + selBottom++; + } + colsGrid->SelectBlock(selTop,0,selBottom,1,false); + colsGrid->SetGridCursor(selTop,0); + } + } + allowSelCells=true; +} + +void gqbGridPanel::OnButtonDownBottom(wxCommandEvent&){ + allowSelCells=false; + //A Single Row is selected + if((selTop>=0 && selBottom==-1) || (selTop==selBottom)){ + selBottom=gModel->GetNumberRows()-1; + selTop=selTop+1; + int newBottom=gModel->GetNumberRows()-1; + gModel->changesRangeOnePos(selTop,selBottom,selTop-1); + colsGrid->SelectBlock(newBottom,0,newBottom,1,false); + colsGrid->SetGridCursor(newBottom,0); + //Put variables in correct values now. + selTop=newBottom; + selBottom=-1; + }else{//A range of rows is selected + int newTop=0, size=gModel->GetNumberRows(); + + if (selTop>=0 && selBottom>=0){ + for(int i=selBottom;ichangesRangeOnePos(selTop,selBottom,newTop); + if(selBottom < gModel->GetNumberRows()-1){ //recalculate new selection area & avoid bad selection area + selTop++; + selBottom++; + } + colsGrid->SelectBlock(selTop,0,selBottom,1,false); + colsGrid->SetGridCursor(selTop,0); + } + } + } + allowSelCells=true; +} + + + +// +// Tree with Columns & tables inside a query model +// + +gqbColsTree::gqbColsTree(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style) +: wxTreeCtrl(parent, id, pos, size, style){ + wxImageList *imageList = new wxImageList(16, 16); + imageList->Add(wxIcon(tables_xpm)); + imageList->Add(wxIcon(table_xpm)); + imageList->Add(wxIcon(column_xpm)); + this->AssignImageList(imageList); + wxString a=wxT("Select Column"); + createRoot(a); + this->Expand(rootNode); +} + +//Create root node +wxTreeItemId& gqbColsTree::createRoot(wxString &Name) +{ + rootNode=this->AddRoot(Name,0,0); + return rootNode; +} + +void gqbColsTree::refreshTree(gqbModel * model){ + this->DeleteAllItems(); //This remove and delete data inside tree's node + wxString a=wxT("Select Column"); + createRoot(a); + this->Expand(rootNode); + + wxTreeItemId parent; + gqbIteratorBase *iterator = model->createQueryIterator(); + while(iterator->HasNext()) + { + gqbQueryObject *tmpTable= (gqbQueryObject *)iterator->Next(); + parent=this->AppendItem(rootNode, tmpTable->getName() , 1, 1,NULL); + gqbIteratorBase *colsIterator = tmpTable->parent->createColumnsIterator(); + while(colsIterator->HasNext()){ + gqbColumn *tmpColumn= (gqbColumn *)colsIterator->Next(); + this->AppendItem(parent, tmpColumn->getName() , 2, 2,NULL); + } + delete colsIterator; + } + delete iterator; + + if(rootNode) + this->Expand(rootNode); +} + + +// +// Poup Window for gqbColsTree +// + +gqbColsPopUp::gqbColsPopUp(wxWindow* parent, wxWindowID id, wxString title, wxPoint pos, const wxSize size): +wxMiniFrame(parent,id,title,pos,size) +{ + this->SetSize(wxSize(233,155)); + editTree = new wxTextCtrl(this, QRTree, wxT(""),wxPoint(0,0),wxSize(193,22)); + editTree->AcceptsFocus(); + editTree->SetFocus(); + editTree->SetEditable(true); + + buttonTree= new wxButton(this, QRTreeOk, wxT("Ok") ,wxPoint(194,0), wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT | wxSIMPLE_BORDER); + this->Connect(QRTreeOk, wxEVT_COMMAND_BUTTON_CLICKED, (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction) &gqbColsPopUp::OnPopUpOKClick); + + //editTree->AcceptsFocus(); + colsTree = new gqbColsTree(this, QRTree, wxPoint(0,26), wxSize(224,104), wxTR_HAS_BUTTONS | wxSIMPLE_BORDER | wxTR_SINGLE); + +this->Connect(QRTree, wxEVT_COMMAND_TREE_ITEM_ACTIVATED, (wxObjectEventFunction) (wxEventFunction) (wxTreeEventFunction) &gqbColsPopUp::OnPopUpTreeDoubleClick); +this->Connect(QRTree, wxEVT_COMMAND_TREE_SEL_CHANGED, (wxObjectEventFunction) (wxEventFunction) (wxTreeEventFunction) &gqbColsPopUp::OnPopUpTreeClick); +} + +void gqbColsPopUp::refreshTree(gqbModel *_model){ + model=_model; + if(colsTree && _model){ + colsTree->refreshTree(model); + } + +} + +void gqbColsPopUp::OnPopUpOKClick(wxCommandEvent& event){ + this->usedGrid->SetCellValue(_row,_col,this->getEditText()); + this->MakeModal(false); + this->Hide(); + this->GetParent()->Refresh(); +} + +void gqbColsPopUp::OnPopUpTreeDoubleClick(wxTreeEvent& event){ + if(colsTree){ + wxTreeItemId itemId = event.GetItem(); + wxTreeItemId itemIdParent = colsTree->GetItemParent(itemId); + if(!colsTree->ItemHasChildren(itemId) && (colsTree->GetRootItem()!=itemId)){ + this->usedGrid->SetCellValue(_row,_col,this->getEditText()); + if(this->usedGrid->GetCellValue(_row,_col).length()<=0){ + this->usedGrid->SetCellValue(_row,_col,wxT("Set Value")); + } + this->MakeModal(false); + this->Hide(); + this->GetParent()->Refresh(); + } + } +} + + +void gqbColsPopUp::OnPopUpTreeClick(wxTreeEvent& event){ + if(colsTree){ + wxTreeItemId itemId = event.GetItem(); + wxTreeItemId itemIdParent = colsTree->GetItemParent(itemId); + + if(!colsTree->ItemHasChildren(itemId) && (colsTree->GetRootItem()!=itemId)){ + this->editTree->SetValue(colsTree->GetItemText(itemIdParent)+wxT(".")+colsTree->GetItemText(itemId)); + } + } +} + +void gqbColsPopUp::setEditText(wxString text){ + this->editTree->SetValue(text); +} + + +void gqbColsPopUp::focus(){ + this->editTree->SetFocus(); + this->editTree->SetSelection(-1,-1); +} + +// +// View Columns Criteria Panel Class. +// + +BEGIN_EVENT_TABLE(gqbCriteriaPanel, wxPanel) +EVT_BUTTON(addButton_ID, gqbCriteriaPanel::OnButtonAdd) +EVT_BUTTON(dropButton_ID, gqbCriteriaPanel::OnButtonDrop) +END_EVENT_TABLE() + +gqbCriteriaPanel::gqbCriteriaPanel(wxWindow* parent, gqbModel *_model, gqbRestGridTable *gridModel): +wxPanel(parent,-1) +{ + model=_model; + gModel=gridModel; + colsPopUp=NULL; + //TODO: add real ID not 321 + this->restrictionsGrid = new wxRestrictionGrid(this, 321); //, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxTE_DONTWRAP,wxT("")); + restrictionsGrid->SetTable(gModel,true,wxGrid::wxGridSelectCells); + restrictionsGrid->SetColSize(0,300); + restrictionsGrid->SetColSize(1,300); + restrictionsGrid->SetColSize(2,300); + restrictionsGrid->SetColSize(3,100); + this->restrictionsGrid->SetSelectionMode(wxGrid::wxGridSelectRows); + +this->Connect(321, wxEVT_GRID_CELL_LEFT_CLICK, (wxObjectEventFunction) (wxEventFunction) (wxGridEventFunction) &gqbCriteriaPanel::OnCellLeftClick); +// TODO: in a future implement OnMouseWheel + + addBitmap= wxBitmap(column_xpm); + dropBitmap= wxBitmap(jobdisabled_xpm); + buttonAdd= new wxBitmapButton( this, addButton_ID, addBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, wxT("Add")); + buttonDrop= new wxBitmapButton( this, dropButton_ID, dropBitmap, wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, wxT("Remove")); + + wxBoxSizer *horizontalSizer = new wxBoxSizer( wxHORIZONTAL ); + horizontalSizer->Add(restrictionsGrid, + 1, // make vertically stretchable + wxEXPAND | // make horizontally stretchable + wxALL, // and make border all around + 10 ); // 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); + +/* +wxString strChoices[3] = {wxT("one"), wxT("two"), wxT("three")}; +restrictionsGrid->SetCellRenderer(1, 1, new wxGridCellComboBoxRenderer); +restrictionsGrid->SetCellRenderer(1, 0, new wxGridCellButtonRenderer); +restrictionsGrid->SetCellEditor(1, 1, new wxFastComboEditor(3, strChoices, TRUE)); +restrictionsGrid->SetCellRenderer(1, 2, new wxGridCellButtonRenderer); + +restrictionsGrid->SetCellRenderer(0, 1, new wxGridCellComboBoxRenderer); +restrictionsGrid->SetCellRenderer(0, 0, new wxGridCellButtonRenderer); +restrictionsGrid->SetCellEditor(0, 1, new wxFastComboEditor(3, strChoices, TRUE)); +restrictionsGrid->SetCellRenderer(0, 2, new wxGridCellButtonRenderer); +*/ + +} + + +void gqbCriteriaPanel::showColsPopUp(int row, int col, wxPoint pos){ + if(!colsPopUp) + { + colsPopUp = new gqbColsPopUp(this,-1,wxT("Set Value"),wxDefaultPosition,wxDefaultSize); + } + + refreshTree(model); + //set initial Value + colsPopUp->setEditText(restrictionsGrid->GetCellValue(row,col)); + //Set Position for Pop Up Tree + wxPoint p=this->GetParent()->GetPosition(); //position of wxNotebook + 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; + colsPopUp->SetPosition(p); + colsPopUp->Show(); + colsPopUp->MakeModal(true); + colsPopUp->focus(); + colsPopUp->setUsedCell(restrictionsGrid,row,col); +} + + +void gqbCriteriaPanel::refreshTree(gqbModel *_model){ + //TODO: Do this through controller... + model=_model; + if(colsPopUp && model) + colsPopUp->refreshTree(model); + +} + +void gqbCriteriaPanel::OnCellLeftClick(wxGridEvent& event) +{ + wxObject *object = event.GetEventObject(); + wxRestrictionGrid *grid = wxDynamicCast( object, wxRestrictionGrid ); + + //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()); + //number 17 is button's width at cellRender function [nButtonWidth] + if((grid->GetRowLabelSize()+cellSize.GetRight())-(event.GetPosition().x) <= 17 ) + { + wxPoint p =event.GetPosition(); + showColsPopUp(event.GetRow(), event.GetCol(),p); + } + } + event.Skip(); +} + +void gqbCriteriaPanel::OnButtonAdd(wxCommandEvent&){ + //TODO: use controller one + gqbQueryRestriction *r = new gqbQueryRestriction(); + gModel->AppendItem(r); + int row=model->getRestrictions()->restrictionsCount()-1; + + wxString strChoices[16] = {wxT("="), wxT("!="),wxT("<"),wxT("<="),wxT(">"),wxT(">="),wxT("BETWEEN"),wxT("LIKE"),wxT("NOT LIKE"),wxT("ILIKE"),wxT("NOT ILIKE"),wxT("IN"),wxT("NOT IN"),wxT("NOT BETWEEN"),wxT("IS NULL"),wxT("IS NOT NULL")}; + restrictionsGrid->SetCellRenderer(row, 1, new wxGridCellComboBoxRenderer); + restrictionsGrid->SetCellRenderer(row, 0, new wxGridCellButtonRenderer); +//555 restrictionsGrid->SetCellEditor(row, 1, new wxFastComboEditor(16, strChoices, TRUE)); + restrictionsGrid->SetCellEditor(row, 1, new dxGridCellSizedChoiceEditor(WXSIZEOF(strChoices),strChoices)); + restrictionsGrid->SetCellRenderer(row, 2, new wxGridCellButtonRenderer); +} + +void gqbCriteriaPanel::OnButtonDrop(wxCommandEvent&){ + if(restrictionsGrid->GetGridCursorRow()>=0) + gModel->DeleteRows(restrictionsGrid->GetGridCursorRow(),1); + restrictionsGrid->Refresh(); +} + + +// +// View Columns Criteria Panel Class's Grid. +// + +wxRestrictionGrid::wxRestrictionGrid(wxWindow* parent, wxWindowID id): +wxGrid(parent, id, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxTE_DONTWRAP,wxT("")), +m_selTemp(NULL) +{ + // Adjust the default row height to be more compact + wxFont font = GetLabelFont(); + int nWidth = 0; + int nHeight = 18; + GetTextExtent(wxT("W"), &nWidth, &nHeight, NULL, NULL, &font); + SetColLabelSize(nHeight+6); + #ifdef __WXGTK__ + SetDefaultRowSize(nHeight+8, TRUE); + #else + SetDefaultRowSize(nHeight+4, TRUE); + #endif + + +} + +void wxRestrictionGrid::RevertSel() + { + if (m_selTemp) + { + wxASSERT(m_selection == NULL); + m_selection = m_selTemp; + m_selTemp = NULL; + } + } + + +void wxRestrictionGrid::ComboBoxEvent(wxGridEvent& event){ + +// This forces the cell to go into edit mode directly + this->m_waitForSlowClick = TRUE; + int row=event.GetRow(); + int col=event.GetCol(); + + + this->SetGridCursor(row,col); + // Store the click co-ordinates in the editor if possible + // if an editor has created a ClientData area, we presume it's + // a wxPoint and we store the click co-ordinates + wxGridCellEditor* pEditor = this->GetCellEditor(event.GetRow(), event.GetCol()); + wxPoint* pClickPoint = (wxPoint*)pEditor->GetClientData(); + if (pClickPoint) + { + *pClickPoint = this->ClientToScreen(event.GetPosition()); + #ifndef __WINDOWS__ + EnableCellEditControl(true); + #endif + } + // hack to prevent selection from being lost when click combobox + if (event.GetCol() == 0 && this->IsInSelection(event.GetRow(), event.GetCol())) + { + this->m_selTemp = this->m_selection; + this->m_selection = NULL; + } + pEditor->DecRef(); + +} + Index: pgadmin/gqb/module.mk =================================================================== --- pgadmin/gqb/module.mk (revision 0) +++ pgadmin/gqb/module.mk (revision 0) @@ -0,0 +1,34 @@ +####################################################################### +# +# pgAdmin III - PostgreSQL Tools +# $Id: module.mk 7109 2008-03-03 20:04:34Z dpage $ +# Copyright (C) 2002 - 2008, The pgAdmin Development Team +# This software is released under the Artistic Licence +# +# module.mk - pgadmin/gqb/ Makefile fragment +# +####################################################################### + +pgadmin3_SOURCES += \ + $(srcdir)/gqb/gqbArrayCollection.cpp \ + $(srcdir)/gqb/gqbBrowser.cpp \ + $(srcdir)/gqb/gqbCollection.cpp \ + $(srcdir)/gqb/gqbColumn.cpp \ + $(srcdir)/gqb/gqbController.cpp \ + $(srcdir)/gqb/gqbDatabase.cpp \ + $(srcdir)/gqb/gqbGraphSimple.cpp \ + $(srcdir)/gqb/gqbGridTable.cpp \ + $(srcdir)/gqb/gqbModel.cpp \ + $(srcdir)/gqb/gqbObject.cpp \ + $(srcdir)/gqb/gqbObjectCollection.cpp \ + $(srcdir)/gqb/gqbQueryObjs.cpp \ + $(srcdir)/gqb/gqbRestGridTable.cpp \ + $(srcdir)/gqb/gqbSchema.cpp \ + $(srcdir)/gqb/gqbTable.cpp \ + $(srcdir)/gqb/gqbViewPanels.cpp \ + $(srcdir)/gqb/gqbView.cpp + +EXTRA_DIST += \ + $(srcdir)/gqb/module.mk + + Index: pgadmin/gqb/gqbObjectCollection.cpp =================================================================== --- pgadmin/gqb/gqbObjectCollection.cpp (revision 0) +++ pgadmin/gqb/gqbObjectCollection.cpp (revision 0) @@ -0,0 +1,92 @@ +// App headers +#include "pgAdmin3.h" + +// wxWindows headers +#include + +//GQB headers +#include +#include +#include +#include + +gqbObjectCollection::gqbObjectCollection(wxString *name, type_gqbObject type): +gqbObject(name, type) +{ +//Create the concrete implementation of the Collection, right now only one implementation not need parameter + implementation = new gqbArrayCollection(); +//Create the collection using the concrete implementation + //use the array implementation of the collection + objectsCollection = new gqbCollection(implementation); + this->setOwner(NULL); +} + + +gqbObjectCollection::~gqbObjectCollection() +{ + if(objectsCollection) //Implementation is deleted when delete the collection & shouldn't be deleted again + delete objectsCollection; +} + + +void gqbObjectCollection::addObject(gqbObject *object) +{ + objectsCollection->addItem(object); +} + + +void gqbObjectCollection::removeObject(gqbObject *object) +{ + objectsCollection->removeItem(object); +} + + +gqbIteratorBase* gqbObjectCollection::createIterator() +{ + return objectsCollection->createIterator(); +} + + +int gqbObjectCollection::countObjects() +{ + return objectsCollection->count(); +} + + +gqbObject* gqbObjectCollection::getObjectAtIndex(int index) +{ + return objectsCollection->getItemAt(index); +} + + +bool gqbObjectCollection::existsObject(gqbObject *object) +{ + return objectsCollection->existsObject(object); +} + + +//Remove all objects from collection without deleting each one. +void gqbObjectCollection::removeAll() +{ + objectsCollection->removeAll(); +} + + +int gqbObjectCollection::indexObject(gqbObject *object) +{ + return objectsCollection->getIndex(object); +} + +void gqbObjectCollection::insertObjectAt(gqbObject *object, int index) +{ + objectsCollection->insertAtIndex(object, index); +} + +int gqbObjectCollection::getCount(){ + return objectsCollection->count(); +} + +//remove & delete all objects +void gqbObjectCollection::deleteAll(){ + objectsCollection->deleteAll(); +} Index: pgadmin/gqb/gqbQueryObjs.cpp =================================================================== --- pgadmin/gqb/gqbQueryObjs.cpp (revision 0) +++ pgadmin/gqb/gqbQueryObjs.cpp (revision 0) @@ -0,0 +1,453 @@ +#include "pgAdmin3.h" + +// wxWindows headers +#include +#include +#include "wx/hyperlink.h" + +#include +#include +#include +#include +#include "gqb/gqbViewPanels.h" + + +// +// Collections of Tables inside a Query, data structured used for query storage & later generation of SQL sentence +// + +gqbQueryObjs::gqbQueryObjs(wxString *name): +gqbObjectCollection(NULL,_gqbQuery) +{ + this->setOwner(NULL); +} + + +void gqbQueryObjs::addTable(gqbQueryObject *mtable) +{ + this->addObject(mtable); +} + + +void gqbQueryObjs::removeTable(gqbQueryObject *mtable) +{ + this->removeObject(mtable); +} + + +gqbIteratorBase* gqbQueryObjs::createQueryIterator() +{ + return this->createIterator(); +} + +int gqbQueryObjs::tablesCount(){ + return this->countObjects(); +} + +void gqbQueryObjs::removeAllQueryObjs(){ + this->removeAll(); +} + + +// +// An Object inside a query (A table object in the query), not equal to gqbTable +// Reason: Sometimes a table can be used twice or more times in a query with different columns selected +// Because this we can not use directly the base table object + +gqbQueryObject::gqbQueryObject(gqbTable *table) +:gqbObjectCollection(new wxString(table->getName()),_gqbQueryObj) +{ + selected=false; + parent=table; +//TODO: Calculate a good initial position + position.x=20; + position.y=20; + haveJoins=false; + haveRegisteredJoins=false; + registeredCollection=NULL; + joinsCollection=NULL; +} + + +//destructor must empty collection to don't allow deleting of column items from tree +// because this collection doesn't owns it, and then shouldn't destroy it. +gqbQueryObject::~gqbQueryObject() +{ + this->removeAll(); + +//Remove item registered at this Query Object + gqbQueryJoin *tmp; + if(registeredCollection) + { + gqbIteratorBase *r=createRegJoinsIterator(); + while(r->HasNext()) + { + tmp= (gqbQueryJoin *)r->Next(); + this->unregisterJoin(tmp,true); //remove and unregister every join in every query object which have registered at this query object +//On each iteration the structure of iterator change because modified his own collection & should be reset + r->ResetIterator(); + } + delete r; + } + + if(joinsCollection) + { + gqbIteratorBase *j=createJoinsIterator(); + while(j->HasNext()) + { + tmp= (gqbQueryJoin *)j->Next(); + this->removeJoin(tmp,true); //removes & unregister Join which have like origin this query object +//On each iteration the structure of iterator change because modified his own collection & should be reset + j->ResetIterator(); + } + delete j; + + } + +//removeJoin & unregisterJoin delete the collections where there aren't any items inside. +} + + +void gqbQueryObject::setSelected(bool value) +{ + this->selected=value; +} + + +bool gqbQueryObject::getSelected() +{ + return this->selected; +} + + +void gqbQueryObject::setWidth(int value) +{ + width=value; +} + + +int gqbQueryObject::getWidth() +{ + return width; +} + + +void gqbQueryObject::setHeight(int value) +{ + height=value; +} + + +int gqbQueryObject::getHeight() +{ + return height; +} + + +void gqbQueryObject::addColumn(gqbColumn *column) +{ + this->addObject(column); +} + + +void gqbQueryObject::removeColumn(gqbColumn *column) +{ + this->removeObject(column); +} + + +bool gqbQueryObject::existsColumn(gqbColumn *column) +{ + return this->existsObject(column); +} + + +gqbIteratorBase* gqbQueryObject::createQueryTableIterator() +{ + return this->createIterator(); +} + + +gqbIteratorBase* gqbQueryObject::createJoinsIterator() +{ + return joinsCollection->createIterator(); +} + + +gqbIteratorBase* gqbQueryObject::createRegJoinsIterator() +{ + return registeredCollection->createIterator(); +} + + +//Create a Join from this table [owner] column to other table [observable] column +gqbQueryJoin* gqbQueryObject::addJoin(gqbQueryObject *owner, gqbQueryObject *observable, gqbColumn *source, gqbColumn *destination, type_Join kind) +{ + if(!haveJoins) + { + implementationj = new gqbArrayCollection(); + joinsCollection = new gqbCollection(implementationj); + haveJoins=true; + } + + gqbQueryJoin *join = new gqbQueryJoin(owner,observable,source,destination,kind); + joinsCollection->addItem(join); + observable->registerJoin(join); + return join; +} + + +//remove the join from this query object [source table] +void gqbQueryObject::removeJoin(gqbQueryJoin *join, bool unRegister = false) +{ +//notify to observable that the join this object owns will be removed & then remove the join + if(unRegister) + join->getDestQTable()->unregisterJoin(join,false); + joinsCollection->removeItem(join); + if(join) + delete join; //Join can be only delete Here by his owner + if(joinsCollection->count()<=0) + { + delete joinsCollection; //implementation it's delete too inside collection. + haveJoins=false; + joinsCollection=NULL; + } +} + + +//register a Join created from other table [source] to this table [destination] +void gqbQueryObject::registerJoin(gqbQueryJoin *join) +{ + if(!haveRegisteredJoins) + { + implementationr = new gqbArrayCollection(); + registeredCollection = new gqbCollection(implementationr); + haveRegisteredJoins=true; + } + registeredCollection->addItem(join); +} + + +//unregister a Join create from other table [source] to this table [destination] delete the join if need it.. +void gqbQueryObject::unregisterJoin(gqbQueryJoin *join, bool removeIt = false) +{ +//notify to source/owner object of join about join removing & then remove + registeredCollection->removeItem(join); + if(removeIt) + join->getSourceQTable()->removeJoin(join,false); + if(registeredCollection->count()<=0) + { + delete registeredCollection; //implementation it's delete too inside collection. + haveRegisteredJoins=false; + registeredCollection=NULL; + } +} + + +int gqbQueryObject::getColumnIndex(gqbColumn *column) +{ + return parent->indexColumn(column); +} + + +bool gqbQueryObject::getHaveJoins() +{ + return haveJoins; +} + + +bool gqbQueryObject::getHaveRegJoins() +{ + return haveRegisteredJoins; +} + + +//TODO if last join it's delete I MUST delete implementation & collection & put haveJoins in false; +//Same for registered joins + +// +// A Join inside a query Object like Table or view [Stored at source, registered at destination] +// I need to store the owner, destination because columns it's share between multiple joins +// +gqbQueryJoin::gqbQueryJoin(gqbQueryObject *_owner, gqbQueryObject *_destination, gqbColumn *sourceCol, gqbColumn *destCol, type_Join joinKind): +gqbObject(NULL,_gqbJoin) +{ + kindofJoin=joinKind; + sCol=sourceCol; + dCol=destCol; + owner=_owner; + selected=false; + destination=_destination; +} + + +void gqbQueryJoin::setKindofJoin(type_Join kind) +{ + kindofJoin=kind; +} + + +type_Join gqbQueryJoin::getKindofJoin() +{ + return kindofJoin; +} + + +//return the object where the join is stored +gqbQueryObject* gqbQueryJoin::getSourceQTable() +{ + return owner; +} + + +//return the object where the join point to. +gqbQueryObject* gqbQueryJoin::getDestQTable() +{ + return destination; +} + + +//return the gqbObject of Destination Column +gqbColumn* gqbQueryJoin::getDCol() +{ + return dCol; +} + + +//return the gqbObject of Source Column +gqbColumn* gqbQueryJoin::getSCol() +{ + return sCol; +} + + +const wxString& gqbQueryJoin::getSourceTable() +{ + gqbTable *s=(gqbTable*)&sCol->getOwner(); + return s->getName(); +} + + +const wxString& gqbQueryJoin::getDestTable() +{ + gqbTable *d=(gqbTable*)&dCol->getOwner(); + return d->getName(); +} + + +const wxString& gqbQueryJoin::getSourceCol() +{ + return sCol->getName(); +} + + +const wxString& gqbQueryJoin::getDestCol() +{ + return dCol->getName(); +} + + +void gqbQueryJoin::setSourceAnchor(wxPoint pt) +{ + sAnchor=pt; +} + + +void gqbQueryJoin::setDestAnchor(wxPoint pt) +{ + dAnchor=pt; +} + + +wxPoint& gqbQueryJoin::getSourceAnchor() +{ + return sAnchor; +} + + +wxPoint& gqbQueryJoin::getDestAnchor() +{ + return dAnchor; +} + +void gqbQueryJoin::setSelected(bool value) +{ + this->selected=value; +} + + +bool gqbQueryJoin::getSelected() +{ + return this->selected; +} + +void gqbQueryJoin::setAnchorsUsed(wxPoint pt){ + anchorsUsed=pt; +} + +wxPoint& gqbQueryJoin::getAnchorsUsed(){ + return anchorsUsed; +} + +// +// A query restriction +// + +enum { + QRButton=9000, + QRValue, + QRConnector, + QRtype +}; + + +gqbQueryRestriction::gqbQueryRestriction(): +gqbObject(NULL,_gqbRestriction) +{ + leftPart=wxT(""); + value_s=wxT(""); + connector=wxT("AND"); + restriction=wxT("="); +} + + +gqbRestrictions::gqbRestrictions(): +gqbObjectCollection(NULL,_gqbRestriction){ + this->setOwner(NULL); +} + +gqbRestrictions::~gqbRestrictions(){ + this->removeAll(); +} + + +void gqbRestrictions::addRestriction(gqbQueryRestriction *r){ + this->addObject(r); +} + +void gqbRestrictions::addRestrictionAt(gqbQueryRestriction *r, int index){ + this->insertObjectAt(r, index); +} + +//Remove but don't delete restriction +void gqbRestrictions::removeRestriction(gqbQueryRestriction *r){ + this->removeObject(r); +} + +void gqbRestrictions::deleteAllRestrictions(){ + this->deleteAll(); +} + +gqbIteratorBase* gqbRestrictions::createRestrictionsIterator(){ + return this->createIterator(); +} + + +int gqbRestrictions::restrictionsCount(){ + return this->getCount(); +} + + +gqbQueryRestriction* gqbRestrictions::getRestrictionAt(int index){ + return (gqbQueryRestriction*)this->getObjectAtIndex(index); +} Index: pgadmin/gqb/gqbController.cpp =================================================================== --- pgadmin/gqb/gqbController.cpp (revision 0) +++ pgadmin/gqb/gqbController.cpp (revision 0) @@ -0,0 +1,355 @@ +#include "pgAdmin3.h" + +// wxWindows headers +#include +#include + + +//GQB headers +#include "gqb/gqbViewController.h" +#include "gqb/gqbModel.h" +#include "gqb/gqbQueryObjs.h" +#include "gqb/gqbBrowser.h" +#include "gqb/gqbEvents.h" + + +//Constructor +gqbController::gqbController(gqbModel *_model, wxWindow *gqbParent, wxNotebook *gridParent, wxSize size=wxSize(800,600)): +wxObject() +{ + pparent = gqbParent; + model=_model; + wxSize tablesBrowserSize = wxSize(200,800); + + //initialize view container with tables browser + gqbContainer = new wxSplitterWindow(gqbParent,wxID_ANY,wxDefaultPosition,wxDefaultSize,wxSP_3D); + //initialize view canvas and tables tree + wxPanel *browserPanel = new wxPanel(gqbContainer, wxID_ANY,wxDefaultPosition,tablesBrowserSize); + tablesBrowser = new gqbBrowser(browserPanel, GQB_BROWSER, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS | wxSIMPLE_BORDER,this); + view=new gqbView(gqbContainer, gridParent, size, this, model); + //Set Scroll Bar & split + view->SetScrollbars( 10, 10, 100, 240 ); + gqbContainer->SplitVertically(browserPanel,view); //WHY if I use this causes a bug in linux + gqbContainer->SetSashPosition(500,true); +} + + +//Destructor +gqbController::~gqbController() +{ + if(view) + { + delete view; + view=NULL; + } +} + + +//Add a table to the model +void gqbController::addTableToModel(gqbTable *table) +{ + model->addTable(table); +} + + +//Remove a table from the model +void gqbController::removeTableFromModel(gqbQueryObject *mtable, gqbGridTable *gridTable=NULL) +{ + model->deleteTable(mtable); + gridTable->removeAllRows(mtable); +} + + +//Add (Select to be use in projection) a column for table in a model +void gqbController::processColumnInModel(gqbQueryObject *table, gqbColumn *column, gqbGridTable *gridTable=NULL) +{ + if(!table->existsColumn(column)) + { + table->addColumn(column); + if(gridTable) + { + gridTable->AppendItem(0,table); + gridTable->AppendItem(1,column); + gridTable->AppendItem(2,NULL); + } + } + else + { + //removes but don't delete because we needed the column at table [this is just a pointer to it] + table->removeColumn(column); + if(gridTable) + { + gridTable->removeRow(table,column); + } + } +} + + +//Get selected item at position pt, marks item as selected and if there is a previous selected then unselect it +gqbObject* gqbController::getModelSelected(wxPoint &pt, gqbQueryObject *lastSelected, gqbQueryJoin *lastJoinSelected, bool mark) +{ + gqbQueryObject *sel=NULL; + gqbQueryJoin *jSel=NULL; + gqbIteratorBase *iterator=model->createQueryIterator(); + bool found=false; + + + while(!found && iterator->HasNext()) + { + //Try to find if click over a table + sel=(gqbQueryObject *)iterator->Next(); + if( ((pt.x - sel->position.x > 0 )&&(sel->position.x + sel->getWidth() > pt.x)) && ((pt.y - sel->position.y > 0)&&(sel->position.y + sel->getHeight() > pt.y)) ) + { //TODO: this function should be move to the view to allow to recalculate it if the graphBehavior changes + if(mark) + sel->setSelected(true); + jSel=NULL; + found=true; + break; + } + + //Try to find if user click over a Join + if(sel->getHaveJoins()){ + gqbIteratorBase *joinsIterator = sel->createJoinsIterator(); + while(joinsIterator->HasNext()) + { + //TODO: don't pass anchor because join it's passed as parameter yet. + jSel = (gqbQueryJoin *) joinsIterator->Next(); + wxPoint o = jSel->getSourceAnchor(); + wxPoint d = jSel->getDestAnchor(); + + /*//adjust coordinates origin + this->CalcScrolledPosition(o.x,o.y,&o.x,&o.y); + //adjust coordinates destination + this->CalcScrolledPosition(d.x,d.y,&d.x,&d.y); + graphBehavior->drawJoin(bdc,o,d,join->getAnchorsUsed(), join->getSelected()); + */ + if(view->clickOnJoin(jSel,pt,o,d)){ + if(mark) + jSel->setSelected(true); + found=true; + sel=NULL; + break; + } + + } + delete joinsIterator; + } + } + + delete iterator; + + if(found) + { + if(mark){ + if(lastSelected && lastSelected!=sel) //unselect previous table selected if exists + lastSelected->setSelected(false); + if(lastJoinSelected && lastJoinSelected!=jSel) //unselect previous join selected if exists + lastJoinSelected->setSelected(false); + } + if(sel) + return sel; + else if(jSel) + return jSel; + } + + return NULL; +} + + +//Unselect any previously selected item in the model +void gqbController::unsetModelSelected(bool queryTable=true) +{ + gqbQueryObject *sel=NULL; + gqbQueryJoin *jSel=NULL; + + if(queryTable){ //QueryTable + gqbIteratorBase *iterator=model->createQueryIterator(); + while(iterator->HasNext()) + { + sel=(gqbQueryObject *)iterator->Next(); + if(sel->getSelected()) + { + sel->setSelected(false); + } + } + delete iterator; + } + + if(!queryTable){ //QueryJoin + gqbIteratorBase *iterator=model->createQueryIterator(); + gqbQueryObject *sel=NULL; + while(iterator->HasNext()) + { + sel=(gqbQueryObject *)iterator->Next(); + if(sel->getHaveJoins()){ + gqbIteratorBase *joinsIterator = sel->createJoinsIterator(); + while(joinsIterator->HasNext()) + { + //TODO: don't pass anchor because join it's passed as parameter yet. + jSel = (gqbQueryJoin *) joinsIterator->Next(); + if(jSel->getSelected()) + { + jSel->setSelected(false); + } + } + + delete joinsIterator; + } + } + delete iterator; + } +} + + + +//TODO: Createa less complex & simpler generation function +//Generate the SQL Sentence from the model +wxString gqbController::generateSQL() +{ + wxString sentence=wxT(""); +if(model->tablesCount()>0){ + sentence+=wxT("SELECT \n"); + //Add selected columns for Query + + gqbQueryObject *sel=NULL; + gqbIteratorBase *iteratorRestrictions=NULL; + gqbIteratorBase *iteratorModel=NULL; + gqbIteratorBase *iteratorJoins=NULL; + + + //Projection [Select x,x,x...] + gqbObjsArray *cols=model->getOrderedColumns(); + gqbObjsArray *tables=model->getColumnsParents(); + wxArrayString *alias=model->getColumnsAlias(); + + int i,size=cols->GetCount(); + + for(i=0;iItem(i).length()>0) + sentence+=((gqbQueryObject*)tables->Item(i))->getName()+ wxT(".")+((gqbColumn*)cols->Item(i))->getName() + wxT(" AS ")+ alias->Item(i)+ wxT(", \n"); + else + sentence+=((gqbQueryObject*)tables->Item(i))->getName()+ wxT(".")+((gqbColumn*)cols->Item(i))->getName() + wxT(", \n"); + } + + if(!size) + sentence+=wxT(" * "); + else{ + sentence.Truncate(sentence.Length()-3); //remove last ", " + sentence+=wxT("\n"); + } + + sentence+=wxT(" FROM \n"); + + iteratorModel=model->createQueryIterator(); + while(iteratorModel->HasNext()) + { + sel=(gqbQueryObject *)iteratorModel->Next(); + sentence+=sel->getName()+wxT(" ,"); + } + sentence.Truncate(sentence.Length()-2); //remove last ", " + +//WHERE PART +//[Joins] + bool first=true, truncAnd=false; + gqbQueryJoin *tmp; + iteratorModel->ResetIterator(); + while(iteratorModel->HasNext()) + { + sel=(gqbQueryObject *)iteratorModel->Next(); + if(sel->getHaveJoins()) + { + truncAnd=true; + iteratorJoins=sel->createJoinsIterator(); + while(iteratorJoins->HasNext()) + { + if(first) + { + first=false; + sentence+= wxT("\n WHERE \n"); + } + tmp = (gqbQueryJoin *)iteratorJoins->Next(); + + if(tmp->getSourceQTable()->getAlias().length()>0) + sentence+= tmp->getSourceQTable()->getAlias() + wxT(".") +tmp->getSourceCol()+ wxT("\n") ; + else + sentence+= tmp->getSourceQTable()->getName() + wxT(".") +tmp->getSourceCol()+ wxT("\n"); + + switch(tmp->getKindofJoin()) + { + case _equally: + sentence+= wxT(" = "); + break; + } + + + if(tmp->getDestQTable()->getAlias().length()>0) + sentence+= tmp->getDestQTable()->getAlias() + wxT(".") +tmp->getDestCol()+wxT(" AND ")+ wxT("\n"); + else + sentence+= tmp->getDestQTable()->getName() + wxT(".") +tmp->getDestCol()+wxT(" AND ")+ wxT("\n"); + } + delete iteratorJoins; + } + } + delete iteratorModel; + + +gqbRestrictions *restrictions=model->getRestrictions(); + +if(truncAnd && (restrictions->restrictionsCount()<=0)) + sentence.Truncate(sentence.Length()-5); //remove last " AND " from joins if there isn't restrictions, only left white space + +if (!truncAnd && (restrictions->restrictionsCount()>0)) //never found a join + sentence+= wxT("\n WHERE \n"); + +//TODO: VALIDATE RESTRICTIONS +iteratorRestrictions=restrictions->createRestrictionsIterator(); +gqbQueryRestriction *r; +sentence+=wxT(" "); + +while(iteratorRestrictions->HasNext()) + { + r=(gqbQueryRestriction *)iteratorRestrictions->Next(); + sentence+=r->getLeft()+wxT(" ")+r->getRestriction()+wxT(" ")+r->getValue_s()+wxT(" ")+r->getConnector()+wxT(" \n"); + } +delete iteratorRestrictions; + + + +if(restrictions->restrictionsCount()>0){ + if(r->getConnector().Contains(wxT("AND"))){ + sentence.Truncate(sentence.Length()-5); + }else{ + sentence.Truncate(sentence.Length()-4); + } +} +} + + return sentence; +} + +gqbQueryRestriction* gqbController::addRestriction(){ + return model->addRestriction(); +} + +gqbQueryJoin* gqbController::addJoin(gqbQueryObject *sTable, gqbColumn *sColumn, gqbQueryObject *dTable, gqbColumn *dColumn, type_Join kind) +{ + return sTable->addJoin(sTable,dTable,sColumn,dColumn,kind); +} + + +void gqbController::removeJoin(gqbQueryJoin *join) +{ + join->getSourceQTable()->removeJoin(join,true); +} + + +void gqbController::setPointerMode(pointerMode pm) +{ + view->setPointerMode(pm); +} + +void gqbController::emptyModel(){ + view->emptyPanelsData(); + model->emptyAll(); +} Index: pgadmin/gqb/gqbBrowser.cpp =================================================================== --- pgadmin/gqb/gqbBrowser.cpp (revision 0) +++ pgadmin/gqb/gqbBrowser.cpp (revision 0) @@ -0,0 +1,95 @@ +#include "pgAdmin3.h" + +// wxWindows headers +#include +#include "wx/regex.h" +#include "wx/imaglist.h" + +//GQB headers +#include + +//REMOVE LATER added only for test purpose +#include +#include +#include +#include +#include +#include +#include + +#include "images/table-sm.xpm" +#include "images/namespace-sm.xpm" +#include "images/namespaces.xpm" +#include "images/database-sm.xpm" +#include "images/catalog-sm.xpm" +#include "images/catalogs.xpm" +#include "images/catalogobject-sm.xpm" + +BEGIN_EVENT_TABLE(gqbBrowser, wxTreeCtrl) +EVT_TREE_ITEM_ACTIVATED(GQB_BROWSER, gqbBrowser::OnItemActivated) +END_EVENT_TABLE() + +//TODO: Add images to tree + +//Constructor +gqbBrowser::gqbBrowser(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, gqbController *_controller) +: wxTreeCtrl(parent, id, pos, size, style) +{ + controller=_controller; + rootNode=NULL; + + //TODO: improve all functions that put data inside GQB Tree and order all. + + //Create normal images list of browser + imageList = new wxImageList(16, 16); + imageList->Add(wxIcon(database_sm_xpm)); + imageList->Add(wxIcon(namespace_sm_xpm)); + imageList->Add(wxIcon(table_sm_xpm)); + imageList->Add(wxIcon(namespaces_xpm)); + imageList->Add(wxIcon(catalogs_xpm)); + imageList->Add(wxIcon(catalog_sm_xpm)); + imageList->Add(wxIcon(catalogobject_sm_xpm)); + this->AssignImageList(imageList); +} + + +//Destructor +gqbBrowser::~gqbBrowser() +{ + //TODO: Research if this Really Delete Items or only remove and then create memory leaks? + this->DeleteAllItems(); //This remove and delete data inside tree's node +} + + +//Create root node +wxTreeItemId& gqbBrowser::createRoot(wxString &Name) +{ + rootNode=this->AddRoot(Name,0,0); + catalogsNode=this->AppendItem(rootNode,wxT("Catalogs"),4,4,NULL); + schemasNode=this->AppendItem(rootNode,wxT("Schemas"),3,3,NULL); + return rootNode; +} + + +//Event activated when user double click on a item of tree +void gqbBrowser::OnItemActivated(wxTreeEvent& event) +{ + wxTreeItemId itemId = event.GetItem(); + gqbTable *item = (gqbTable *) GetItemData(itemId); + + if ( item != NULL ) + { + controller->addTableToModel(item); + controller->getView()->Refresh(); + } +} + +void gqbBrowser::refreshTables(pgConn *connection){ + controller->emptyModel(); + this->DeleteAllItems(); //TODO: same as destructor + wxString *a = new wxString(wxT("Database Name Here")); + gqbDatabase *Data = new gqbDatabase(a,_gqbDatabase); + Data->createObjects(this,connection); + this->Expand(rootNode); +} + Index: pgadmin/gqb/gqbTable.cpp =================================================================== --- pgadmin/gqb/gqbTable.cpp (revision 0) +++ pgadmin/gqb/gqbTable.cpp (revision 0) @@ -0,0 +1,171 @@ +// App headers +#include "pgAdmin3.h" + +// wxWindows headers +#include + +//GQB headers +#include +#include +#include +#include + +gqbTable::gqbTable(gqbObject *parent, wxString *name, type_gqbObject type=_gqbTable): +gqbObjectCollection(name,type) +{ + this->setType(_gqbTable); + this->setName(name); + this->setOwner(parent); +} + + +gqbIteratorBase* gqbTable::createColumnsIterator() +{ + return createIterator(); +} + + +void gqbTable::addColumn(gqbColumn *column) +{ + this->addObject(column); +} + + +void gqbTable::createObjects(gqbBrowser *_tablesBrowser, pgConn *_conn, OID oidVal, wxTreeItemId parentNode) +{ + createColumns(_conn, _tablesBrowser, parentNode, oidVal); +} + + +wxString gqbTable::NumToStr(OID value) +{ + wxString result; + result.Printf(wxT("%lu"), (long)value); + return result; +} + + +void gqbTable::createColumns(pgConn *conn, gqbBrowser *tablesBrowser, wxTreeItemId parentNode, OID oidVal) +{ + + wxString systemRestriction; + if (!settings->GetShowSystemObjects()) + systemRestriction = wxT("\n AND attnum > 0"); + + wxString sql= + wxT("SELECT att.*, def.*, pg_catalog.pg_get_expr(def.adbin, def.adrelid) AS defval, CASE WHEN attndims > 0 THEN 1 ELSE 0 END AS isarray, format_type(ty.oid,NULL) AS typname, tn.nspname as typnspname, et.typname as elemtypname,\n") + wxT(" cl.relname, na.nspname, att.attstattarget, description, cs.relname AS sername, ns.nspname AS serschema,\n") + wxT(" (SELECT count(1) FROM pg_type t2 WHERE t2.typname=ty.typname) > 1 AS isdup, indkey"); + + if (conn->BackendMinimumVersion(7, 4)) + sql += + wxT(",\n") + wxT(" EXISTS(SELECT 1 FROM pg_constraint WHERE conrelid=att.attrelid AND contype='f'") + wxT(" AND att.attnum=ANY(conkey)) As isfk"); + + sql += wxT("\n") + wxT(" FROM pg_attribute att\n") + wxT(" JOIN pg_type ty ON ty.oid=atttypid\n") + wxT(" JOIN pg_namespace tn ON tn.oid=ty.typnamespace\n") + wxT(" JOIN pg_class cl ON cl.oid=attrelid\n") + wxT(" JOIN pg_namespace na ON na.oid=cl.relnamespace\n") + wxT(" LEFT OUTER JOIN pg_type et ON et.oid=ty.typelem\n") + wxT(" LEFT OUTER JOIN pg_attrdef def ON adrelid=attrelid AND adnum=attnum\n") + wxT(" LEFT OUTER JOIN pg_description des ON des.objoid=attrelid AND des.objsubid=attnum\n") + wxT(" LEFT OUTER JOIN (pg_depend JOIN pg_class cs ON objid=cs.oid AND cs.relkind='S') ON refobjid=attrelid AND refobjsubid=attnum\n") + wxT(" LEFT OUTER JOIN pg_namespace ns ON ns.oid=cs.relnamespace\n") + wxT(" LEFT OUTER JOIN pg_index pi ON pi.indrelid=attrelid AND indisprimary\n") + wxT(" WHERE attrelid = ") + + NumToStr(oidVal) + + systemRestriction + wxT("\n") + wxT(" AND attisdropped IS FALSE\n") + wxT(" ORDER BY attnum"); + + pgSet *columns= conn->ExecuteSet(sql); + if (columns) + { + while (!columns->Eof()) + { +/* TODO: delete when no more code needed + +column = new pgColumn(collection->GetTable(), columns->GetVal(wxT("attname"))); + +column->iSetAttTypId(columns->GetOid(wxT("atttypid"))); +column->iSetColNumber(columns->GetLong(wxT("attnum"))); +column->iSetIsArray(columns->GetBool(wxT("isarray"))); +column->iSetComment(columns->GetVal(wxT("description"))); +column->iSetSerialSequence(columns->GetVal(wxT("sername"))); +column->iSetSerialSchema(columns->GetVal(wxT("serschema"))); +column->iSetPkCols(columns->GetVal(wxT("indkey"))); +if (database->BackendMinimumVersion(7, 4)) +column->iSetIsFK(columns->GetBool(wxT("isfk"))); + +if (columns->GetBool(wxT("atthasdef"))) +column->iSetDefault(columns->GetVal(wxT("defval"))); +column->iSetStatistics(columns->GetLong(wxT("attstattarget"))); + +wxString storage=columns->GetVal(wxT("attstorage")); +column->iSetStorage( +storage == wxT("p") ? wxT("PLAIN") : +storage == wxT("e") ? wxT("EXTERNAL") : +storage == wxT("m") ? wxT("MAIN") : +storage == wxT("x") ? wxT("EXTENDED") : wxT("Unknown")); + +column->iSetTyplen(columns->GetLong(wxT("attlen"))); + +long typmod=columns->GetLong(wxT("atttypmod")); +pgDatatype dt(columns->GetVal(wxT("typnspname")), columns->GetVal(wxT("typname")), +columns->GetBool(wxT("isdup")), +columns->GetLong(wxT("attndims")), typmod); + +column->iSetTypmod(typmod); +column->iSetLength(dt.Length()); +column->iSetPrecision(dt.Precision()); +column->iSetRawTypename(dt.Name()); + +column->iSetVarTypename(dt.FullName()); +column->iSetQuotedTypename(dt.FullName()); + +column->iSetNotNull(columns->GetBool(wxT("attnotnull"))); +column->iSetQuotedFullTable(database->GetQuotedSchemaPrefix(columns->GetVal(wxT("nspname"))) ++ qtIdent(columns->GetVal(wxT("relname")))); +column->iSetTableName(columns->GetVal(wxT("relname"))); +column->iSetInheritedCount(columns->GetLong(wxT("attinhcount"))); +column->iSetIsLocal(columns->GetBool(wxT("attislocal"))); +column->iSetAttstattarget(columns->GetLong(wxT("attstattarget")));*/ + + if (tablesBrowser) + { +//Disable, Column SHOULDN'T be added to tree only use for debug purposes tablesBrowser->AppendItem(parentNode, columns->GetVal(wxT("attname")) , -1, -1); + wxString *tmpname= new wxString(columns->GetVal(wxT("attname"))); + gqbColumn *column = new gqbColumn(this,tmpname,_gqbColumn); + this->addColumn(column); + columns->MoveNext(); + } + else + break; + } + + delete columns; + } +} + + +//work as a synonym for function +int gqbTable::countCols() +{ + return this->countObjects(); +} + + +//work as a synonym for function & return correct type +gqbColumn* gqbTable::getColumnAtIndex(int index) +{ + return (gqbColumn *)this->getObjectAtIndex(index); +} + + +int gqbTable::indexColumn(gqbColumn *col) +{ + return this->indexObject(col); +} Index: pgadmin/gqb/gqbArrayCollection.cpp =================================================================== --- pgadmin/gqb/gqbArrayCollection.cpp (revision 0) +++ pgadmin/gqb/gqbArrayCollection.cpp (revision 0) @@ -0,0 +1,135 @@ +#include "pgAdmin3.h" + +// wxWindows headers +#include + +#include +#include + +//Destructor +gqbArrayCollection::~gqbArrayCollection() +{ + WX_CLEAR_ARRAY(gqbArray); +} + + +//Add item to array +void gqbArrayCollection::addItem(gqbObject *item) +{ + gqbArray.Add(item); +} + + +//Remove item from array but don't delete it. +void gqbArrayCollection::removeItem(gqbObject *item) +{ + gqbArray.Remove(item); +} + + +//Create an iterator for the objects inside the array +gqbIteratorBase* gqbArrayCollection::createIterator() +{ + return (new gqbArrayIterator(&gqbArray)); +} + + +//Return the number of elements inside the array +int gqbArrayCollection::count() +{ + return gqbArray.Count(); +} + + +//Return true if an element pointer is found inside array +bool gqbArrayCollection::existsObject(gqbObject *item) +{ + gqbObject *found=NULL; + int size=gqbArray.GetCount(); + for(int i=0;iItem(position); + position++; + return obj; +} + + +//Return true if the array has more elements to return +bool gqbArrayIterator::HasNext() +{ + int size=internalArray->GetCount(); + if( (size>0) && (position<=(size-1)) ) + return true; + else + return false; +} + + +void gqbArrayIterator::ResetIterator() +{ + position=0; +} + Index: pgadmin/gqb/gqbRestGridTable.cpp =================================================================== --- pgadmin/gqb/gqbRestGridTable.cpp (revision 0) +++ pgadmin/gqb/gqbRestGridTable.cpp (revision 0) @@ -0,0 +1,338 @@ +// App headers +#include "pgAdmin3.h" + +// wxWindows headers +#include +#include +#include +#include + + +//GQB headers +#include +#include +#include +#include "gqb/gqbViewPanels.h" + + +gqbRestGridTable::gqbRestGridTable(gqbRestrictions *_restrictions): +wxGridTableBase(){ + restrictions=_restrictions; +} + + +gqbRestGridTable::~gqbRestGridTable(){ +/* not exceptions??? + if(restrictions) + delete restrictions; + */ +} + +int gqbRestGridTable::GetNumberRows(){ + return (restrictions->restrictionsCount()); +} + +int gqbRestGridTable::GetNumberCols(){ + return 4; +} + + +//TODO: improve +bool gqbRestGridTable::IsEmptyCell( int row, int col ){ + + int count=restrictions->restrictionsCount(); + if(row+1 <= count) + return false; + else + return true; +} + +wxString gqbRestGridTable::GetValue( int row, int col ){ + switch(col){ + case 0: + return ((gqbQueryRestriction*)restrictions->getRestrictionAt(row))->getLeft(); //TODO: include table alias + break; + case 1: + return ((gqbQueryRestriction*)restrictions->getRestrictionAt(row))->getRestriction(); + break; + case 2: + return ((gqbQueryRestriction*)restrictions->getRestrictionAt(row))->getValue_s(); + break; + case 3: + return ((gqbQueryRestriction*)restrictions->getRestrictionAt(row))->getConnector(); + break; + }; + + return wxT(""); +} + +wxString gqbRestGridTable::GetColLabelValue( int col){ + switch(col){ + case 0: + return wxT("Restricted Value"); + break; + case 1: + return wxT("Restriction"); + break; + case 2: + return wxT("Value"); + break; + case 3: + return wxT("Connector"); + break; + }; + return wxT(""); +} + +void gqbRestGridTable::SetValue( int row, int col, const wxString& value ){ + //Do nothing values cannot be edited on this model + switch(col){ + case 0: + ((gqbQueryRestriction*)restrictions->getRestrictionAt(row))->setLeft(value); + break; + case 1: + ((gqbQueryRestriction*)restrictions->getRestrictionAt(row))->setRestriction(value); + break; + case 2: + ((gqbQueryRestriction*)restrictions->getRestrictionAt(row))->setValue_s(value); + break; + case 3: + ((gqbQueryRestriction*)restrictions->getRestrictionAt(row))->setConnector(value); + break; + } +} + + +void gqbRestGridTable::AppendItem(gqbQueryRestriction *item){ +bool notify=true; + +restrictions->addRestriction(item); + +if (notify && GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_INSERTED, + (restrictions->restrictionsCount()-1), + 1 ); + GetView()->ProcessTableMessage( msg ); + } + +} + + +bool gqbRestGridTable::DeleteRows(size_t pos = 0, size_t numRows = 1){ + if(pos>=0 && numRows==1){ + gqbQueryRestriction *r=restrictions->getRestrictionAt(pos); + restrictions->removeRestriction(r); + if ( GetView() ) //Notify Grid about the change + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_DELETED, + pos, //TODO: check this is necesaary ??? //Because row(0) it's title + 1 ); + GetView()->ProcessTableMessage( msg ); + } + + delete r; + return true; + } + else + return false; +} + + +//removes all items from gqbGridTable +void gqbRestGridTable::emptyTableData(){ + + int count=restrictions->restrictionsCount(); + restrictions->deleteAllRestrictions(); + + if ( GetView() ) //Notify Grid about the change + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_DELETED, + 1, //TODO: check this is necesaary ??? //Because row(0) it's title + count); + GetView()->ProcessTableMessage( msg ); + } +} + + +// +// Cell rendering utilities classes +// + + +void wxGridCellComboBoxRenderer::Draw(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, + const wxRect& rectCell, int row, int col, bool isSelected) +{ + wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); + // first calculate button size + // don't draw outside the cell + int nButtonWidth = 17; + if (rectCell.height < 2) return; + wxRect rectButton; + rectButton.x = rectCell.x + rectCell.width - nButtonWidth; + rectButton.y = rectCell.y + 1; + int cell_rows, cell_cols; + attr.GetSize(&cell_rows, &cell_cols); + rectButton.width = nButtonWidth; + if (cell_rows == 1) + rectButton.height = rectCell.height-2; + else + rectButton.height = nButtonWidth; + + SetTextColoursAndFont(grid, attr, dc, isSelected); + int hAlign, vAlign; + attr.GetAlignment(&hAlign, &vAlign); + // leave room for button + wxRect rect = rectCell; + rect.SetWidth(rectCell.GetWidth() - rectButton.GetWidth()-2); + rect.Inflate(-1); + grid.DrawTextRectangle(dc, grid.GetCellValue(row, col), rect, hAlign, vAlign); + + // don't bother drawing if the cell is too small + if (rectButton.height < 4 || rectButton.width < 4) return; + // draw 3-d button + wxColour colourBackGround = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); + dc.SetBrush(wxBrush(colourBackGround, wxSOLID)); + dc.SetPen(wxPen(colourBackGround, 1, wxSOLID)); + dc.DrawRectangle(rectButton); + dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT), 1, wxSOLID)); + dc.DrawLine(rectButton.GetLeft(), rectButton.GetBottom(), + rectButton.GetRight(), rectButton.GetBottom()); + dc.DrawLine(rectButton.GetRight(), rectButton.GetBottom(), + rectButton.GetRight(), rectButton.GetTop()-1); + dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW), + 1, wxSOLID)); + dc.DrawLine(rectButton.GetLeft()+1, rectButton.GetBottom()-1, + rectButton.GetRight()-1, rectButton.GetBottom()-1); + dc.DrawLine(rectButton.GetRight()-1, rectButton.GetBottom()-1, + rectButton.GetRight()-1, rectButton.GetTop()); + dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT), + 1, wxSOLID)); + dc.DrawLine(rectButton.GetRight()-2, rectButton.GetTop()+1, + rectButton.GetLeft()+1, rectButton.GetTop()+1); + dc.DrawLine(rectButton.GetLeft()+1, rectButton.GetTop()+1, + rectButton.GetLeft()+1, rectButton.GetBottom()-1); + // Draw little triangle + int nTriWidth = 7; + int nTriHeight = 4; + wxPoint point[3]; + point[0] = wxPoint(rectButton.GetLeft() + (rectButton.GetWidth()-nTriWidth)/2, + rectButton.GetTop()+(rectButton.GetHeight()-nTriHeight)/2); + point[1] = wxPoint(point[0].x+nTriWidth-1, point[0].y); + point[2] = wxPoint(point[0].x+3, point[0].y+nTriHeight-1); + dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT), wxSOLID)); + dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT), 1, wxSOLID)); + dc.DrawPolygon(3, point); + if (m_border == wxLAYOUT_TOP) + { + dc.SetPen(wxPen(*wxBLACK, 1, wxDOT)); + dc.DrawLine(rectCell.GetRight(), rectCell.GetTop(), + rectCell.GetLeft(), rectCell.GetTop()); + } +} + +void wxGridCellButtonRenderer::Draw(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, + const wxRect& rectCell, int row, int col, bool isSelected) +{ + wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected); + // first calculate button size + // don't draw outside the cell + int nButtonWidth = 17; + if (rectCell.height < 2) return; + wxRect rectButton; + rectButton.x = rectCell.x + rectCell.width - nButtonWidth; + rectButton.y = rectCell.y + 1; + int cell_rows, cell_cols; + attr.GetSize(&cell_rows, &cell_cols); + rectButton.width = nButtonWidth; + if (cell_rows == 1) + rectButton.height = rectCell.height-2; + else + rectButton.height = nButtonWidth; + + SetTextColoursAndFont(grid, attr, dc, isSelected); + int hAlign, vAlign; + attr.GetAlignment(&hAlign, &vAlign); + // leave room for button + wxRect rect = rectCell; + rect.SetWidth(rectCell.GetWidth() - rectButton.GetWidth()-2); + rect.Inflate(-1); + grid.DrawTextRectangle(dc, grid.GetCellValue(row, col), rect, hAlign, vAlign); + + // don't bother drawing if the cell is too small + if (rectButton.height < 4 || rectButton.width < 4) return; + // draw 3-d button + wxColour colourBackGround = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); + dc.SetBrush(wxBrush(colourBackGround, wxSOLID)); + dc.SetPen(wxPen(colourBackGround, 1, wxSOLID)); + dc.DrawRectangle(rectButton); + dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT), 1, wxSOLID)); + dc.DrawLine(rectButton.GetLeft(), rectButton.GetBottom(), + rectButton.GetRight(), rectButton.GetBottom()); + dc.DrawLine(rectButton.GetRight(), rectButton.GetBottom(), + rectButton.GetRight(), rectButton.GetTop()-1); + dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW), + 1, wxSOLID)); + dc.DrawLine(rectButton.GetLeft()+1, rectButton.GetBottom()-1, + rectButton.GetRight()-1, rectButton.GetBottom()-1); + dc.DrawLine(rectButton.GetRight()-1, rectButton.GetBottom()-1, + rectButton.GetRight()-1, rectButton.GetTop()); + dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT), + 1, wxSOLID)); + dc.DrawLine(rectButton.GetRight()-2, rectButton.GetTop()+1, + rectButton.GetLeft()+1, rectButton.GetTop()+1); + dc.DrawLine(rectButton.GetLeft()+1, rectButton.GetTop()+1, + rectButton.GetLeft()+1, rectButton.GetBottom()-1); + // Draw little plus symbol + dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT), wxSOLID)); + dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT), 1, wxSOLID)); + int nPlusWidth = 7; + int nPlusHeight = 7; + wxPoint point[4]; + point[0] = wxPoint(rectButton.GetLeft() + (rectButton.GetWidth()-nPlusWidth)/2, rectButton.GetTop()+(rectButton.GetHeight()/2)-1); + point[1] = wxPoint(point[0].x+nPlusWidth, point[0].y); + point[2] = wxPoint(rectButton.GetLeft() + (rectButton.GetWidth())/2, rectButton.GetTop()+(rectButton.GetHeight()-nPlusHeight)/2); + point[3] = wxPoint(point[2].x,point[2].y+nPlusHeight); + dc.DrawLine(point[0],point[1]); + dc.DrawLine(point[2],point[3]); + + if (m_border == wxLAYOUT_TOP) + { + dc.SetPen(wxPen(*wxBLACK, 1, wxDOT)); + dc.DrawLine(rectCell.GetRight(), rectCell.GetTop(), + rectCell.GetLeft(), rectCell.GetTop()); + } +} + + + +// +// Cell editing utilities classes +// +dxGridCellSizedChoiceEditor::dxGridCellSizedChoiceEditor(const wxArrayString& choices, bool allowOthers) +:wxGridCellChoiceEditor(choices,allowOthers) +{ +} + +dxGridCellSizedChoiceEditor::dxGridCellSizedChoiceEditor(size_t count, const wxString choices[], bool allowOthers) +:wxGridCellChoiceEditor(count,choices, allowOthers) +{ +} + +wxGridCellEditor *dxGridCellSizedChoiceEditor::Clone() const +{ + dxGridCellSizedChoiceEditor *editor = new + dxGridCellSizedChoiceEditor(); + return editor; +} + +void dxGridCellSizedChoiceEditor::Show(bool show, wxGridCellAttr *attr) +{ + wxGridCellEditor::Show(show, attr); +} + + + Index: pgadmin/gqb/gqbCollection.cpp =================================================================== --- pgadmin/gqb/gqbCollection.cpp (revision 0) +++ pgadmin/gqb/gqbCollection.cpp (revision 0) @@ -0,0 +1,78 @@ +// App headers +#include "pgAdmin3.h" + +// wxWindows headers +#include +#include +#include + +gqbCollection::gqbCollection(gqbCollectionBase *collectionBase) +{ + collection=collectionBase; +} + + +gqbCollection::~gqbCollection() +{ + if(collection) + delete collection; +} + + +void gqbCollection::addItem(gqbObject *item) +{ + collection->addItem(item); +} + + +void gqbCollection::removeItem(gqbObject *item) +{ + collection->removeItem(item); +} + + +gqbIteratorBase* gqbCollection::createIterator() +{ + return collection->createIterator(); +} + + +int gqbCollection::count() +{ + return collection->count(); +} + + +bool gqbCollection::existsObject(gqbObject *item) +{ + return collection->existsObject(item); +} + + +gqbObject* gqbCollection::getItemAt(int index) +{ + return collection->getItemAt(index); +} + + +//Remove all items from collection without deleting each one. +void gqbCollection::removeAll() +{ + collection->removeAll(); +} + + +void gqbCollection::deleteAll() +{ + collection->deleteAll(); +} + + +int gqbCollection::getIndex(gqbObject *item) +{ + return collection->getIndex(item); +} + +void gqbCollection::insertAtIndex(gqbObject *item, int index){ + collection->insertAtIndex(item,index); +} Index: pgadmin/gqb/gqbColumn.cpp =================================================================== --- pgadmin/gqb/gqbColumn.cpp (revision 0) +++ pgadmin/gqb/gqbColumn.cpp (revision 0) @@ -0,0 +1,20 @@ +// App headers +#include "pgAdmin3.h" + +// wxWindows headers +#include + +//GQB headers +#include +#include +#include +#include +#include + +gqbColumn::gqbColumn(gqbObject *parent, wxString *name, type_gqbObject type=_gqbColumn): +gqbObject(name, type) +{ + this->setType(_gqbColumn); + this->setName(name); + this->setOwner(parent); +} Index: pgadmin/gqb/gqbGridTable.cpp =================================================================== --- pgadmin/gqb/gqbGridTable.cpp (revision 0) +++ pgadmin/gqb/gqbGridTable.cpp (revision 0) @@ -0,0 +1,283 @@ +// App headers +#include "pgAdmin3.h" + +// wxWindows headers +#include +#include +#include +#include + + +//GQB headers +#include +#include +#include + + +gqbGridTable::gqbGridTable(gqbObjsArray *position, gqbObjsArray *parent, wxArrayString *alias): +wxGridTableBase(){ + colsPosition=position; + colsParents=parent; + columnsAlias=alias; + //TODO: replace above pointers array with local variable if possible or research what it's causing bug in destructor??? + +} + +gqbGridTable::~gqbGridTable(){ +/* +Option 1: gives an exception +colsPosition->Empty(); + colsParents->Empty(); + +Option 2: gives an exception too +if(colsPosition) + delete colsPosition; +if(colsParents) + delete colsParents; + */ +} + +int gqbGridTable::GetNumberRows(){ + return (colsPosition->GetCount()); +} + + +int gqbGridTable::GetNumberCols(){ + + return 3; +} + +bool gqbGridTable::IsEmptyCell( int row, int col ){ + + int count=colsParents->GetCount(); + if(row+1 <= count) + return false; + else + return true; +} + +wxString gqbGridTable::GetValue( int row, int col ){ + switch(col){ + case 0: + return ((gqbQueryObject*)colsParents->Item(row))->getName(); //TODO if table have synonym this should be used here + break; + case 1: + return ((gqbColumn*)colsPosition->Item(row))->getName(); + break; + case 2: + return columnsAlias->Item(row); + break; + }; + return wxT(""); +} + +wxString gqbGridTable::GetColLabelValue( int col){ + switch(col){ + case 0: + return wxT("Table Name"); + break; + case 1: + return wxT("Column Name"); + break; + case 2: + return wxT("Column Display Name"); + break; + }; + return wxT(""); +} + +void gqbGridTable::SetValue( int row, int col, const wxString& value ){ + //Do nothing on values that cannot be edited on this model [Column & Table Name] + switch(col){ + case 2: + columnsAlias->Item(row)=value; + break; + }; +} + +void* gqbGridTable::GetValueAsCustom( int row, int col, const wxString& typeName ){ + switch(col){ + case 0: + return (void *)&colsParents->Item(row); + break; + case 1: + return (void *)&colsPosition->Item(row); + break; + case 2: + //return NULL; + break; + }; + return NULL; +} + +void gqbGridTable::SetValueAsCustom( int row, int col, const wxString& typeName, void* value ){ + switch(col){ + case 0: + colsParents->Add(((gqbQueryObject*)value)); + break; + case 1: + colsPosition->Add(((gqbColumn*)value)); + /* case 2: + TODO: this function it's needed or can be deleted?*/ + + }; +} + + + +void gqbGridTable::AppendItem(int col, gqbObject *item){ +bool notify=false; + switch(col){ + case 0: + colsParents->Add(item); + break; + case 1: + colsPosition->Add(item); + notify=true; + break; + case 2: + columnsAlias->Add(wxT("")); + break; + }; + +if (notify && GetView() ) + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_INSERTED, + (colsParents->GetCount()-1), + 1 ); + GetView()->ProcessTableMessage( msg ); + } + +} + + +//Remove a column at the grid +bool gqbGridTable::removeRow(gqbObject *itemTable, gqbObject *itemColumn){ + bool found=false; + int i,size=colsPosition->GetCount(); + + for(i=0;iItem(i)==itemTable && colsPosition->Item(i)==itemColumn) + { + found=true; + break; + } + } + + if(found){ + colsParents->RemoveAt(i); + colsPosition->RemoveAt(i); + columnsAlias->RemoveAt(i); + + if ( GetView() ) //Notify Grid about the change + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_DELETED, + i+1, //TODO: check this is necesaary ??? //Because row(0) it's title + 1 ); + GetView()->ProcessTableMessage( msg ); + } + } + +return found; +} + + +void gqbGridTable::removeAllRows(gqbObject *itemTable){ + + int size=colsParents->GetCount(); + for(int i=(size-1);i>=0;i--) + { + if (colsParents->Item(i)==itemTable){ + colsParents->RemoveAt(i); + colsPosition->RemoveAt(i); + columnsAlias->RemoveAt(i); + + if ( GetView() ) //Notify Grid about the change + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_DELETED, + i+1, //TODO: check this is necesaary ??? //Because row(0) it's title + 1 ); + GetView()->ProcessTableMessage( msg ); + } + } + } +} + +void gqbGridTable::changesPositions(int sPos, int dPos){ + +int size=colsPosition->GetCount(); +gqbObject *tmpTable=NULL, *tmpColumn=NULL; +wxString tmpAlias = wxT(""); + +if( (sPos>=0 && sPos < size) && (dPos>=0 && dPos < size) ) + { + tmpTable=colsParents->Item(sPos); + tmpColumn=colsPosition->Item(sPos); + tmpAlias=columnsAlias->Item(sPos); + + colsParents->Item(sPos)=colsParents->Item(dPos); + colsPosition->Item(sPos)=colsPosition->Item(dPos); + columnsAlias->Item(sPos)=columnsAlias->Item(dPos); + colsParents->Item(dPos)=tmpTable; + colsPosition->Item(dPos)=tmpColumn; + columnsAlias->Item(dPos)=tmpAlias; + } + + wxGridTableMessage msg( this, + wxGRIDTABLE_REQUEST_VIEW_GET_VALUES, + sPos, + 1 ); + GetView()->ProcessTableMessage( msg ); + +} + + + +//TODO: optimize this functions & related buttons events at gqbView because works but are a mess. +//Change a single row or a range to one pos up or down (but no more than one position) +void gqbGridTable::changesRangeOnePos(int topPos, int bottomPos, int newTop){ + //Eliminate side effect of zero base array on calculations, but carefull newTop still it's zero based + topPos++; + bottomPos++; + int sizeRange=bottomPos-(topPos-1), size=GetNumberRows(); + if(topPos>newTop){ //Go Down + //Only if the movement don't create an overflow + if( (topPos > 1) && ((newTop+sizeRange) < size) ){ + for(int i=newTop ; i < (newTop+sizeRange) ; i++){ + changesPositions(i,i+1); + } + } + + }else{ //Go Up + //Only if the movement don't create an overflow + if( (bottomPos < size) && ((newTop+sizeRange) <= size) ){ + for(int i=(newTop+sizeRange-1) ; i >= newTop ; i--){ //Go Up Down + changesPositions(i-1,i); + } + } + } +} + + +//removes all items from gqbGridTable +void gqbGridTable::emptyTableData(){ + + int count=colsPosition->GetCount(); + colsPosition->Empty(); + colsParents->Empty(); + columnsAlias->Empty(); + + if ( GetView() ) //Notify Grid about the change + { + wxGridTableMessage msg( this, + wxGRIDTABLE_NOTIFY_ROWS_DELETED, + 1, //TODO: check this is necesaary ??? //Because row(0) it's title + count); + GetView()->ProcessTableMessage( msg ); + } +} + Index: pgadmin/gqb/gqbModel.cpp =================================================================== --- pgadmin/gqb/gqbModel.cpp (revision 0) +++ pgadmin/gqb/gqbModel.cpp (revision 0) @@ -0,0 +1,75 @@ +#include "pgAdmin3.h" + +// wxWindows headers +#include +#include +#include + +gqbModel::gqbModel(): +wxObject() +{ +//here store all queryObjects +//TODO: allow different names for each model + queryCollection = new gqbQueryObjs(new wxString(wxT("MODEL1"))); + restrictions = new gqbRestrictions(); + columnsAlias = new wxArrayString(); +} + + +//TODO: check this destructoy, if destroy model this destroy table used by model??? +gqbModel::~gqbModel() +{ + if(queryCollection) + delete queryCollection; +// WX_CLEAR_ARRAY(colsPosition); + //don't owns objects only remove then in both + colsPosition.Empty(); + colsParents.Empty(); + if(columnsAlias) + delete columnsAlias; +//TODO: delete restrictions +} + + +void gqbModel::addTable(gqbTable *table) +{ +//get a table but introduce a QueryObject + gqbQueryObject *tmp = new gqbQueryObject(table); +//now use insert the new object in the collection of the model + queryCollection->addTable(tmp); +} + + +gqbIteratorBase* gqbModel::createQueryIterator() +{ + return queryCollection->createQueryIterator(); +} + + +void gqbModel::deleteTable(gqbQueryObject *modelTable) +{ + if(modelTable) + { + queryCollection->removeTable(modelTable); + delete modelTable; + modelTable=NULL; + } +} + +int gqbModel::tablesCount(){ + return queryCollection->tablesCount(); +} + +void gqbModel::emptyAll(){ + colsPosition.Empty(); + colsParents.Empty(); + queryCollection->removeAllQueryObjs(); + +} + +gqbQueryRestriction* gqbModel::addRestriction(){ + gqbQueryRestriction *r = new gqbQueryRestriction(); + restrictions->addRestriction(r); + return r; +} + Index: pgadmin/gqb/gqbSchema.cpp =================================================================== --- pgadmin/gqb/gqbSchema.cpp (revision 0) +++ pgadmin/gqb/gqbSchema.cpp (revision 0) @@ -0,0 +1,127 @@ +// App headers +#include "pgAdmin3.h" + +// wxWindows headers +#include + +//GQB headers +#include +#include +#include +#include + +gqbSchema::gqbSchema(gqbObject *parent, wxString *name, type_gqbObject type=_gqbSchema): +gqbObject(name,type) +{ + this->setType(_gqbSchema); + this->setName(name); + this->setOwner(parent); +} + + +//TODO: don't declare OID inside gqbBrowsear instead use the pgadmin one +void gqbSchema::createObjects(gqbBrowser *_tablesBrowser, pgConn *_conn, OID oidVal, wxTreeItemId parentNode, int _indexImage) +{ + createTables(_conn, _tablesBrowser, parentNode, oidVal, _indexImage); +} + + +wxString gqbSchema::NumToStr(OID value) +{ + wxString result; + result.Printf(wxT("%lu"), (long)value); + return result; +} + + +void gqbSchema::createTables(pgConn *conn, gqbBrowser *tablesBrowser, wxTreeItemId parentNode, OID oidVal, int indexImage) +{ + + wxString query; + wxString restriction=wxT(""); + + if (conn->BackendMinimumVersion(8, 0)) + { + query= wxT("SELECT rel.oid, relname, rel.reltablespace AS spcoid, spcname, pg_get_userbyid(relowner) AS relowner, relacl, relhasoids, ") + wxT("relhassubclass, reltuples, description, conname, conkey,\n") + wxT(" EXISTS(select 1 FROM pg_trigger\n") + wxT(" JOIN pg_proc pt ON pt.oid=tgfoid AND pt.proname='logtrigger'\n") + wxT(" JOIN pg_proc pc ON pc.pronamespace=pt.pronamespace AND pc.proname='slonyversion'\n") + wxT(" WHERE tgrelid=rel.oid) AS isrepl\n"); + if (conn->BackendMinimumVersion(8, 2)) + query += wxT(", substring(array_to_string(reloptions, ',') from 'fillfactor=([0-9]*)') AS fillfactor \n"); + query += wxT(" FROM pg_class rel\n") + wxT(" LEFT OUTER JOIN pg_tablespace ta on ta.oid=rel.reltablespace\n") + wxT(" LEFT OUTER JOIN pg_description des ON (des.objoid=rel.oid AND des.objsubid=0)\n") + wxT(" LEFT OUTER JOIN pg_constraint c ON c.conrelid=rel.oid AND c.contype='p'\n") + wxT(" WHERE relkind IN ('r','s','t') AND relnamespace = ") + NumToStr(oidVal) + wxT("\n") + + restriction + + wxT(" ORDER BY relname"); + } + else + { + query= wxT("SELECT rel.oid, relname, pg_get_userbyid(relowner) AS relowner, relacl, relhasoids, ") + wxT("relhassubclass, reltuples, description, conname, conkey,\n") + wxT(" EXISTS(select 1 FROM pg_trigger\n") + wxT(" JOIN pg_proc pt ON pt.oid=tgfoid AND pt.proname='logtrigger'\n") + wxT(" JOIN pg_proc pc ON pc.pronamespace=pt.pronamespace AND pc.proname='slonyversion'\n") + wxT(" WHERE tgrelid=rel.oid) AS isrepl\n") + wxT(" FROM pg_class rel\n") + wxT(" LEFT OUTER JOIN pg_description des ON (des.objoid=rel.oid AND des.objsubid=0)\n") + wxT(" LEFT OUTER JOIN pg_constraint c ON c.conrelid=rel.oid AND c.contype='p'\n") + wxT(" WHERE relkind IN ('r','s','t') AND relnamespace = ") + NumToStr(oidVal) + wxT("\n") + + restriction + + wxT(" ORDER BY relname"); + } + + pgSet *tables = conn->ExecuteSet(query); + wxTreeItemId parent; + + if (tables) + { + while (!tables->Eof()) + { +/*TODO: delete when no more code needed + +table = new pgTable(collection->GetSchema(), tables->GetVal(wxT("relname"))); + +table->iSetOid(tables->GetOid(wxT("oid"))); +table->iSetOwner(tables->GetVal(wxT("relowner"))); +table->iSetAcl(tables->GetVal(wxT("relacl"))); +if (collection->GetConnection()->BackendMinimumVersion(8, 0)) +{ +if (tables->GetOid(wxT("spcoid")) == 0) +table->iSetTablespaceOid(collection->GetDatabase()->GetTablespaceOid()); +else +table->iSetTablespaceOid(tables->GetOid(wxT("spcoid"))); + +if (tables->GetVal(wxT("spcname")) == wxEmptyString) +table->iSetTablespace(collection->GetDatabase()->GetTablespace()); +else +table->iSetTablespace(tables->GetVal(wxT("spcname"))); +} +table->iSetComment(tables->GetVal(wxT("description"))); +table->iSetHasOids(tables->GetBool(wxT("relhasoids"))); +table->iSetEstimatedRows(tables->GetDouble(wxT("reltuples"))); +if (collection->GetConnection()->BackendMinimumVersion(8, 2)) { +table->iSetFillFactor(tables->GetVal(wxT("fillfactor"))); +} +table->iSetHasSubclass(tables->GetBool(wxT("relhassubclass"))); +table->iSetPrimaryKeyName(tables->GetVal(wxT("conname"))); +table->iSetIsReplicated(tables->GetBool(wxT("isrepl"))); +wxString cn=tables->GetVal(wxT("conkey")); +cn=cn.Mid(1, cn.Length()-2); +table->iSetPrimaryKeyColNumbers(cn);*/ + + wxString *tmpname= new wxString(tables->GetVal(wxT("relname"))); + gqbTable *table = new gqbTable(this,tmpname,_gqbTable); + parent=tablesBrowser->AppendItem(parentNode, tables->GetVal(wxT("relname")) , indexImage, indexImage, table); + //Create columns inside this table. + table->createObjects(tablesBrowser,conn,tables->GetOid(wxT("oid")),parent); + + tables->MoveNext(); + } + + delete tables; + } +}