]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/grid.cpp
fix compilation without wxUSE_STREAMS (closes #10900)
[wxWidgets.git] / src / generic / grid.cpp
index 73318daf36dd28fab641790b92941a2f708c61dd..dccf054460b7a4767ffb42472d68bc792a41986b 100644 (file)
@@ -48,6 +48,7 @@
 #include "wx/tokenzr.h"
 #include "wx/renderer.h"
 #include "wx/headerctrl.h"
+#include "wx/hashset.h"
 
 #include "wx/generic/gridsel.h"
 #include "wx/generic/gridctrl.h"
@@ -71,6 +72,9 @@ const char wxGridNameStr[] = "grid";
 // Required for wxIs... functions
 #include <ctype.h>
 
+WX_DECLARE_HASH_SET_WITH_DECL(int, wxIntegerHash, wxIntegerEqual,
+                              wxGridFixedIndicesSet, class WXDLLIMPEXP_ADV);
+
 
 // ----------------------------------------------------------------------------
 // globals
@@ -193,8 +197,6 @@ wxGridCellWorker::~wxGridCellWorker()
 
 void wxGridCellAttr::Init(wxGridCellAttr *attrDefault)
 {
-    m_nRef = 1;
-
     m_isReadOnly = Unset;
 
     m_renderer = NULL;
@@ -641,30 +643,30 @@ void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol)
     {
         if ( attr )
         {
-            // add the attribute - no need to do anything to reference count
-            //                     since we take ownership of the attribute.
+            // store the new attribute, taking its ownership
             m_rowsOrCols.Add(rowOrCol);
             m_attrs.Add(attr);
         }
         // nothing to remove
     }
-    else
+    else // we have an attribute for this row or column
     {
         size_t n = (size_t)i;
-        if ( m_attrs[n] == attr )
-            // nothing to do
-            return;
+
+        // notice that this code works correctly even when the old attribute is
+        // the same as the new one: as we own of it, we must call DecRef() on
+        // it in any case and this won't result in destruction of the new
+        // attribute if it's the same as old one because it must have ref count
+        // of at least 2 to be passed to us while we keep a reference to it too
+        m_attrs[n]->DecRef();
+
         if ( attr )
         {
-            // change the attribute, handling reference count manually,
-            //                       taking ownership of the new attribute.
-            m_attrs[n]->DecRef();
+            // replace the attribute with the new one
             m_attrs[n] = attr;
         }
-        else
+        else // remove the attribute
         {
-            // remove this attribute, handling reference count manually
-            m_attrs[n]->DecRef();
             m_rowsOrCols.RemoveAt(n);
             m_attrs.RemoveAt(n);
         }
@@ -1123,11 +1125,14 @@ IMPLEMENT_DYNAMIC_CLASS( wxGridStringTable, wxGridTableBase )
 wxGridStringTable::wxGridStringTable()
         : wxGridTableBase()
 {
+    m_numCols = 0;
 }
 
 wxGridStringTable::wxGridStringTable( int numRows, int numCols )
         : wxGridTableBase()
 {
+    m_numCols = numCols;
+
     m_data.Alloc( numRows );
 
     wxArrayString sa;
@@ -1137,23 +1142,6 @@ wxGridStringTable::wxGridStringTable( int numRows, int numCols )
     m_data.Add( sa, numRows );
 }
 
-wxGridStringTable::~wxGridStringTable()
-{
-}
-
-int wxGridStringTable::GetNumberRows()
-{
-    return m_data.GetCount();
-}
-
-int wxGridStringTable::GetNumberCols()
-{
-    if ( m_data.GetCount() > 0 )
-        return m_data[0].GetCount();
-    else
-        return 0;
-}
-
 wxString wxGridStringTable::GetValue( int row, int col )
 {
     wxCHECK_MSG( (row < GetNumberRows()) && (col < GetNumberCols()),
@@ -1323,6 +1311,8 @@ bool wxGridStringTable::InsertCols( size_t pos, size_t numCols )
         }
     }
 
+    m_numCols += numCols;
+
     if ( GetView() )
     {
         wxGridTableMessage msg( this,
@@ -1347,6 +1337,8 @@ bool wxGridStringTable::AppendCols( size_t numCols )
         m_data[row].Add( wxEmptyString, numCols );
     }
 
+    m_numCols += numCols;
+
     if ( GetView() )
     {
         wxGridTableMessage msg( this,
@@ -1400,16 +1392,23 @@ bool wxGridStringTable::DeleteCols( size_t pos, size_t numCols )
             m_colLabels.RemoveAt( colID, nToRm );
     }
 
-    for ( row = 0; row < curNumRows; row++ )
+    if ( numCols >= curNumCols )
     {
-        if ( numCols >= curNumCols )
+        for ( row = 0; row < curNumRows; row++ )
         {
             m_data[row].Clear();
         }
-        else
+
+        m_numCols = 0;
+    }
+    else // something will be left
+    {
+        for ( row = 0; row < curNumRows; row++ )
         {
             m_data[row].RemoveAt( colID, numCols );
         }
+
+        m_numCols -= numCols;
     }
 
     if ( GetView() )
@@ -1822,6 +1821,9 @@ wxGrid::~wxGrid()
 
     delete m_typeRegistry;
     delete m_selection;
+
+    delete m_setFixedRows;
+    delete m_setFixedCols;
 }
 
 //
@@ -2047,6 +2049,9 @@ void wxGrid::Init()
     m_rowLabelWidth  = WXGRID_DEFAULT_ROW_LABEL_WIDTH;
     m_colLabelHeight = WXGRID_DEFAULT_COL_LABEL_HEIGHT;
 
+    m_setFixedRows =
+    m_setFixedCols = NULL;
+
     // init attr cache
     m_attrCache.row = -1;
     m_attrCache.col = -1;
@@ -2916,11 +2921,12 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
     //
     else if ( event.LeftDown() )
     {
-        // don't send a label click event for a hit on the
-        // edge of the row label - this is probably the user
-        // wanting to resize the row
-        //
-        if ( YToEdgeOfRow(y) < 0 )
+        row = YToEdgeOfRow(y);
+        if ( row != wxNOT_FOUND && CanDragRowSize(row) )
+        {
+            ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
+        }
+        else // not a request to start resizing
         {
             row = YToRow(y);
             if ( row >= 0 &&
@@ -2948,12 +2954,6 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
                 ChangeCursorMode(WXGRID_CURSOR_SELECT_ROW, m_rowLabelWin);
             }
         }
-        else
-        {
-            // starting to drag-resize a row
-            if ( CanDragRowSize() )
-                ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin);
-        }
     }
 
     // ------------ Left double click
@@ -2961,7 +2961,19 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
     else if (event.LeftDClick() )
     {
         row = YToEdgeOfRow(y);
-        if ( row < 0 )
+        if ( row != wxNOT_FOUND && CanDragRowSize(row) )
+        {
+            // adjust row height depending on label text
+            //
+            // TODO: generate RESIZING event, see #10754
+            AutoSizeRowLabelSize( row );
+
+            SendGridSizeEvent(wxEVT_GRID_ROW_SIZE, row, -1, event);
+
+            ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow());
+            m_dragLastPos = -1;
+        }
+        else // not on row separator or it's not resizeable
         {
             row = YToRow(y);
             if ( row >=0 &&
@@ -2970,14 +2982,6 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
                 // no default action at the moment
             }
         }
-        else
-        {
-            // adjust row height depending on label text
-            AutoSizeRowLabelSize( row );
-
-            ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow());
-            m_dragLastPos = -1;
-        }
     }
 
     // ------------ Left button released
