From 10a4531d1df283f12225dc71cbbc3351a2a7f83b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Tue, 16 Sep 2008 16:31:44 +0000 Subject: [PATCH] more grid folding: got rid of duplicate version of methods for finding the closest row/column edge, appending/inserting/deleting rows/columns, and moving cursor vertically/horizontally git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@55663 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/generic/grid.h | 185 +++++--- interface/wx/grid.h | 8 + src/generic/grid.cpp | 911 ++++++++++++++------------------------ 3 files changed, 454 insertions(+), 650 deletions(-) diff --git a/include/wx/generic/grid.h b/include/wx/generic/grid.h index 767635a16f..69ca1db214 100644 --- a/include/wx/generic/grid.h +++ b/include/wx/generic/grid.h @@ -87,6 +87,7 @@ class WXDLLIMPEXP_FWD_CORE wxSpinCtrl; class wxGridOperations; class wxGridRowOperations; class wxGridColumnOperations; +class wxGridDirectionOperations; // ---------------------------------------------------------------------------- // macros @@ -829,14 +830,72 @@ private: DECLARE_NO_COPY_CLASS(wxGridCellAttrProvider) }; -////////////////////////////////////////////////////////////////////// +// ---------------------------------------------------------------------------- +// wxGridCellCoords: location of a cell in the grid +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_ADV wxGridCellCoords +{ +public: + wxGridCellCoords() { m_row = m_col = -1; } + wxGridCellCoords( int r, int c ) { m_row = r; m_col = c; } + + // default copy ctor is ok + + int GetRow() const { return m_row; } + void SetRow( int n ) { m_row = n; } + int GetCol() const { return m_col; } + void SetCol( int n ) { m_col = n; } + void Set( int row, int col ) { m_row = row; m_col = col; } + + wxGridCellCoords& operator=( const wxGridCellCoords& other ) + { + if ( &other != this ) + { + m_row=other.m_row; + m_col=other.m_col; + } + return *this; + } + + bool operator==( const wxGridCellCoords& other ) const + { + return (m_row == other.m_row && m_col == other.m_col); + } + + bool operator!=( const wxGridCellCoords& other ) const + { + return (m_row != other.m_row || m_col != other.m_col); + } + + bool operator!() const + { + return (m_row == -1 && m_col == -1 ); + } + +private: + int m_row; + int m_col; +}; + + +// For comparisons... // -// Grid table classes +extern WXDLLIMPEXP_ADV wxGridCellCoords wxGridNoCellCoords; +extern WXDLLIMPEXP_ADV wxRect wxGridNoCellRect; + +// An array of cell coords... // -////////////////////////////////////////////////////////////////////// +WX_DECLARE_OBJARRAY_WITH_DECL(wxGridCellCoords, wxGridCellCoordsArray, + class WXDLLIMPEXP_ADV); +// ---------------------------------------------------------------------------- +// Grid table classes +// ---------------------------------------------------------------------------- -class WXDLLIMPEXP_ADV wxGridTableBase : public wxObject, public wxClientDataContainer +// the abstract base class +class WXDLLIMPEXP_ADV wxGridTableBase : public wxObject, + public wxClientDataContainer { public: wxGridTableBase(); @@ -847,6 +906,12 @@ public: virtual int GetNumberRows() = 0; virtual int GetNumberCols() = 0; virtual bool IsEmptyCell( int row, int col ) = 0; + + bool IsEmpty(const wxGridCellCoords& coord) + { + return IsEmptyCell(coord.GetRow(), coord.GetCol()); + } + virtual wxString GetValue( int row, int col ) = 0; virtual void SetValue( int row, int col, const wxString& value ) = 0; @@ -1028,65 +1093,6 @@ private: // Grid view classes // ============================================================================ -// ---------------------------------------------------------------------------- -// wxGridCellCoords: location of a cell in the grid -// ---------------------------------------------------------------------------- - -class WXDLLIMPEXP_ADV wxGridCellCoords -{ -public: - wxGridCellCoords() { m_row = m_col = -1; } - wxGridCellCoords( int r, int c ) { m_row = r; m_col = c; } - - // default copy ctor is ok - - int GetRow() const { return m_row; } - void SetRow( int n ) { m_row = n; } - int GetCol() const { return m_col; } - void SetCol( int n ) { m_col = n; } - void Set( int row, int col ) { m_row = row; m_col = col; } - - wxGridCellCoords& operator=( const wxGridCellCoords& other ) - { - if ( &other != this ) - { - m_row=other.m_row; - m_col=other.m_col; - } - return *this; - } - - bool operator==( const wxGridCellCoords& other ) const - { - return (m_row == other.m_row && m_col == other.m_col); - } - - bool operator!=( const wxGridCellCoords& other ) const - { - return (m_row != other.m_row || m_col != other.m_col); - } - - bool operator!() const - { - return (m_row == -1 && m_col == -1 ); - } - -private: - int m_row; - int m_col; -}; - - -// For comparisons... -// -extern WXDLLIMPEXP_ADV wxGridCellCoords wxGridNoCellCoords; -extern WXDLLIMPEXP_ADV wxRect wxGridNoCellRect; - -// An array of cell coords... -// -WX_DECLARE_OBJARRAY_WITH_DECL(wxGridCellCoords, wxGridCellCoordsArray, - class WXDLLIMPEXP_ADV); - // ---------------------------------------------------------------------------- // wxGrid // ---------------------------------------------------------------------------- @@ -1172,12 +1178,36 @@ public: wxGridTableBase * GetTable() const { return m_table; } void ClearGrid(); - bool InsertRows( int pos = 0, int numRows = 1, bool updateLabels = true ); - bool AppendRows( int numRows = 1, bool updateLabels = true ); - bool DeleteRows( int pos = 0, int numRows = 1, bool updateLabels = true ); - bool InsertCols( int pos = 0, int numCols = 1, bool updateLabels = true ); - bool AppendCols( int numCols = 1, bool updateLabels = true ); - bool DeleteCols( int pos = 0, int numCols = 1, bool updateLabels = true ); + bool InsertRows(int pos = 0, int numRows = 1, bool updateLabels = true) + { + return DoModifyLines(&wxGridTableBase::InsertRows, + pos, numRows, updateLabels); + } + bool InsertCols(int pos = 0, int numCols = 1, bool updateLabels = true) + { + return DoModifyLines(&wxGridTableBase::InsertCols, + pos, numCols, updateLabels); + } + + bool AppendRows(int numRows = 1, bool updateLabels = true) + { + return DoAppendLines(&wxGridTableBase::AppendRows, numRows, updateLabels); + } + bool AppendCols(int numCols = 1, bool updateLabels = true) + { + return DoAppendLines(&wxGridTableBase::AppendCols, numCols, updateLabels); + } + + bool DeleteRows(int pos = 0, int numRows = 1, bool updateLabels = true) + { + return DoModifyLines(&wxGridTableBase::DeleteRows, + pos, numRows, updateLabels); + } + bool DeleteCols(int pos = 0, int numCols = 1, bool updateLabels = true) + { + return DoModifyLines(&wxGridTableBase::DeleteCols, + pos, numCols, updateLabels); + } void DrawGridCellArea( wxDC& dc , const wxGridCellCoordsArray& cells ); void DrawGridSpace( wxDC& dc ); @@ -2070,7 +2100,22 @@ private: void DoEndDragResizeLine(const wxGridOperations& oper); int PosToLine(int pos, bool clipToMinMax, const wxGridOperations& oper) const; - + int PosToEdgeOfLine(int pos, const wxGridOperations& oper) const; + + bool DoMoveCursor(bool expandSelection, + const wxGridDirectionOperations& diroper); + bool DoMoveCursorByPage(const wxGridDirectionOperations& diroper); + bool DoMoveCursorByBlock(bool expandSelection, + const wxGridDirectionOperations& diroper); + void AdvanceToNextNonEmpty(wxGridCellCoords& coords, + const wxGridDirectionOperations& diroper); + + // common part of {Insert,Delete}{Rows,Cols} + bool DoModifyLines(bool (wxGridTableBase::*funcModify)(size_t, size_t), + int pos, int num, bool updateLabels); + // Append{Rows,Cols} is a bit different because of one less parameter + bool DoAppendLines(bool (wxGridTableBase::*funcAppend)(size_t), + int num, bool updateLabels); DECLARE_DYNAMIC_CLASS( wxGrid ) DECLARE_EVENT_TABLE() diff --git a/interface/wx/grid.h b/interface/wx/grid.h index 10d96fc530..fdd1ee05b6 100644 --- a/interface/wx/grid.h +++ b/interface/wx/grid.h @@ -101,6 +101,14 @@ public: /// Must be overridden to implement testing for empty cells. virtual bool IsEmptyCell(int row, int col) = 0; + /** + Same as IsEmptyCell() but taking wxGridCellCoords. + + Notice that this method is not virtual, only IsEmptyCell() should be + overridden. + */ + bool IsEmpty(const wxGridCellCoords& coords); + /// Must be overridden to implement accessing the table values as text. virtual wxString GetValue(int row, int col) = 0; diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 0f8f95ea1b..41fe1d6fc9 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -14,6 +14,8 @@ - Replace use of wxINVERT with wxOverlay - Make Begin/EndBatch() the same as the generic Freeze/Thaw() + - Review the column reordering code, it's a mess. + - Implement row reordering after dealing with the columns. */ // For compilers that support precompilation, includes "wx/wx.h". @@ -452,6 +454,7 @@ public: virtual int CalcScrolledPosition(wxGrid *grid, int pos) const = 0; // Selects the horizontal or vertical component from the given object. + virtual int Select(const wxGridCellCoords& coords) const = 0; virtual int Select(const wxPoint& pt) const = 0; virtual int Select(const wxSize& sz) const = 0; virtual int Select(const wxRect& r) const = 0; @@ -463,6 +466,9 @@ public: // Make a wxSize such that Select() applied to it returns first component virtual wxSize MakeSize(int first, int second) const = 0; + // Sets the row or column component of the given cell coordinates + virtual void Set(wxGridCellCoords& coords, int line) const = 0; + // Draws a line parallel to the row or column, i.e. horizontal or vertical: // pos is the vertical or horizontal position of the line and start and end @@ -472,11 +478,18 @@ public: // Return the row or column at the given pixel coordinate. - virtual int PosToLine(wxGrid *grid, int pos, bool clip = false) const = 0; + virtual int + PosToLine(const wxGrid *grid, int pos, bool clip = false) const = 0; // Get the top/left position, in pixels, of the given row or column virtual int GetLineStartPos(const wxGrid *grid, int line) const = 0; + // Get the bottom/right position, in pixels, of the given row or column + virtual int GetLineEndPos(const wxGrid *grid, int line) const = 0; + + // Get the height/width of the given row/column + virtual int GetLineSize(const wxGrid *grid, int line) const = 0; + // Get wxGrid::m_rowBottoms/m_colRights array virtual const wxArrayInt& GetLineEnds(const wxGrid *grid) const = 0; @@ -492,6 +505,9 @@ public: // Set the row height or column width virtual void SetLineSize(wxGrid *grid, int line, int size) const = 0; + // True if rows/columns can be resized by user + virtual bool CanResizeLines(const wxGrid *grid) const = 0; + // Return the index of the line at the given position // @@ -505,6 +521,11 @@ public: // Get the width or height of the row or column label window virtual int GetHeaderWindowSize(wxGrid *grid) const = 0; + + + // This class is never used polymorphically but give it a virtual dtor + // anyhow to suppress g++ complaints about it + virtual ~wxGridOperations() { } }; class wxGridRowOperations : public wxGridOperations @@ -524,6 +545,7 @@ public: virtual int CalcScrolledPosition(wxGrid *grid, int pos) const { return grid->CalcScrolledPosition(wxPoint(pos, 0)).x; } + virtual int Select(const wxGridCellCoords& c) const { return c.GetRow(); } virtual int Select(const wxPoint& pt) const { return pt.x; } virtual int Select(const wxSize& sz) const { return sz.x; } virtual int Select(const wxRect& r) const { return r.x; } @@ -531,14 +553,20 @@ public: virtual int& SelectSize(wxRect& r) const { return r.width; } virtual wxSize MakeSize(int first, int second) const { return wxSize(first, second); } + virtual void Set(wxGridCellCoords& coords, int line) const + { coords.SetRow(line); } virtual void DrawParallelLine(wxDC& dc, int start, int end, int pos) const { dc.DrawLine(start, pos, end, pos); } - virtual int PosToLine(wxGrid *grid, int pos, bool clip = false) const + virtual int PosToLine(const wxGrid *grid, int pos, bool clip = false) const { return grid->YToRow(pos, clip); } virtual int GetLineStartPos(const wxGrid *grid, int line) const { return grid->GetRowTop(line); } + virtual int GetLineEndPos(const wxGrid *grid, int line) const + { return grid->GetRowBottom(line); } + virtual int GetLineSize(const wxGrid *grid, int line) const + { return grid->GetRowHeight(line); } virtual const wxArrayInt& GetLineEnds(const wxGrid *grid) const { return grid->m_rowBottoms; } virtual int GetDefaultLineSize(const wxGrid *grid) const @@ -549,6 +577,8 @@ public: { return grid->GetRowMinimalHeight(line); } virtual void SetLineSize(wxGrid *grid, int line, int size) const { grid->SetRowSize(line, size); } + virtual bool CanResizeLines(const wxGrid *grid) const + { return grid->CanDragRowSize(); } virtual int GetLineAt(const wxGrid * WXUNUSED(grid), int line) const { return line; } // TODO: implement row reordering @@ -576,6 +606,7 @@ public: virtual int CalcScrolledPosition(wxGrid *grid, int pos) const { return grid->CalcScrolledPosition(wxPoint(0, pos)).y; } + virtual int Select(const wxGridCellCoords& c) const { return c.GetCol(); } virtual int Select(const wxPoint& pt) const { return pt.y; } virtual int Select(const wxSize& sz) const { return sz.y; } virtual int Select(const wxRect& r) const { return r.y; } @@ -583,14 +614,20 @@ public: virtual int& SelectSize(wxRect& r) const { return r.height; } virtual wxSize MakeSize(int first, int second) const { return wxSize(second, first); } + virtual void Set(wxGridCellCoords& coords, int line) const + { coords.SetCol(line); } virtual void DrawParallelLine(wxDC& dc, int start, int end, int pos) const { dc.DrawLine(pos, start, pos, end); } - virtual int PosToLine(wxGrid *grid, int pos, bool clip = false) const + virtual int PosToLine(const wxGrid *grid, int pos, bool clip = false) const { return grid->XToCol(pos, clip); } virtual int GetLineStartPos(const wxGrid *grid, int line) const { return grid->GetColLeft(line); } + virtual int GetLineEndPos(const wxGrid *grid, int line) const + { return grid->GetColRight(line); } + virtual int GetLineSize(const wxGrid *grid, int line) const + { return grid->GetColWidth(line); } virtual const wxArrayInt& GetLineEnds(const wxGrid *grid) const { return grid->m_colRights; } virtual int GetDefaultLineSize(const wxGrid *grid) const @@ -601,6 +638,8 @@ public: { return grid->GetColMinimalWidth(line); } virtual void SetLineSize(wxGrid *grid, int line, int size) const { grid->SetColSize(line, size); } + virtual bool CanResizeLines(const wxGrid *grid) const + { return grid->CanDragColSize(); } virtual int GetLineAt(const wxGrid *grid, int line) const { return grid->GetColAt(line); } @@ -625,6 +664,109 @@ wxGridOperations& wxGridColumnOperations::Dual() const return s_rowOper; } +// This class abstracts the difference between operations going forward +// (down/right) and backward (up/left) and allows to use the same code for +// functions which differ only in the direction of grid traversal +// +// Like wxGridOperations it's an ABC with two concrete subclasses below. Unlike +// it, this is a normal object and not just a function dispatch table and has a +// non-default ctor. +// +// Note: the explanation of this discrepancy is the existence of (very useful) +// Dual() method in wxGridOperations which forces us to make wxGridOperations a +// function dispatcher only. +class wxGridDirectionOperations +{ +public: + // The oper parameter to ctor selects whether we work with rows or columns + wxGridDirectionOperations(wxGrid *grid, const wxGridOperations& oper) + : m_grid(grid), + m_oper(oper) + { + } + + // Check if the component of this point in our direction is at the + // boundary, i.e. is the first/last row/column + virtual bool IsAtBoundary(const wxGridCellCoords& coords) const = 0; + + // Increment the component of this point in our direction + virtual void Advance(wxGridCellCoords& coords) const = 0; + + // Find the line at the given distance, in pixels, away from this one + // (this uses clipping, i.e. anything after the last line is counted as the + // last one and anything before the first one as 0) + virtual int MoveByPixelDistance(int line, int distance) const = 0; + + // This class is never used polymorphically but give it a virtual dtor + // anyhow to suppress g++ complaints about it + virtual ~wxGridDirectionOperations() { } + +protected: + wxGrid * const m_grid; + const wxGridOperations& m_oper; +}; + +class wxGridBackwardOperations : public wxGridDirectionOperations +{ +public: + wxGridBackwardOperations(wxGrid *grid, const wxGridOperations& oper) + : wxGridDirectionOperations(grid, oper) + { + } + + virtual bool IsAtBoundary(const wxGridCellCoords& coords) const + { + wxASSERT_MSG( m_oper.Select(coords) >= 0, "invalid row/column" ); + + return m_oper.Select(coords) == 0; + } + + virtual void Advance(wxGridCellCoords& coords) const + { + wxASSERT( !IsAtBoundary(coords) ); + + m_oper.Set(coords, m_oper.Select(coords) - 1); + } + + virtual int MoveByPixelDistance(int line, int distance) const + { + int pos = m_oper.GetLineStartPos(m_grid, line); + return m_oper.PosToLine(m_grid, pos - distance + 1, true); + } +}; + +class wxGridForwardOperations : public wxGridDirectionOperations +{ +public: + wxGridForwardOperations(wxGrid *grid, const wxGridOperations& oper) + : wxGridDirectionOperations(grid, oper), + m_numLines(oper.GetNumberOfLines(grid)) + { + } + + virtual bool IsAtBoundary(const wxGridCellCoords& coords) const + { + wxASSERT_MSG( m_oper.Select(coords) < m_numLines, "invalid row/column" ); + + return m_oper.Select(coords) == m_numLines - 1; + } + + virtual void Advance(wxGridCellCoords& coords) const + { + wxASSERT( !IsAtBoundary(coords) ); + + m_oper.Set(coords, m_oper.Select(coords) + 1); + } + + virtual int MoveByPixelDistance(int line, int distance) const + { + int pos = m_oper.GetLineStartPos(m_grid, line); + return m_oper.PosToLine(m_grid, pos + distance, true); + } + +private: + const int m_numLines; +}; // ---------------------------------------------------------------------------- // globals @@ -2863,7 +3005,7 @@ void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col) wxGridCellAttr *wxGridCellAttrData::GetAttr(int row, int col) const { - wxGridCellAttr *attr = (wxGridCellAttr *)NULL; + wxGridCellAttr *attr = NULL; int n = FindIndex(row, col); if ( n != wxNOT_FOUND ) @@ -2973,7 +3115,7 @@ wxGridRowOrColAttrData::~wxGridRowOrColAttrData() wxGridCellAttr *wxGridRowOrColAttrData::GetAttr(int rowOrCol) const { - wxGridCellAttr *attr = (wxGridCellAttr *)NULL; + wxGridCellAttr *attr = NULL; int n = m_rowsOrCols.Index(rowOrCol); if ( n != wxNOT_FOUND ) @@ -3059,7 +3201,7 @@ void wxGridRowOrColAttrData::UpdateAttrRowsOrCols( size_t pos, int numRowsOrCols wxGridCellAttrProvider::wxGridCellAttrProvider() { - m_data = (wxGridCellAttrProviderData *)NULL; + m_data = NULL; } wxGridCellAttrProvider::~wxGridCellAttrProvider() @@ -3075,7 +3217,7 @@ void wxGridCellAttrProvider::InitData() wxGridCellAttr *wxGridCellAttrProvider::GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind ) const { - wxGridCellAttr *attr = (wxGridCellAttr *)NULL; + wxGridCellAttr *attr = NULL; if ( m_data ) { switch (kind) @@ -3377,8 +3519,8 @@ IMPLEMENT_ABSTRACT_CLASS( wxGridTableBase, wxObject ) wxGridTableBase::wxGridTableBase() { - m_view = (wxGrid *) NULL; - m_attrProvider = (wxGridCellAttrProvider *) NULL; + m_view = NULL; + m_attrProvider = NULL; } wxGridTableBase::~wxGridTableBase() @@ -3408,7 +3550,7 @@ wxGridCellAttr *wxGridTableBase::GetAttr(int row, int col, wxGridCellAttr::wxAtt if ( m_attrProvider ) return m_attrProvider->GetAttr(row, col, kind); else - return (wxGridCellAttr *)NULL; + return NULL; } void wxGridTableBase::SetAttr(wxGridCellAttr* attr, int row, int col) @@ -3607,7 +3749,7 @@ void wxGridTableBase::SetValueAsCustom( int WXUNUSED(row), int WXUNUSED(col), wxGridTableMessage::wxGridTableMessage() { - m_table = (wxGridTableBase *) NULL; + m_table = NULL; m_id = -1; m_comInt1 = -1; m_comInt2 = -1; @@ -4661,7 +4803,7 @@ void wxGrid::Init() m_canDragColMove = false; m_cursorMode = WXGRID_CURSOR_SELECT_CELL; - m_winCapture = (wxWindow *)NULL; + m_winCapture = NULL; m_canDragRowSize = true; m_canDragColSize = true; m_canDragGridSize = true; @@ -6037,7 +6179,7 @@ void wxGrid::ChangeCursorMode(CursorMode mode, { if (m_winCapture->HasCapture()) m_winCapture->ReleaseMouse(); - m_winCapture = (wxWindow *)NULL; + m_winCapture = NULL; } m_cursorMode = mode; @@ -6691,7 +6833,7 @@ bool wxGrid::ProcessTableMessage( wxGridTableMessage& msg ) // The behaviour of this function depends on the grid table class // Clear() function. For the default wxGridStringTable class the -// behavious is to replace all cell contents with wxEmptyString but +// behaviour is to replace all cell contents with wxEmptyString but // not to change the number of rows or cols. // void wxGrid::ClearGrid() @@ -6707,132 +6849,34 @@ void wxGrid::ClearGrid() } } -bool wxGrid::InsertRows( int pos, int numRows, bool WXUNUSED(updateLabels) ) -{ - if ( !m_created ) - { - wxFAIL_MSG( wxT("Called wxGrid::InsertRows() before calling CreateGrid()") ); - return false; - } - - if ( m_table ) - { - if (IsCellEditControlEnabled()) - DisableCellEditControl(); - - bool done = m_table->InsertRows( pos, numRows ); - return done; - - // the table will have sent the results of the insert row - // operation to this view object as a grid table message - } - - return false; -} - -bool wxGrid::AppendRows( int numRows, bool WXUNUSED(updateLabels) ) -{ - if ( !m_created ) - { - wxFAIL_MSG( wxT("Called wxGrid::AppendRows() before calling CreateGrid()") ); - return false; - } - - if ( m_table ) - { - bool done = m_table && m_table->AppendRows( numRows ); - return done; - - // the table will have sent the results of the append row - // operation to this view object as a grid table message - } - - return false; -} - -bool wxGrid::DeleteRows( int pos, int numRows, bool WXUNUSED(updateLabels) ) +bool +wxGrid::DoModifyLines(bool (wxGridTableBase::*funcModify)(size_t, size_t), + int pos, int num, bool WXUNUSED(updateLabels) ) { - if ( !m_created ) - { - wxFAIL_MSG( wxT("Called wxGrid::DeleteRows() before calling CreateGrid()") ); - return false; - } - - if ( m_table ) - { - if (IsCellEditControlEnabled()) - DisableCellEditControl(); - - bool done = m_table->DeleteRows( pos, numRows ); - return done; - // the table will have sent the results of the delete row - // operation to this view object as a grid table message - } - - return false; -} + wxCHECK_MSG( m_created, false, "must finish creating the grid first" ); -bool wxGrid::InsertCols( int pos, int numCols, bool WXUNUSED(updateLabels) ) -{ - if ( !m_created ) - { - wxFAIL_MSG( wxT("Called wxGrid::InsertCols() before calling CreateGrid()") ); + if ( !m_table ) return false; - } - if ( m_table ) - { - if (IsCellEditControlEnabled()) - DisableCellEditControl(); + if ( IsCellEditControlEnabled() ) + DisableCellEditControl(); - bool done = m_table->InsertCols( pos, numCols ); - return done; - // the table will have sent the results of the insert col - // operation to this view object as a grid table message - } + return (m_table->*funcModify)(pos, num); - return false; + // the table will have sent the results of the insert row + // operation to this view object as a grid table message } -bool wxGrid::AppendCols( int numCols, bool WXUNUSED(updateLabels) ) +bool +wxGrid::DoAppendLines(bool (wxGridTableBase::*funcAppend)(size_t), + int num, bool WXUNUSED(updateLabels)) { - if ( !m_created ) - { - wxFAIL_MSG( wxT("Called wxGrid::AppendCols() before calling CreateGrid()") ); - return false; - } - - if ( m_table ) - { - bool done = m_table->AppendCols( numCols ); - return done; - // the table will have sent the results of the append col - // operation to this view object as a grid table message - } + wxCHECK_MSG( m_created, false, "must finish creating the grid first" ); - return false; -} - -bool wxGrid::DeleteCols( int pos, int numCols, bool WXUNUSED(updateLabels) ) -{ - if ( !m_created ) - { - wxFAIL_MSG( wxT("Called wxGrid::DeleteCols() before calling CreateGrid()") ); + if ( !m_table ) return false; - } - if ( m_table ) - { - if (IsCellEditControlEnabled()) - DisableCellEditControl(); - - bool done = m_table->DeleteCols( pos, numCols ); - return done; - // the table will have sent the results of the delete col - // operation to this view object as a grid table message - } - - return false; + return (m_table->*funcAppend)(num); } // @@ -7768,27 +7812,6 @@ void wxGrid::DrawCellHighlight( wxDC& dc, const wxGridCellAttr *attr ) dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRectangle(rect); } - -#if 0 - // VZ: my experiments with 3D borders... - - // how to properly set colours for arbitrary bg? - wxCoord x1 = rect.x, - y1 = rect.y, - x2 = rect.x + rect.width - 1, - y2 = rect.y + rect.height - 1; - - dc.SetPen(*wxWHITE_PEN); - dc.DrawLine(x1, y1, x2, y1); - dc.DrawLine(x1, y1, x1, y2); - - dc.DrawLine(x1 + 1, y2 - 1, x2 - 1, y2 - 1); - dc.DrawLine(x2 - 1, y1 + 1, x2 - 1, y2); - - dc.SetPen(*wxBLACK_PEN); - dc.DrawLine(x1, y2, x2, y2); - dc.DrawLine(x2, y1, x2, y2 + 1); -#endif } wxPen wxGrid::GetDefaultGridLinePen() @@ -8331,8 +8354,6 @@ bool wxGrid::Enable(bool enable) void wxGrid::EnableEditing( bool edit ) { - // TODO: improve this ? - // if ( edit != m_editable ) { if (!edit) @@ -8733,55 +8754,48 @@ int wxGrid::XToCol(int x, bool clipToMinMax) const return PosToLine(x, clipToMinMax, wxGridColumnOperations()); } -// return the row number that that the y coord is near -// the edge of, or -1 if not near an edge. +// return the row number that 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_ nead the edge (i.e., if the height/width is smaller +// 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. // -int wxGrid::YToEdgeOfRow( int y ) const +int wxGrid::PosToEdgeOfLine(int pos, const wxGridOperations& oper) const { - int i; - i = internalYToRow(y); + if ( !oper.CanResizeLines(this) ) + return -1; - if ( GetRowHeight(i) > WXGRID_LABEL_EDGE_ZONE && CanDragRowSize() ) + const int line = oper.PosToLine(this, pos, true); + + if ( oper.GetLineSize(this, line) > WXGRID_LABEL_EDGE_ZONE ) { - // We know that we are in row i, test whether we are - // close enough to lower or upper border, respectively. - if ( abs(GetRowBottom(i) - y) < WXGRID_LABEL_EDGE_ZONE ) - return i; - else if ( i > 0 && y - GetRowTop(i) < WXGRID_LABEL_EDGE_ZONE ) - return i - 1; + // We know that we are in this line, test whether we are close enough + // to start or end border, respectively. + if ( abs(oper.GetLineEndPos(this, line) - pos) < WXGRID_LABEL_EDGE_ZONE ) + return line; + else if ( line > 0 && + pos - oper.GetLineStartPos(this, + line) < WXGRID_LABEL_EDGE_ZONE ) + return line - 1; } return -1; } -// return the col number that that the x coord is near the edge of, or -// -1 if not near an edge -// See comment at YToEdgeOfRow for conditions on edge detection. -// -int wxGrid::XToEdgeOfCol( int x ) const +int wxGrid::YToEdgeOfRow(int y) const { - int i; - i = internalXToCol(x); - - if ( GetColWidth(i) > WXGRID_LABEL_EDGE_ZONE && CanDragColSize() ) - { - // We know that we are in column i; test whether we are - // close enough to right or left border, respectively. - if ( abs(GetColRight(i) - x) < WXGRID_LABEL_EDGE_ZONE ) - return i; - else if ( i > 0 && x - GetColLeft(i) < WXGRID_LABEL_EDGE_ZONE ) - return i - 1; - } + return PosToEdgeOfLine(y, wxGridRowOperations()); +} - return -1; +int wxGrid::XToEdgeOfCol(int x) const +{ + return PosToEdgeOfLine(x, wxGridColumnOperations()); } wxRect wxGrid::CellToRect( int row, int col ) const @@ -8934,463 +8948,200 @@ void wxGrid::MakeCellVisible( int row, int col ) // ------ Grid cursor movement functions // -bool wxGrid::MoveCursorUp( bool expandSelection ) +bool +wxGrid::DoMoveCursor(bool expandSelection, + const wxGridDirectionOperations& diroper) { - if ( m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetRow() >= 0 ) + if ( m_currentCellCoords == wxGridNoCellCoords ) + return false; + + if ( expandSelection ) { - if ( expandSelection ) - { - if ( m_selectingKeyboard == wxGridNoCellCoords ) - m_selectingKeyboard = m_currentCellCoords; - if ( m_selectingKeyboard.GetRow() > 0 ) - { - m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() - 1 ); - MakeCellVisible( m_selectingKeyboard.GetRow(), - m_selectingKeyboard.GetCol() ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - } - else if ( m_currentCellCoords.GetRow() > 0 ) - { - int row = m_currentCellCoords.GetRow() - 1; - int col = m_currentCellCoords.GetCol(); - ClearSelection(); - MakeCellVisible( row, col ); - SetCurrentCell( row, col ); - } - else - return false; + if ( m_selectingKeyboard == wxGridNoCellCoords ) + m_selectingKeyboard = m_currentCellCoords; - return true; - } + if ( diroper.IsAtBoundary(m_selectingKeyboard) ) + return false; - return false; -} + diroper.Advance(m_selectingKeyboard); -bool wxGrid::MoveCursorDown( bool expandSelection ) -{ - if ( m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetRow() < m_numRows ) + MakeCellVisible(m_selectingKeyboard); + HighlightBlock(m_currentCellCoords, m_selectingKeyboard); + } + else { - if ( expandSelection ) - { - if ( m_selectingKeyboard == wxGridNoCellCoords ) - m_selectingKeyboard = m_currentCellCoords; - if ( m_selectingKeyboard.GetRow() < m_numRows - 1 ) - { - m_selectingKeyboard.SetRow( m_selectingKeyboard.GetRow() + 1 ); - MakeCellVisible( m_selectingKeyboard.GetRow(), - m_selectingKeyboard.GetCol() ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - } - else if ( m_currentCellCoords.GetRow() < m_numRows - 1 ) - { - int row = m_currentCellCoords.GetRow() + 1; - int col = m_currentCellCoords.GetCol(); - ClearSelection(); - MakeCellVisible( row, col ); - SetCurrentCell( row, col ); - } - else + if ( diroper.IsAtBoundary(m_currentCellCoords) ) return false; - return true; + ClearSelection(); + + wxGridCellCoords coords = m_currentCellCoords; + diroper.Advance(coords); + MakeCellVisible(coords); + SetCurrentCell(coords); } - return false; + return true; } -bool wxGrid::MoveCursorLeft( bool expandSelection ) +bool wxGrid::MoveCursorUp(bool expandSelection) { - if ( m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetCol() >= 0 ) - { - if ( expandSelection ) - { - if ( m_selectingKeyboard == wxGridNoCellCoords ) - m_selectingKeyboard = m_currentCellCoords; - if ( m_selectingKeyboard.GetCol() > 0 ) - { - m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() - 1 ); - MakeCellVisible( m_selectingKeyboard.GetRow(), - m_selectingKeyboard.GetCol() ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - } - else if ( GetColPos( m_currentCellCoords.GetCol() ) > 0 ) - { - int row = m_currentCellCoords.GetRow(); - int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) - 1 ); - ClearSelection(); - - MakeCellVisible( row, col ); - SetCurrentCell( row, col ); - } - else - return false; - - return true; - } - - return false; + return DoMoveCursor(expandSelection, + wxGridBackwardOperations(this, wxGridRowOperations())); } -bool wxGrid::MoveCursorRight( bool expandSelection ) +bool wxGrid::MoveCursorDown(bool expandSelection) { - if ( m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetCol() < m_numCols ) - { - if ( expandSelection ) - { - if ( m_selectingKeyboard == wxGridNoCellCoords ) - m_selectingKeyboard = m_currentCellCoords; - if ( m_selectingKeyboard.GetCol() < m_numCols - 1 ) - { - m_selectingKeyboard.SetCol( m_selectingKeyboard.GetCol() + 1 ); - MakeCellVisible( m_selectingKeyboard.GetRow(), - m_selectingKeyboard.GetCol() ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - } - else if ( GetColPos( m_currentCellCoords.GetCol() ) < m_numCols - 1 ) - { - int row = m_currentCellCoords.GetRow(); - int col = GetColAt( GetColPos( m_currentCellCoords.GetCol() ) + 1 ); - ClearSelection(); - - MakeCellVisible( row, col ); - SetCurrentCell( row, col ); - } - else - return false; + return DoMoveCursor(expandSelection, + wxGridForwardOperations(this, wxGridRowOperations())); +} - return true; - } +bool wxGrid::MoveCursorLeft(bool expandSelection) +{ + return DoMoveCursor(expandSelection, + wxGridBackwardOperations(this, wxGridColumnOperations())); +} - return false; +bool wxGrid::MoveCursorRight(bool expandSelection) +{ + return DoMoveCursor(expandSelection, + wxGridForwardOperations(this, wxGridColumnOperations())); } -bool wxGrid::MovePageUp() +bool wxGrid::DoMoveCursorByPage(const wxGridDirectionOperations& diroper) { if ( m_currentCellCoords == wxGridNoCellCoords ) return false; - int row = m_currentCellCoords.GetRow(); - if ( row > 0 ) - { - int cw, ch; - m_gridWin->GetClientSize( &cw, &ch ); - - int y = GetRowTop(row); - int newRow = internalYToRow( y - ch + 1 ); + if ( diroper.IsAtBoundary(m_currentCellCoords) ) + return false; - if ( newRow == row ) - { - // row > 0, so newRow can never be less than 0 here. - newRow = row - 1; - } + const int oldRow = m_currentCellCoords.GetRow(); + int newRow = diroper.MoveByPixelDistance(oldRow, m_gridWin->GetClientSize().y); + if ( newRow == oldRow ) + { + wxGridCellCoords coords(m_currentCellCoords); + diroper.Advance(coords); + newRow = coords.GetRow(); + } - MakeCellVisible( newRow, m_currentCellCoords.GetCol() ); - SetCurrentCell( newRow, m_currentCellCoords.GetCol() ); + MakeCellVisible(newRow, m_currentCellCoords.GetCol()); + SetCurrentCell(newRow, m_currentCellCoords.GetCol()); - return true; - } + return true; +} - return false; +bool wxGrid::MovePageUp() +{ + return DoMoveCursorByPage( + wxGridBackwardOperations(this, wxGridRowOperations())); } bool wxGrid::MovePageDown() { - if ( m_currentCellCoords == wxGridNoCellCoords ) - return false; + return DoMoveCursorByPage( + wxGridForwardOperations(this, wxGridColumnOperations())); +} - int row = m_currentCellCoords.GetRow(); - if ( (row + 1) < m_numRows ) +// helper of DoMoveCursorByBlock(): advance the cell coordinates using diroper +// until we find a non-empty cell or reach the grid end +void +wxGrid::AdvanceToNextNonEmpty(wxGridCellCoords& coords, + const wxGridDirectionOperations& diroper) +{ + while ( !diroper.IsAtBoundary(coords) ) { - int cw, ch; - m_gridWin->GetClientSize( &cw, &ch ); - - int y = GetRowTop(row); - int newRow = internalYToRow( y + ch ); - if ( newRow == row ) - { - // row < m_numRows, so newRow can't overflow here. - newRow = row + 1; - } - - MakeCellVisible( newRow, m_currentCellCoords.GetCol() ); - SetCurrentCell( newRow, m_currentCellCoords.GetCol() ); - - return true; + diroper.Advance(coords); + if ( !m_table->IsEmpty(coords) ) + break; } - - return false; } -bool wxGrid::MoveCursorUpBlock( bool expandSelection ) +bool +wxGrid::DoMoveCursorByBlock(bool expandSelection, + const wxGridDirectionOperations& diroper) { - if ( m_table && - m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetRow() > 0 ) - { - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - - if ( m_table->IsEmptyCell(row, col) ) - { - // starting in an empty cell: find the next block of - // non-empty cells - // - while ( row > 0 ) - { - row--; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else if ( m_table->IsEmptyCell(row - 1, col) ) - { - // starting at the top of a block: find the next block - // - row--; - while ( row > 0 ) - { - row--; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else - { - // starting within a block: find the top of the block - // - while ( row > 0 ) - { - row--; - if ( m_table->IsEmptyCell(row, col) ) - { - row++; - break; - } - } - } + if ( !m_table || m_currentCellCoords == wxGridNoCellCoords ) + return false; - MakeCellVisible( row, col ); - if ( expandSelection ) - { - m_selectingKeyboard = wxGridCellCoords( row, col ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - else - { - ClearSelection(); - SetCurrentCell( row, col ); - } + if ( diroper.IsAtBoundary(m_currentCellCoords) ) + return false; - return true; + wxGridCellCoords coords(m_currentCellCoords); + if ( m_table->IsEmpty(coords) ) + { + // we are in an empty cell: find the next block of non-empty cells + AdvanceToNextNonEmpty(coords, diroper); } - - return false; -} - -bool wxGrid::MoveCursorDownBlock( bool expandSelection ) -{ - if ( m_table && - m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetRow() < m_numRows - 1 ) + else // current cell is not empty { - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - - if ( m_table->IsEmptyCell(row, col) ) - { - // starting in an empty cell: find the next block of - // non-empty cells - // - while ( row < m_numRows - 1 ) - { - row++; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else if ( m_table->IsEmptyCell(row + 1, col) ) + diroper.Advance(coords); + if ( m_table->IsEmpty(coords) ) { - // starting at the bottom of a block: find the next block - // - row++; - while ( row < m_numRows - 1 ) - { - row++; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } + // we started at the end of a block, find the next one + AdvanceToNextNonEmpty(coords, diroper); } - else + else // we're in a middle of a block { - // starting within a block: find the bottom of the block - // - while ( row < m_numRows - 1 ) + // go to the end of it, i.e. find the last cell before the next + // empty one + while ( !diroper.IsAtBoundary(coords) ) { - row++; - if ( m_table->IsEmptyCell(row, col) ) - { - row--; + wxGridCellCoords coordsNext(coords); + diroper.Advance(coordsNext); + if ( m_table->IsEmpty(coordsNext) ) break; - } - } - } - MakeCellVisible( row, col ); - if ( expandSelection ) - { - m_selectingKeyboard = wxGridCellCoords( row, col ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - else - { - ClearSelection(); - SetCurrentCell( row, col ); + coords = coordsNext; + } } + } - return true; + MakeCellVisible(coords); + if ( expandSelection ) + { + m_selectingKeyboard = coords; + HighlightBlock(m_currentCellCoords, m_selectingKeyboard); + } + else + { + ClearSelection(); + SetCurrentCell(coords); } - return false; + return true; } -bool wxGrid::MoveCursorLeftBlock( bool expandSelection ) +bool wxGrid::MoveCursorUpBlock(bool expandSelection) { - if ( m_table && - m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetCol() > 0 ) - { - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - - if ( m_table->IsEmptyCell(row, col) ) - { - // starting in an empty cell: find the next block of - // non-empty cells - // - while ( col > 0 ) - { - col--; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else if ( m_table->IsEmptyCell(row, col - 1) ) - { - // starting at the left of a block: find the next block - // - col--; - while ( col > 0 ) - { - col--; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else - { - // starting within a block: find the left of the block - // - while ( col > 0 ) - { - col--; - if ( m_table->IsEmptyCell(row, col) ) - { - col++; - break; - } - } - } - - MakeCellVisible( row, col ); - if ( expandSelection ) - { - m_selectingKeyboard = wxGridCellCoords( row, col ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - else - { - ClearSelection(); - SetCurrentCell( row, col ); - } + return DoMoveCursorByBlock( + expandSelection, + wxGridBackwardOperations(this, wxGridRowOperations()) + ); +} - return true; - } +bool wxGrid::MoveCursorDownBlock( bool expandSelection ) +{ + return DoMoveCursorByBlock( + expandSelection, + wxGridForwardOperations(this, wxGridRowOperations()) + ); +} - return false; +bool wxGrid::MoveCursorLeftBlock( bool expandSelection ) +{ + return DoMoveCursorByBlock( + expandSelection, + wxGridBackwardOperations(this, wxGridColumnOperations()) + ); } bool wxGrid::MoveCursorRightBlock( bool expandSelection ) { - if ( m_table && - m_currentCellCoords != wxGridNoCellCoords && - m_currentCellCoords.GetCol() < m_numCols - 1 ) - { - int row = m_currentCellCoords.GetRow(); - int col = m_currentCellCoords.GetCol(); - - if ( m_table->IsEmptyCell(row, col) ) - { - // starting in an empty cell: find the next block of - // non-empty cells - // - while ( col < m_numCols - 1 ) - { - col++; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else if ( m_table->IsEmptyCell(row, col + 1) ) - { - // starting at the right of a block: find the next block - // - col++; - while ( col < m_numCols - 1 ) - { - col++; - if ( !(m_table->IsEmptyCell(row, col)) ) - break; - } - } - else - { - // starting within a block: find the right of the block - // - while ( col < m_numCols - 1 ) - { - col++; - if ( m_table->IsEmptyCell(row, col) ) - { - col--; - break; - } - } - } - - MakeCellVisible( row, col ); - if ( expandSelection ) - { - m_selectingKeyboard = wxGridCellCoords( row, col ); - HighlightBlock( m_currentCellCoords, m_selectingKeyboard ); - } - else - { - ClearSelection(); - SetCurrentCell( row, col ); - } - - return true; - } - - return false; + return DoMoveCursorByBlock( + expandSelection, + wxGridForwardOperations(this, wxGridColumnOperations()) + ); } // @@ -10026,7 +9777,7 @@ wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const if ( !LookupAttr(row, col, &attr) ) { attr = m_table ? m_table->GetAttr(row, col, wxGridCellAttr::Any) - : (wxGridCellAttr *)NULL; + : NULL; CacheAttr(row, col, attr); } } @@ -10046,7 +9797,7 @@ wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const { - wxGridCellAttr *attr = (wxGridCellAttr *)NULL; + wxGridCellAttr *attr = NULL; bool canHave = ((wxGrid*)this)->CanHaveAttributes(); wxCHECK_MSG( canHave, attr, _T("Cell attributes not allowed")); -- 2.45.2