Index: src/ctl/ctlSQLResult.cpp
===================================================================
--- src/ctl/ctlSQLResult.cpp	(revision 4990)
+++ src/ctl/ctlSQLResult.cpp	(working copy)
@@ -11,6 +11,7 @@
 
 // wxWindows headers
 #include <wx/wx.h>
+#include <wx/clipbrd.h>
 
 #include "pgConn.h"
 #include "ctl/ctlSQLResult.h"
@@ -20,10 +21,19 @@
 
 
 ctlSQLResult::ctlSQLResult(wxWindow *parent, pgConn *_conn, wxWindowID id, const wxPoint& pos, const wxSize& size)
-: wxListView(parent, id, pos, size, wxLC_REPORT | wxSUNKEN_BORDER)
+: wxGrid(parent, id, pos, size, wxWANTS_CHARS|wxVSCROLL|wxHSCROLL)
 {
     conn=_conn;
     thread=0;
+    CreateGrid(0, 0);
+    EnableEditing(false);
+    SetSizer(new wxBoxSizer(wxVERTICAL));
+
+    wxFont fntLabel(settings->GetSystemFont());
+    fntLabel.SetWeight(wxBOLD);
+    SetLabelFont(fntLabel);
+
+    Connect(wxID_ANY, wxEVT_GRID_RANGE_SELECT, wxGridRangeSelectEventHandler(ctlSQLResult::OnGridSelect));
 }
 
 
@@ -40,12 +50,6 @@
 }
 
 