@@ -2985,14 +2989,7 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
     else if ( event.LeftUp() )
     {
         if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
-        {
-            DoEndDragResizeRow();
-
-            // Note: we are ending the event *after* doing
-            // default processing in this case
-            //
-            SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
-        }
+            DoEndDragResizeRow(event);
 
         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, m_rowLabelWin);
         m_dragLastPos = -1;
@@ -3027,12 +3024,11 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event )
     else if ( event.Moving() )
     {
         m_dragRowOrCol = YToEdgeOfRow( y );
-        if ( m_dragRowOrCol >= 0 )
+        if ( m_dragRowOrCol != wxNOT_FOUND )
         {
             if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
             {
-                // don't capture the mouse yet
-                if ( CanDragRowSize() )
+                if ( CanDragRowSize(m_dragRowOrCol) )
                     ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, m_rowLabelWin, false);
             }
         }
@@ -3248,12 +3244,14 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
     //
     else if ( event.LeftDown() )
     {
-        // don't send a label click event for a hit on the
-        // edge of the col label - this is probably the user
-        // wanting to resize the col
-        //
-        if ( XToEdgeOfCol(x) < 0 )
+        int col = XToEdgeOfCol(x);
+        if ( col != wxNOT_FOUND && CanDragColSize(col) )
         {
+            ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, GetColLabelWindow());
+        }
+        else // not a request to start resizing
+        {
+            col = XToCol(x);
             if ( col >= 0 &&
                  !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) )
             {
@@ -3294,13 +3292,6 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
                 }
             }
         }
-        else
-        {
-            // starting to drag-resize a col
-            //
-            if ( CanDragColSize() )
-                ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, GetColLabelWindow());
-        }
     }
 
     // ------------ Left double click
@@ -3319,8 +3310,12 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
         else
         {
             // adjust column width depending on label text
+            //
+            // TODO: generate RESIZING event, see #10754
             AutoSizeColLabelSize( colEdge );
 
+            SendGridSizeEvent(wxEVT_GRID_COL_SIZE, -1, colEdge, event);
+
             ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow());
             m_dragLastPos = -1;
         }
@@ -3333,7 +3328,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
         switch ( m_cursorMode )
         {
             case WXGRID_CURSOR_RESIZE_COL:
-                DoEndDragResizeCol();
+                DoEndDragResizeCol(event);
                 break;
 
             case WXGRID_CURSOR_MOVE_COL:
@@ -3394,8 +3389,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event )
         {
             if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
             {
-                // don't capture the cursor yet
-                if ( CanDragColSize() )
+                if ( CanDragColSize(m_dragRowOrCol) )
                     ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, GetColLabelWindow(), false);
             }
         }
@@ -3756,17 +3750,12 @@ wxGrid::DoGridCellLeftUp(wxMouseEvent& event, const wxGridCellCoords& coords)
     else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW )
     {
         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
-        DoEndDragResizeRow();
-
-        // Note: we are ending the event *after* doing
-        // default processing in this case
-        //
-        SendEvent( wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event );
+        DoEndDragResizeRow(event);
     }
     else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL )
     {
         ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL);
-        DoEndDragResizeCol();
+        DoEndDragResizeCol(event);
     }
 
     m_dragLastPos = -1;
@@ -3796,27 +3785,24 @@ wxGrid::DoGridMouseMoveEvent(wxMouseEvent& WXUNUSED(event),
         return;
     }
 
-    if ( dragRow >= 0 )
+    if ( dragRow >= 0 && CanDragGridSize() && CanDragRowSize(dragRow) )
     {
-        m_dragRowOrCol = dragRow;
-
         if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
         {
-            if ( CanDragRowSize() && CanDragGridSize() )
-                ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, NULL, false);
+            m_dragRowOrCol = dragRow;
+            ChangeCursorMode(WXGRID_CURSOR_RESIZE_ROW, NULL, false);
         }
     }
     // When using the native header window we can only resize the columns by
     // dragging the dividers in it because we can't make it enter into the
     // column resizing mode programmatically
-    else if ( dragCol >= 0 && !m_useNativeHeader )
+    else if ( dragCol >= 0 && !m_useNativeHeader &&
+                CanDragGridSize() && CanDragColSize(dragCol) )
     {
-        m_dragRowOrCol = dragCol;
-
         if ( m_cursorMode == WXGRID_CURSOR_SELECT_CELL )
         {
-            if ( CanDragColSize() && CanDragGridSize() )
-                ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, NULL, false);
+            m_dragRowOrCol = dragCol;
+            ChangeCursorMode(WXGRID_CURSOR_RESIZE_COL, NULL, false);
         }
     }
     else // Neither on a row or col edge
@@ -3899,10 +3885,11 @@ void wxGrid::ProcessGridCellMouseEvent(wxMouseEvent& event)
     }
 }
 