-void ctlSQLResult::SelectAll()
-{
-	for (int i = 0; i < GetItemCount(); i++)
-		Select(i);
-}
-
 bool ctlSQLResult::Export()
 {
     if (rowsRetrieved>0 || (thread && thread->DataSet()->NumRows() > 0))
@@ -66,23 +70,46 @@
 
 wxString ctlSQLResult::GetExportLine(int row)
 {
-    if (GetColumnCount() <= 1)
+    return GetExportLine(row, 0, GetNumberCols() - 1);
+}
+
+wxString ctlSQLResult::GetExportLine(int row, int col1, int col2)
+{
+    wxArrayInt cols;
+    wxString str;
+    int i;
+
+    if (col2 < col1)
+        return str;
+
+    cols.Alloc(col2 - col1 + 1);
+    for (i = col1; i <= col2; i++) {
+        cols.Add(i);
+    }
+
+    return GetExportLine(row, cols);
+}
+
+
+wxString ctlSQLResult::GetExportLine(int row, wxArrayInt cols)
+{
+    if (GetNumberCols() <= 1)
         return GetItemText(row);
 
     wxString str;
-    int col;
-    for (col=1 ; col < GetColumnCount() ; col++)
+    unsigned int col;
+    for (col=0 ; col < cols.Count() ; col++)
     {
-        if (col > 1)
+        if (col > 0)
             str.Append(settings->GetCopyColSeparator());
 
-        wxString text=GetItemText(row, col);
+        wxString text = GetCellValue(row, cols[col]);
 
 		bool needQuote  = false;
 		if (settings->GetCopyQuoting() == 1)
 		{
 			/* Quote strings only */
-			switch (colTypClasses.Item(col))
+			switch (colTypClasses.Item(cols[col]))
 			{
 			case PGTYPCLASS_NUMERIC:
 			case PGTYPCLASS_BOOL:
@@ -112,20 +139,27 @@
 
     colSizes.Empty();
     colHeaders.Empty();
+    int num;
+
+#if 0
+    /* Seems pointless to me... */
     int i;
-    wxListItem item;
-    item.SetMask(wxLIST_MASK_TEXT|wxLIST_MASK_WIDTH);
-
-    for (i=0 ; i < GetColumnCount() ; i++)
+    for (i=0 ; i < GetNumberCols() ; i++)
     {
-        GetColumn(i, item);
-        colHeaders.Add(item.GetText());
-        colSizes.Add(item.GetWidth());
+        colHeaders.Add(GetColLabelValue(i));
+        colSizes.Add(GetColSize(i));
     }
+#endif
 
-    ClearAll();
+    num = GetNumberRows();
+    if (num)
+        DeleteRows(0, num);
+    num = GetNumberCols();
+    if (num)
+        DeleteCols(0, num);
 
     rowsRetrieved=0;
+    maxRows = 0;
     colNames.Empty();
     colTypes.Empty();
     colTypClasses.Empty();
@@ -165,22 +199,17 @@
 
     if (!rowsRetrieved)
     {
-        int w, h;
-        if (colSizes.GetCount() == 1)
-            w = colSizes.Item(0);
-        else
-            GetSize(&w, &h);
-
         colNames.Add(thread->DataSet()->ColName(0));
         colTypes.Add(wxT(""));
         colTypClasses.Add(0L);
 
 
-        InsertColumn(0, thread->DataSet()->ColName(0), wxLIST_FORMAT_LEFT, w);
+        SetColLabelValue(0, thread->DataSet()->ColName(0));
+        SetColLabelAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
 
         while (!thread->DataSet()->Eof())
         {
-            InsertItem(rowsRetrieved, thread->DataSet()->GetVal(0));
+            SetCellValue(rowsRetrieved, 0, thread->DataSet()->GetVal(0));
             rowsRetrieved++;
             thread->DataSet()->MoveNext();
         }
@@ -207,8 +236,16 @@
         colTypClasses.Add(0L);
 
         Freeze();
-        InsertColumn(0, _("Row"), wxLIST_FORMAT_RIGHT, 30);
-        colNames.Add(wxT("Row"));
+        
+        if (!GetTable()) {
+            SetTable(new sqlResultTable(), true);
+        }
+        GetTable()->AppendCols(nCols);
+        SetColLabelAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
+        if (maxRows)
+            GetTable()->AppendRows(maxRows);
+        else
+            GetTable()->AppendRows(NumRows());
 
         size_t hdrIndex=0;
 
@@ -220,7 +257,7 @@
             colTypes.Add(colType);
             colTypClasses.Add(thread->DataSet()->ColTypClass(col));
 
-            wxString colHeader=colName +wxT(" (")+ colType +wxT(")");
+            wxString colHeader = colName + wxT("\n") + colType;
 
             int w;
             if (hdrIndex < colHeaders.GetCount() && colHeaders.Item(hdrIndex) == colHeader)
@@ -236,7 +273,8 @@
                     w=-1;
             }
 
-            InsertColumn(col+1, colHeader, wxLIST_FORMAT_LEFT, w);
+            SetColLabelValue(col, colHeader);
+            SetColSize(col, w);
         }
         Thaw();
     }
@@ -246,8 +284,6 @@
 
     while (chunk-- && !thread->DataSet()->Eof())
     {
-        InsertItem(rowsRetrieved, NumToStr(rowsRetrieved+1L));
-
         for (col=0 ; col < nCols ; col++)
         {
             wxString value = thread->DataSet()->GetVal(col);
@@ -256,7 +292,7 @@
                 if ((int)value.Length() > maxColSize)
                     value = value.Left(maxColSize) + wxT(" (..)");
             }
-            SetItem(rowsRetrieved, col+1, value);
+            GetTable()->SetValue(rowsRetrieved, col, value);
         }
         
         thread->DataSet()->MoveNext();
@@ -272,14 +308,9 @@
 wxString ctlSQLResult::GetItemText(int row, int col)
 {
     if (col < 0)
-        return wxListCtrl::GetItemText(row);
-
-    wxListItem item;
-    item.m_mask=wxLIST_MASK_TEXT;
-    item.m_itemId=row;
-    item.m_col=col;
-    GetItem(item);
-    return item.GetText();
+        return GetExportLine(row);
+    else
+        return GetCellValue(row, col);
 }
 
 
@@ -334,3 +365,173 @@
 }
 
 
+void ctlSQLResult::Copy()
+{
+    wxString str;
+    int copied = 0;
+    size_t i;
+
+    if (GetSelectedRows().GetCount()) {
+        wxArrayInt rows = GetSelectedRows();
+
+        for (i=0 ; i < rows.GetCount() ; i++)
+        {
+            str.Append(GetExportLine(rows.Item(i)));
+    
+            if (rows.GetCount() > 1)
+                str.Append(END_OF_LINE);
+        }
+
+        copied = rows.GetCount();
+    }
+    else if (GetSelectedCols().GetCount()) {
+        wxArrayInt cols = GetSelectedCols();
+        size_t numRows = GetNumberRows();
+
+        for (i=0 ; i < numRows ; i++)
+        {
+            str.Append(GetExportLine(i, cols));
+    
+            if (numRows > 1)
+                str.Append(END_OF_LINE);
+        }
+
+        copied = numRows;
+    }
+    else if (GetSelectionBlockTopLeft().GetCount() > 0 &&
+        GetSelectionBlockBottomRight().GetCount() > 0) {
+        unsigned int x1, x2, y1, y2;
+
+        x1 = GetSelectionBlockTopLeft()[0].GetCol();
+        x2 = GetSelectionBlockBottomRight()[0].GetCol();
+        y1 = GetSelectionBlockTopLeft()[0].GetRow();
+        y2 = GetSelectionBlockBottomRight()[0].GetRow();
+
+        for (i = y1; i <= y2; i++) {
+            str.Append(GetExportLine(i, x1, x2));
+
+            if (y2 > y1)
+                str.Append(END_OF_LINE);
+        }
+
+        copied = y2 - y1 + 1;
+    }
+    else {
+        int row, col;
+
+        row = GetGridCursorRow();
+        col = GetGridCursorCol();
+
+        str.Append(GetExportLine(row, col, col));
+        copied = 1;
+    }
+
+    if (copied && wxTheClipboard->Open())
+    {
+        wxTheClipboard->SetData(new wxTextDataObject(str));
+        wxTheClipboard->Close();
+    }
+}
+
+void ctlSQLResult::SetMaxRows(int rows)
+{
+    maxRows = rows;
+}
+
+void ctlSQLResult::ResultsFinished()
+{
+    int rows = GetTable()->GetNumberRows();
+
+    if (rowsRetrieved < rows) {
+        GetTable()->DeleteRows(rowsRetrieved, rows - rowsRetrieved);
+    }
+}
+
+void ctlSQLResult::OnGridSelect(wxGridRangeSelectEvent& event)
+{
+    SetFocus();
+}
+
+sqlResultTable::sqlResultTable()
+{
+    nRows = nCols = 0;
+    values = 0;
+}
+
+sqlResultTable::~sqlResultTable()
+{
+    values.Clear();
+}
+
+int sqlResultTable::GetNumberRows()
+{
+    return nRows;
+}
+
+int sqlResultTable::GetNumberCols()
+{
+    return nCols;
+}
+
+bool sqlResultTable::AppendCols(size_t numCols)
+{
+    if (values.Count()) {
+        values.Clear();
+        nRows = 0;
+    }
+
+    nCols = numCols;
+    return true;
+}
+
+bool sqlResultTable::AppendRows(size_t numRows)
+{
+    if (numRows <= 0)
+        return false;
+
+    values.Add(wxT(""), nCols * numRows);
+    nRows += numRows;
+    return true;
+}
+
+void sqlResultTable::SetValue(int row, int col, const wxString& s)
+{
+    if (row < 0 || row >= nRows)
+        return;
+
+    if (col < 0 || col >= nCols)
+        return;
+
+    values[row * nCols + col] = s;
+}
+
+wxString sqlResultTable::GetValue(int row, int col)
+{
+    if (row < 0 || row >= nRows)
+        return wxT("");
+
+    if (col < 0 || col >= nCols)
+        return wxT("");
+
+    return values[row * nCols + col];
+}
+
+bool sqlResultTable::IsEmptyCell(int row, int col)
+{
+    return false;
+}
+
+bool sqlResultTable::DeleteRows(size_t pos, size_t numRows)
+{
+    if (pos >= (size_t)nRows)
+        return false;
+
+    values.RemoveAt(pos, numRows);
+
+    if (pos + numRows > (size_t)nRows)
+        nRows = pos;
+    else
+        nRows -= numRows;
+
+    return true;
+}
Index: src/frm/frmEditGrid.cpp
===================================================================
--- src/frm/frmEditGrid.cpp	(revision 5004)
+++ src/frm/frmEditGrid.cpp	(working copy)
@@ -93,7 +93,7 @@
     wxFont fntLabel(settings->GetSystemFont());
     fntLabel.SetWeight(wxBOLD);
     sqlGrid->SetLabelFont(fntLabel);
-
+    sqlGrid->SetColLabelAlignment(wxALIGN_LEFT, wxALIGN_CENTER);
    
     toolBar = CreateToolBar();
 
Index: src/frm/frmExport.cpp
===================================================================
--- src/frm/frmExport.cpp	(revision 4990)
+++ src/frm/frmExport.cpp	(working copy)
@@ -156,8 +156,8 @@
     }
     else
     {
-        colCount = data->GetColumnCount();
-        rowCount = data->GetItemCount();
+        colCount = data->GetNumberCols();
+        rowCount = data->GetNumberRows();
         if (colCount > 1) // first col contains row count
             startCol=1;
     }
Index: src/frm/frmQuery.cpp
===================================================================
--- src/frm/frmQuery.cpp	(revision 4990)
+++ src/frm/frmQuery.cpp	(working copy)
@@ -590,27 +590,16 @@
         msgResult->Copy();
     else if (wnd == msgHistory)
         msgHistory->Copy();
-    else if (wnd == sqlResult && sqlResult->GetSelectedItemCount() > 0)
-    {
-        wxString str;
-        int row=-1;
-        while (true)
-        {
-            row = sqlResult->GetNextItem(row, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
-            if (row < 0)
+    else {
+        wxWindow *obj = wnd;
+
+        while (obj != NULL) {
+            if (obj == sqlResult) {
+                sqlResult->Copy();
                 break;
-            
-            str.Append(sqlResult->GetExportLine(row));
-            if (sqlResult->GetSelectedItemCount() > 1)
-                str.Append(END_OF_LINE);
+            }
+            obj = obj->GetParent();
         }
-
-        if (wxTheClipboard->Open())
-        {
-            wxTheClipboard->SetData(new wxTextDataObject(str));
-            wxTheClipboard->Close();
-        }
-
     }
     updateMenu();
 }
@@ -1205,6 +1194,7 @@
                                 break;
                         }
                     }
+                    sqlResult->SetMaxRows(maxRows);
                     wxLongLong startTimeRetrieve=wxGetLocalTimeMillis();
                     wxLongLong elapsed;
                     elapsedRetrieve=0;
@@ -1245,6 +1235,7 @@
                             wxYield();
                         }
                     }