-void wxGrid::DoEndDragResizeLine(const wxGridOperations& oper)
+// this function returns true only if the size really changed
+bool wxGrid::DoEndDragResizeLine(const wxGridOperations& oper)
 {
     if ( m_dragLastPos == -1 )
-        return;
+        return false;
 
     const wxGridOperations& doper = oper.Dual();
 
@@ -3926,9 +3913,12 @@ void wxGrid::DoEndDragResizeLine(const wxGridOperations& oper)
 
     // do resize the line
     const int lineStart = oper.GetLineStartPos(this, m_dragRowOrCol);
+    const int lineSizeOld = oper.GetLineSize(this, m_dragRowOrCol);
     oper.SetLineSize(this, m_dragRowOrCol,
                      wxMax(m_dragLastPos - lineStart,
                            oper.GetMinimalLineSize(this, m_dragRowOrCol)));
+    const bool
+        sizeChanged = oper.GetLineSize(this, m_dragRowOrCol) != lineSizeOld;
 
     m_dragLastPos = -1;
 
@@ -3991,24 +3981,24 @@ void wxGrid::DoEndDragResizeLine(const wxGridOperations& oper)
 
     // show the edit control back again
     ShowCellEditControl();
+
+    return sizeChanged;
 }
 
-void wxGrid::DoEndDragResizeRow()
+void wxGrid::DoEndDragResizeRow(const wxMouseEvent& event)
 {
-    DoEndDragResizeLine(wxGridRowOperations());
+    // TODO: generate RESIZING event, see #10754
+
+    if ( DoEndDragResizeLine(wxGridRowOperations()) )
+        SendGridSizeEvent(wxEVT_GRID_ROW_SIZE, m_dragRowOrCol, -1, event);
 }
 
-void wxGrid::DoEndDragResizeCol(wxMouseEvent *event)
+void wxGrid::DoEndDragResizeCol(const wxMouseEvent& event)
 {
-    DoEndDragResizeLine(wxGridColumnOperations());
+    // TODO: generate RESIZING event, see #10754
 
-    // Note: we are ending the event *after* doing
-    // default processing in this case
-    //
-    if ( event )
-        SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, *event );
-    else
-        SendEvent( wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol );
+    if ( DoEndDragResizeLine(wxGridColumnOperations()) )
+        SendGridSizeEvent(wxEVT_GRID_COL_SIZE, -1, m_dragRowOrCol, event);
 }
 
 void wxGrid::DoStartMoveCol(int col)
@@ -4182,9 +4172,27 @@ wxGrid::DoAppendLines(bool (wxGridTableBase::*funcAppend)(size_t),
     return (m_table->*funcAppend)(num);
 }
 
-//
-// ----- event handlers
-//
+// ----------------------------------------------------------------------------
+// event generation helpers
+// ----------------------------------------------------------------------------
+
+void
+wxGrid::SendGridSizeEvent(wxEventType type,
+                      int row, int col,
+                      const wxMouseEvent& mouseEv)
+{
+   int rowOrCol = row == -1 ? col : row;
+
+   wxGridSizeEvent gridEvt( GetId(),
+           type,
+           this,
+           rowOrCol,
+           mouseEv.GetX() + GetRowLabelSize(),
+           mouseEv.GetY() + GetColLabelSize(),
+           mouseEv);
+
+   GetEventHandler()->ProcessEvent(gridEvt);
+}
 
 // Generate a grid event based on a mouse event and return:
 //  -1 if the event was vetoed
@@ -4193,26 +4201,11 @@ wxGrid::DoAppendLines(bool (wxGridTableBase::*funcAppend)(size_t),
 int
 wxGrid::SendEvent(const wxEventType type,
                   int row, int col,
-                  wxMouseEvent& mouseEv)
+                  const wxMouseEvent& mouseEv)
 {
    bool claimed, vetoed;
 
-   if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
-   {
-       int rowOrCol = (row == -1 ? col : row);
-
-       wxGridSizeEvent gridEvt( GetId(),
-               type,
-               this,
-               rowOrCol,
-               mouseEv.GetX() + GetRowLabelSize(),
-               mouseEv.GetY() + GetColLabelSize(),
-               mouseEv);
-
-       claimed = GetEventHandler()->ProcessEvent(gridEvt);
-       vetoed = !gridEvt.IsAllowed();
-   }
-   else if ( type == wxEVT_GRID_RANGE_SELECT )
+   if ( type == wxEVT_GRID_RANGE_SELECT )
    {
        // Right now, it should _never_ end up here!
        wxGridRangeSelectEvent gridEvt( GetId(),
@@ -4275,28 +4268,13 @@ wxGrid::SendEvent(const wxEventType type,
 int
 wxGrid::SendEvent(const wxEventType type, int row, int col, const wxString& s)
 {
-   bool claimed, vetoed;
-
-    if ( type == wxEVT_GRID_ROW_SIZE || type == wxEVT_GRID_COL_SIZE )
-    {
-        int rowOrCol = (row == -1 ? col : row);
-
-        wxGridSizeEvent gridEvt( GetId(), type, this, rowOrCol );
-
-        claimed = GetEventHandler()->ProcessEvent(gridEvt);
-        vetoed  = !gridEvt.IsAllowed();
-    }
-    else
-    {
-        wxGridEvent gridEvt( GetId(), type, this, row, col );
-        gridEvt.SetString(s);
+    wxGridEvent gridEvt( GetId(), type, this, row, col );
+    gridEvt.SetString(s);
 
-        claimed = GetEventHandler()->ProcessEvent(gridEvt);
-        vetoed  = !gridEvt.IsAllowed();
-     }
+    const bool claimed = GetEventHandler()->ProcessEvent(gridEvt);
 
     // A Veto'd event may not be `claimed' so test this first
-    if (vetoed)
+    if ( !gridEvt.IsAllowed() )
         return -1;
 
     return claimed ? 1 : 0;
@@ -6124,23 +6102,15 @@ int wxGrid::XToPos(int x) const
     return PosToLinePos(x, true /* clip */, wxGridColumnOperations());
 }
 
-// return the row number that that the y coord is near the edge of, or -1 if
+// return the row number such that the y coord is near the edge of, or -1 if
 // not near an edge.
 //
-// coords can only possibly be near an edge if
-//    (a) the row/column is large enough to still allow for an "inner" area
-//        that is _not_ near the edge (i.e., if the height/width is smaller
-//        than WXGRID_LABEL_EDGE_ZONE, coords are _never_ considered to be
-//        near the edge).
-//   and
-//    (b) resizing rows/columns (the thing for which edge detection is
-//        relevant at all) is enabled.
-//
+// notice that position can only possibly be near an edge if the row/column is
+// large enough to still allow for an "inner" area that is _not_ near the edge
+// (i.e., if the height/width is smaller than WXGRID_LABEL_EDGE_ZONE, pos will
+// _never_ be considered to be near the edge).
 int wxGrid::PosToEdgeOfLine(int pos, const wxGridOperations& oper) const
 {
-    if ( !oper.CanResizeLines(this) )
-        return -1;
-
     const int line = oper.PosToLine(this, pos, true);
 
     if ( oper.GetLineSize(this, line) > WXGRID_LABEL_EDGE_ZONE )
@@ -7481,6 +7451,22 @@ wxGridCellRenderer * wxGrid::GetDefaultRendererForType(const wxString& typeName)
 // row/col size
 // ----------------------------------------------------------------------------
 
+void wxGrid::DoDisableLineResize(int line, wxGridFixedIndicesSet *& setFixed)
+{
+    if ( !setFixed )
+    {
+        setFixed = new wxGridFixedIndicesSet;
+    }
+
+    setFixed->insert(line);
+}
+
+bool
+wxGrid::DoCanResizeLine(int line, const wxGridFixedIndicesSet *setFixed) const
+{
+    return !setFixed || !setFixed->count(line);
+}
+
 void wxGrid::EnableDragRowSize( bool enable )
 {
     m_canDragRowSize = enable;
@@ -8083,7 +8069,8 @@ void wxGrid::DeselectLine(int line, const wxGridOperations& oper)
         return;
 
     const wxGridSelectionModes mode = m_selection->GetSelectionMode();
-    if ( mode == oper.GetSelectionMode() )
+    if ( mode == oper.GetSelectionMode() ||
+            mode == wxGrid::wxGridSelectRowsOrColumns )
     {
         const wxGridCellCoords c(oper.MakeCoords(line, 0));
         if ( m_selection->IsInSelection(c) )