+                    sqlResult->ResultsFinished();
                     if (resultFreezed)
                         sqlResult->Thaw();
 
Index: src/include/ctl/ctlSQLResult.h
===================================================================
--- src/include/ctl/ctlSQLResult.h	(revision 4990)
+++ src/include/ctl/ctlSQLResult.h	(working copy)
@@ -13,7 +13,7 @@
 #define CTLSQLRESULT_H
 
 // wxWindows headers
-#include <wx/listctrl.h>
+#include <wx/grid.h>
 #include <wx/thread.h>
 
 #include "pgSet.h"
@@ -24,7 +24,7 @@
 
 #define CTLSQL_RUNNING 100  // must be greater than ExecStatusType PGRES_xxx values
 
-class ctlSQLResult : public wxListView 
+class ctlSQLResult : public wxGrid
 {
 public:
     ctlSQLResult(wxWindow *parent, pgConn *conn, wxWindowID id, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize);
@@ -41,18 +41,24 @@
     int RetrieveOne();
     int Abort();
 
-	void SelectAll();
-
     bool Export();
     bool CanExport() { return rowsRetrieved>0 && colNames.GetCount() > 0; }
 
     wxString GetItemText(int row, int col=-1);
     wxString GetExportLine(int row);
+    wxString GetExportLine(int row, wxArrayInt cols);
+    wxString GetExportLine(int row, int col1, int col2);
+    void Copy();
 
     int RunStatus();
     wxString GetMessagesAndClear();
     wxString GetErrorMessage();
 
+    void SetMaxRows(int rows);
+    void ResultsFinished();
+
+    void OnGridSelect(wxGridRangeSelectEvent& event);
+
     wxArrayString colNames;
     wxArrayString colTypes;
     wxArrayLong colTypClasses;
@@ -64,6 +70,27 @@
     pgQueryThread *thread;
     pgConn *conn;
     long rowsRetrieved;
+    int maxRows;
 };
 
+class sqlResultTable : public wxGridTableBase
+{
+public:
+    sqlResultTable();
+    ~sqlResultTable();
+    int GetNumberRows();
+    int GetNumberCols();
+    bool AppendCols(size_t numCols); // NOTE: Replaces cols rather than appends
+    bool AppendRows(size_t numRows);
+    void SetValue(int row, int col, const wxString& s);
+    wxString GetValue(int row, int col);
+    bool IsEmptyCell(int row, int col);
+    bool DeleteRows(size_t pos = 0, size_t numRows = 1);
+
+private:
+    int nRows;
+    int nCols;
+    wxArrayString values;
+};
+
 #endif
