+ return rect;
+}
+
+bool wxGrid::IsVisible( int row, int col, bool wholeCellVisible ) const
+{
+ // get the cell rectangle in logical coords
+ //
+ wxRect r( CellToRect( row, col ) );
+
+ // convert to device coords
+ //
+ int left, top, right, bottom;
+ CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
+ CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
+
+ // check against the client area of the grid window
+ int cw, ch;
+ m_gridWin->GetClientSize( &cw, &ch );
+
+ if ( wholeCellVisible )
+ {
+ // is the cell wholly visible ?
+ return ( left >= 0 && right <= cw &&
+ top >= 0 && bottom <= ch );
+ }
+ else
+ {
+ // is the cell partly visible ?
+ //
+ return ( ((left >= 0 && left < cw) || (right > 0 && right <= cw)) &&
+ ((top >= 0 && top < ch) || (bottom > 0 && bottom <= ch)) );
+ }
+}
+
+// make the specified cell location visible by doing a minimal amount
+// of scrolling
+//
+void wxGrid::MakeCellVisible( int row, int col )
+{
+ int i;
+ int xpos = -1, ypos = -1;
+
+ if ( row >= 0 && row < m_numRows &&
+ col >= 0 && col < m_numCols )
+ {
+ // get the cell rectangle in logical coords
+ wxRect r( CellToRect( row, col ) );
+
+ // convert to device coords
+ int left, top, right, bottom;
+ CalcScrolledPosition( r.GetLeft(), r.GetTop(), &left, &top );
+ CalcScrolledPosition( r.GetRight(), r.GetBottom(), &right, &bottom );
+
+ int cw, ch;
+ m_gridWin->GetClientSize( &cw, &ch );
+
+ if ( top < 0 )
+ {
+ ypos = r.GetTop();
+ }
+ else if ( bottom > ch )
+ {
+ int h = r.GetHeight();
+ ypos = r.GetTop();
+ for ( i = row - 1; i >= 0; i-- )
+ {
+ int rowHeight = GetRowHeight(i);
+ if ( h + rowHeight > ch )
+ break;
+
+ h += rowHeight;
+ ypos -= rowHeight;
+ }
+
+ // we divide it later by GRID_SCROLL_LINE, make sure that we don't
+ // have rounding errors (this is important, because if we do,
+ // we might not scroll at all and some cells won't be redrawn)
+ //
+ // Sometimes GRID_SCROLL_LINE / 2 is not enough,
+ // so just add a full scroll unit...
+ ypos += m_yScrollPixelsPerLine;
+ }
+
+ // special handling for wide cells - show always left part of the cell!
+ // Otherwise, e.g. when stepping from row to row, it would jump between
+ // left and right part of the cell on every step!
+// if ( left < 0 )
+ if ( left < 0 || (right - left) >= cw )
+ {
+ xpos = r.GetLeft();
+ }
+ else if ( right > cw )
+ {
+ // position the view so that the cell is on the right
+ int x0, y0;
+ CalcUnscrolledPosition(0, 0, &x0, &y0);
+ xpos = x0 + (right - cw);
+
+ // see comment for ypos above
+ xpos += m_xScrollPixelsPerLine;
+ }
+
+ if ( xpos != -1 || ypos != -1 )
+ {
+ if ( xpos != -1 )
+ xpos /= m_xScrollPixelsPerLine;
+ if ( ypos != -1 )
+ ypos /= m_yScrollPixelsPerLine;
+ Scroll( xpos, ypos );
+ AdjustScrollbars();
+ }
+ }
+}
+
+//
+// ------ Grid cursor movement functions
+//
+
+bool
+wxGrid::DoMoveCursor(bool expandSelection,
+ const wxGridDirectionOperations& diroper)
+{
+ if ( m_currentCellCoords == wxGridNoCellCoords )
+ return false;
+
+ if ( expandSelection )
+ {
+ wxGridCellCoords coords = m_selectedBlockCorner;
+ if ( coords == wxGridNoCellCoords )
+ coords = m_currentCellCoords;
+
+ if ( diroper.IsAtBoundary(coords) )
+ return false;
+
+ diroper.Advance(coords);
+
+ UpdateBlockBeingSelected(m_currentCellCoords, coords);
+ }
+ else // don't expand selection
+ {
+ ClearSelection();
+
+ if ( diroper.IsAtBoundary(m_currentCellCoords) )
+ return false;
+
+ wxGridCellCoords coords = m_currentCellCoords;
+ diroper.Advance(coords);
+
+ GoToCell(coords);
+ }
+
+ return true;
+}
+
+bool wxGrid::MoveCursorUp(bool expandSelection)
+{
+ return DoMoveCursor(expandSelection,
+ wxGridBackwardOperations(this, wxGridRowOperations()));
+}
+
+bool wxGrid::MoveCursorDown(bool expandSelection)
+{
+ return DoMoveCursor(expandSelection,
+ wxGridForwardOperations(this, wxGridRowOperations()));
+}
+
+bool wxGrid::MoveCursorLeft(bool expandSelection)
+{
+ return DoMoveCursor(expandSelection,
+ wxGridBackwardOperations(this, wxGridColumnOperations()));
+}
+
+bool wxGrid::MoveCursorRight(bool expandSelection)
+{
+ return DoMoveCursor(expandSelection,
+ wxGridForwardOperations(this, wxGridColumnOperations()));
+}
+
+bool wxGrid::DoMoveCursorByPage(const wxGridDirectionOperations& diroper)
+{
+ if ( m_currentCellCoords == wxGridNoCellCoords )
+ return false;
+
+ if ( diroper.IsAtBoundary(m_currentCellCoords) )
+ return false;
+
+ 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();
+ }
+
+ GoToCell(newRow, m_currentCellCoords.GetCol());
+
+ return true;
+}
+
+bool wxGrid::MovePageUp()
+{
+ return DoMoveCursorByPage(
+ wxGridBackwardOperations(this, wxGridRowOperations()));
+}
+
+bool wxGrid::MovePageDown()
+{
+ return DoMoveCursorByPage(
+ wxGridForwardOperations(this, wxGridRowOperations()));
+}
+
+// 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) )
+ {
+ diroper.Advance(coords);
+ if ( !m_table->IsEmpty(coords) )
+ break;
+ }
+}
+
+bool
+wxGrid::DoMoveCursorByBlock(bool expandSelection,
+ const wxGridDirectionOperations& diroper)
+{
+ if ( !m_table || m_currentCellCoords == wxGridNoCellCoords )
+ return false;
+
+ if ( diroper.IsAtBoundary(m_currentCellCoords) )
+ return false;
+
+ 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);
+ }
+ else // current cell is not empty
+ {
+ diroper.Advance(coords);
+ if ( m_table->IsEmpty(coords) )
+ {
+ // we started at the end of a block, find the next one
+ AdvanceToNextNonEmpty(coords, diroper);
+ }
+ else // we're in a middle of a block
+ {
+ // go to the end of it, i.e. find the last cell before the next
+ // empty one
+ while ( !diroper.IsAtBoundary(coords) )
+ {
+ wxGridCellCoords coordsNext(coords);
+ diroper.Advance(coordsNext);
+ if ( m_table->IsEmpty(coordsNext) )
+ break;
+
+ coords = coordsNext;
+ }
+ }
+ }
+
+ if ( expandSelection )
+ {
+ UpdateBlockBeingSelected(m_currentCellCoords, coords);
+ }
+ else
+ {
+ ClearSelection();
+ GoToCell(coords);
+ }
+
+ return true;
+}
+
+bool wxGrid::MoveCursorUpBlock(bool expandSelection)
+{
+ return DoMoveCursorByBlock(
+ expandSelection,
+ wxGridBackwardOperations(this, wxGridRowOperations())
+ );
+}
+
+bool wxGrid::MoveCursorDownBlock( bool expandSelection )
+{
+ return DoMoveCursorByBlock(
+ expandSelection,
+ wxGridForwardOperations(this, wxGridRowOperations())
+ );
+}
+
+bool wxGrid::MoveCursorLeftBlock( bool expandSelection )
+{
+ return DoMoveCursorByBlock(
+ expandSelection,
+ wxGridBackwardOperations(this, wxGridColumnOperations())
+ );
+}
+
+bool wxGrid::MoveCursorRightBlock( bool expandSelection )
+{
+ return DoMoveCursorByBlock(
+ expandSelection,
+ wxGridForwardOperations(this, wxGridColumnOperations())
+ );
+}
+
+//
+// ------ Label values and formatting
+//
+
+void wxGrid::GetRowLabelAlignment( int *horiz, int *vert ) const
+{
+ if ( horiz )
+ *horiz = m_rowLabelHorizAlign;
+ if ( vert )
+ *vert = m_rowLabelVertAlign;
+}
+
+void wxGrid::GetColLabelAlignment( int *horiz, int *vert ) const
+{
+ if ( horiz )
+ *horiz = m_colLabelHorizAlign;
+ if ( vert )
+ *vert = m_colLabelVertAlign;
+}
+
+int wxGrid::GetColLabelTextOrientation() const
+{
+ return m_colLabelTextOrientation;
+}
+
+wxString wxGrid::GetRowLabelValue( int row ) const
+{
+ if ( m_table )
+ {
+ return m_table->GetRowLabelValue( row );
+ }
+ else
+ {
+ wxString s;
+ s << row;
+ return s;
+ }
+}
+
+wxString wxGrid::GetColLabelValue( int col ) const
+{
+ if ( m_table )
+ {
+ return m_table->GetColLabelValue( col );
+ }
+ else
+ {
+ wxString s;
+ s << col;
+ return s;
+ }
+}
+
+void wxGrid::SetRowLabelSize( int width )
+{
+ wxASSERT( width >= 0 || width == wxGRID_AUTOSIZE );
+
+ if ( width == wxGRID_AUTOSIZE )
+ {
+ width = CalcColOrRowLabelAreaMinSize(wxGRID_ROW);
+ }
+
+ if ( width != m_rowLabelWidth )
+ {
+ if ( width == 0 )
+ {
+ m_rowLabelWin->Show( false );
+ m_cornerLabelWin->Show( false );
+ }
+ else if ( m_rowLabelWidth == 0 )
+ {
+ m_rowLabelWin->Show( true );
+ if ( m_colLabelHeight > 0 )
+ m_cornerLabelWin->Show( true );
+ }
+
+ m_rowLabelWidth = width;
+ CalcWindowSizes();
+ wxScrolledWindow::Refresh( true );
+ }
+}
+
+void wxGrid::SetColLabelSize( int height )
+{
+ wxASSERT( height >=0 || height == wxGRID_AUTOSIZE );
+
+ if ( height == wxGRID_AUTOSIZE )
+ {
+ height = CalcColOrRowLabelAreaMinSize(wxGRID_COLUMN);
+ }
+
+ if ( height != m_colLabelHeight )
+ {
+ if ( height == 0 )
+ {
+ m_colWindow->Show( false );
+ m_cornerLabelWin->Show( false );
+ }
+ else if ( m_colLabelHeight == 0 )
+ {
+ m_colWindow->Show( true );
+ if ( m_rowLabelWidth > 0 )
+ m_cornerLabelWin->Show( true );
+ }
+
+ m_colLabelHeight = height;
+ CalcWindowSizes();
+ wxScrolledWindow::Refresh( true );
+ }
+}
+
+void wxGrid::SetLabelBackgroundColour( const wxColour& colour )
+{
+ if ( m_labelBackgroundColour != colour )
+ {
+ m_labelBackgroundColour = colour;
+ m_rowLabelWin->SetBackgroundColour( colour );
+ m_colWindow->SetBackgroundColour( colour );
+ m_cornerLabelWin->SetBackgroundColour( colour );
+
+ if ( !GetBatchCount() )
+ {
+ m_rowLabelWin->Refresh();
+ m_colWindow->Refresh();
+ m_cornerLabelWin->Refresh();
+ }
+ }
+}
+
+void wxGrid::SetLabelTextColour( const wxColour& colour )
+{
+ if ( m_labelTextColour != colour )
+ {
+ m_labelTextColour = colour;
+ if ( !GetBatchCount() )
+ {
+ m_rowLabelWin->Refresh();
+ m_colWindow->Refresh();
+ }
+ }
+}
+
+void wxGrid::SetLabelFont( const wxFont& font )
+{
+ m_labelFont = font;
+ if ( !GetBatchCount() )
+ {
+ m_rowLabelWin->Refresh();
+ m_colWindow->Refresh();
+ }
+}
+
+void wxGrid::SetRowLabelAlignment( int horiz, int vert )
+{
+ // allow old (incorrect) defs to be used
+ switch ( horiz )
+ {
+ case wxLEFT: horiz = wxALIGN_LEFT; break;
+ case wxRIGHT: horiz = wxALIGN_RIGHT; break;
+ case wxCENTRE: horiz = wxALIGN_CENTRE; break;
+ }
+
+ switch ( vert )
+ {
+ case wxTOP: vert = wxALIGN_TOP; break;
+ case wxBOTTOM: vert = wxALIGN_BOTTOM; break;
+ case wxCENTRE: vert = wxALIGN_CENTRE; break;
+ }
+
+ if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT )
+ {
+ m_rowLabelHorizAlign = horiz;
+ }
+
+ if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM )
+ {
+ m_rowLabelVertAlign = vert;
+ }
+
+ if ( !GetBatchCount() )
+ {
+ m_rowLabelWin->Refresh();
+ }
+}
+
+void wxGrid::SetColLabelAlignment( int horiz, int vert )
+{
+ // allow old (incorrect) defs to be used
+ switch ( horiz )
+ {
+ case wxLEFT: horiz = wxALIGN_LEFT; break;
+ case wxRIGHT: horiz = wxALIGN_RIGHT; break;
+ case wxCENTRE: horiz = wxALIGN_CENTRE; break;
+ }
+
+ switch ( vert )
+ {
+ case wxTOP: vert = wxALIGN_TOP; break;
+ case wxBOTTOM: vert = wxALIGN_BOTTOM; break;
+ case wxCENTRE: vert = wxALIGN_CENTRE; break;
+ }
+
+ if ( horiz == wxALIGN_LEFT || horiz == wxALIGN_CENTRE || horiz == wxALIGN_RIGHT )
+ {
+ m_colLabelHorizAlign = horiz;
+ }
+
+ if ( vert == wxALIGN_TOP || vert == wxALIGN_CENTRE || vert == wxALIGN_BOTTOM )
+ {
+ m_colLabelVertAlign = vert;
+ }
+
+ if ( !GetBatchCount() )
+ {
+ m_colWindow->Refresh();
+ }
+}
+
+// Note: under MSW, the default column label font must be changed because it
+// does not support vertical printing
+//
+// Example: wxFont font(9, wxSWISS, wxNORMAL, wxBOLD);
+// pGrid->SetLabelFont(font);
+// pGrid->SetColLabelTextOrientation(wxVERTICAL);
+//
+void wxGrid::SetColLabelTextOrientation( int textOrientation )
+{
+ if ( textOrientation == wxHORIZONTAL || textOrientation == wxVERTICAL )
+ m_colLabelTextOrientation = textOrientation;
+
+ if ( !GetBatchCount() )
+ m_colWindow->Refresh();
+}
+
+void wxGrid::SetRowLabelValue( int row, const wxString& s )
+{
+ if ( m_table )
+ {
+ m_table->SetRowLabelValue( row, s );
+ if ( !GetBatchCount() )
+ {
+ wxRect rect = CellToRect( row, 0 );
+ if ( rect.height > 0 )
+ {
+ CalcScrolledPosition(0, rect.y, &rect.x, &rect.y);
+ rect.x = 0;
+ rect.width = m_rowLabelWidth;
+ m_rowLabelWin->Refresh( true, &rect );
+ }
+ }
+ }
+}
+
+void wxGrid::SetColLabelValue( int col, const wxString& s )
+{
+ if ( m_table )
+ {
+ m_table->SetColLabelValue( col, s );
+ if ( !GetBatchCount() )
+ {
+ if ( m_useNativeHeader )
+ {
+ GetGridColHeader()->UpdateColumn(col);
+ }
+ else
+ {
+ wxRect rect = CellToRect( 0, col );
+ if ( rect.width > 0 )
+ {
+ CalcScrolledPosition(rect.x, 0, &rect.x, &rect.y);
+ rect.y = 0;
+ rect.height = m_colLabelHeight;
+ GetColLabelWindow()->Refresh( true, &rect );
+ }
+ }
+ }
+ }
+}
+
+void wxGrid::SetGridLineColour( const wxColour& colour )
+{
+ if ( m_gridLineColour != colour )
+ {
+ m_gridLineColour = colour;
+
+ if ( GridLinesEnabled() )
+ RedrawGridLines();
+ }
+}
+
+void wxGrid::SetCellHighlightColour( const wxColour& colour )
+{
+ if ( m_cellHighlightColour != colour )
+ {
+ m_cellHighlightColour = colour;
+
+ wxClientDC dc( m_gridWin );
+ PrepareDC( dc );
+ wxGridCellAttr* attr = GetCellAttr(m_currentCellCoords);
+ DrawCellHighlight(dc, attr);
+ attr->DecRef();
+ }
+}
+
+void wxGrid::SetCellHighlightPenWidth(int width)
+{
+ if (m_cellHighlightPenWidth != width)
+ {
+ m_cellHighlightPenWidth = width;
+
+ // Just redrawing the cell highlight is not enough since that won't
+ // make any visible change if the thickness is getting smaller.
+ int row = m_currentCellCoords.GetRow();
+ int col = m_currentCellCoords.GetCol();
+ if ( row == -1 || col == -1 || GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
+ return;
+
+ wxRect rect = CellToRect(row, col);
+ m_gridWin->Refresh(true, &rect);
+ }
+}
+
+void wxGrid::SetCellHighlightROPenWidth(int width)
+{
+ if (m_cellHighlightROPenWidth != width)
+ {
+ m_cellHighlightROPenWidth = width;
+
+ // Just redrawing the cell highlight is not enough since that won't
+ // make any visible change if the thickness is getting smaller.
+ int row = m_currentCellCoords.GetRow();
+ int col = m_currentCellCoords.GetCol();
+ if ( row == -1 || col == -1 ||
+ GetColWidth(col) <= 0 || GetRowHeight(row) <= 0 )
+ return;
+
+ wxRect rect = CellToRect(row, col);
+ m_gridWin->Refresh(true, &rect);
+ }
+}
+
+void wxGrid::RedrawGridLines()
+{
+ // the lines will be redrawn when the window is thawn
+ if ( GetBatchCount() )
+ return;
+
+ if ( GridLinesEnabled() )
+ {
+ wxClientDC dc( m_gridWin );
+ PrepareDC( dc );
+ DrawAllGridLines( dc, wxRegion() );
+ }
+ else // remove the grid lines
+ {
+ m_gridWin->Refresh();
+ }
+}
+
+void wxGrid::EnableGridLines( bool enable )
+{
+ if ( enable != m_gridLinesEnabled )
+ {
+ m_gridLinesEnabled = enable;
+
+ RedrawGridLines();
+ }
+}
+
+void wxGrid::DoClipGridLines(bool& var, bool clip)
+{
+ if ( clip != var )
+ {
+ var = clip;
+
+ if ( GridLinesEnabled() )
+ RedrawGridLines();
+ }
+}
+
+int wxGrid::GetDefaultRowSize() const
+{
+ return m_defaultRowHeight;
+}
+
+int wxGrid::GetRowSize( int row ) const
+{
+ wxCHECK_MSG( row >= 0 && row < m_numRows, 0, wxT("invalid row index") );
+
+ return GetRowHeight(row);
+}
+
+int wxGrid::GetDefaultColSize() const
+{
+ return m_defaultColWidth;
+}
+
+int wxGrid::GetColSize( int col ) const
+{
+ wxCHECK_MSG( col >= 0 && col < m_numCols, 0, wxT("invalid column index") );
+
+ return GetColWidth(col);
+}
+
+// ============================================================================
+// access to the grid attributes: each of them has a default value in the grid
+// itself and may be overidden on a per-cell basis
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// setting default attributes
+// ----------------------------------------------------------------------------
+
+void wxGrid::SetDefaultCellBackgroundColour( const wxColour& col )
+{
+ m_defaultCellAttr->SetBackgroundColour(col);
+#ifdef __WXGTK__
+ m_gridWin->SetBackgroundColour(col);
+#endif
+}
+
+void wxGrid::SetDefaultCellTextColour( const wxColour& col )
+{
+ m_defaultCellAttr->SetTextColour(col);
+}
+
+void wxGrid::SetDefaultCellAlignment( int horiz, int vert )
+{
+ m_defaultCellAttr->SetAlignment(horiz, vert);
+}
+
+void wxGrid::SetDefaultCellOverflow( bool allow )
+{
+ m_defaultCellAttr->SetOverflow(allow);
+}
+
+void wxGrid::SetDefaultCellFont( const wxFont& font )
+{
+ m_defaultCellAttr->SetFont(font);
+}
+
+// For editors and renderers the type registry takes precedence over the
+// default attr, so we need to register the new editor/renderer for the string
+// data type in order to make setting a default editor/renderer appear to
+// work correctly.
+
+void wxGrid::SetDefaultRenderer(wxGridCellRenderer *renderer)
+{
+ RegisterDataType(wxGRID_VALUE_STRING,
+ renderer,
+ GetDefaultEditorForType(wxGRID_VALUE_STRING));
+}
+
+void wxGrid::SetDefaultEditor(wxGridCellEditor *editor)
+{
+ RegisterDataType(wxGRID_VALUE_STRING,
+ GetDefaultRendererForType(wxGRID_VALUE_STRING),
+ editor);
+}
+
+// ----------------------------------------------------------------------------
+// access to the default attributes
+// ----------------------------------------------------------------------------
+
+wxColour wxGrid::GetDefaultCellBackgroundColour() const
+{
+ return m_defaultCellAttr->GetBackgroundColour();
+}
+
+wxColour wxGrid::GetDefaultCellTextColour() const
+{
+ return m_defaultCellAttr->GetTextColour();
+}
+
+wxFont wxGrid::GetDefaultCellFont() const
+{
+ return m_defaultCellAttr->GetFont();
+}
+
+void wxGrid::GetDefaultCellAlignment( int *horiz, int *vert ) const
+{
+ m_defaultCellAttr->GetAlignment(horiz, vert);
+}
+
+bool wxGrid::GetDefaultCellOverflow() const
+{
+ return m_defaultCellAttr->GetOverflow();
+}
+
+wxGridCellRenderer *wxGrid::GetDefaultRenderer() const
+{
+ return m_defaultCellAttr->GetRenderer(NULL, 0, 0);
+}
+
+wxGridCellEditor *wxGrid::GetDefaultEditor() const
+{
+ return m_defaultCellAttr->GetEditor(NULL, 0, 0);
+}
+
+// ----------------------------------------------------------------------------
+// access to cell attributes
+// ----------------------------------------------------------------------------
+
+wxColour wxGrid::GetCellBackgroundColour(int row, int col) const
+{
+ wxGridCellAttr *attr = GetCellAttr(row, col);
+ wxColour colour = attr->GetBackgroundColour();
+ attr->DecRef();
+
+ return colour;
+}
+
+wxColour wxGrid::GetCellTextColour( int row, int col ) const
+{
+ wxGridCellAttr *attr = GetCellAttr(row, col);
+ wxColour colour = attr->GetTextColour();
+ attr->DecRef();
+
+ return colour;
+}
+
+wxFont wxGrid::GetCellFont( int row, int col ) const
+{
+ wxGridCellAttr *attr = GetCellAttr(row, col);
+ wxFont font = attr->GetFont();
+ attr->DecRef();
+
+ return font;
+}
+
+void wxGrid::GetCellAlignment( int row, int col, int *horiz, int *vert ) const
+{
+ wxGridCellAttr *attr = GetCellAttr(row, col);
+ attr->GetAlignment(horiz, vert);
+ attr->DecRef();
+}
+
+bool wxGrid::GetCellOverflow( int row, int col ) const
+{
+ wxGridCellAttr *attr = GetCellAttr(row, col);
+ bool allow = attr->GetOverflow();
+ attr->DecRef();
+
+ return allow;
+}
+
+wxGrid::CellSpan
+wxGrid::GetCellSize( int row, int col, int *num_rows, int *num_cols ) const
+{
+ wxGridCellAttr *attr = GetCellAttr(row, col);
+ attr->GetSize( num_rows, num_cols );
+ attr->DecRef();
+
+ if ( *num_rows == 1 && *num_cols == 1 )
+ return CellSpan_None; // just a normal cell
+
+ if ( *num_rows < 0 || *num_cols < 0 )
+ return CellSpan_Inside; // covered by a multi-span cell
+
+ // this cell spans multiple cells to its right/bottom
+ return CellSpan_Main;
+}
+
+wxGridCellRenderer* wxGrid::GetCellRenderer(int row, int col) const
+{
+ wxGridCellAttr* attr = GetCellAttr(row, col);
+ wxGridCellRenderer* renderer = attr->GetRenderer(this, row, col);
+ attr->DecRef();
+
+ return renderer;
+}
+
+wxGridCellEditor* wxGrid::GetCellEditor(int row, int col) const
+{
+ wxGridCellAttr* attr = GetCellAttr(row, col);
+ wxGridCellEditor* editor = attr->GetEditor(this, row, col);
+ attr->DecRef();
+
+ return editor;
+}
+
+bool wxGrid::IsReadOnly(int row, int col) const
+{
+ wxGridCellAttr* attr = GetCellAttr(row, col);
+ bool isReadOnly = attr->IsReadOnly();
+ attr->DecRef();
+
+ return isReadOnly;
+}
+
+// ----------------------------------------------------------------------------
+// attribute support: cache, automatic provider creation, ...
+// ----------------------------------------------------------------------------
+
+bool wxGrid::CanHaveAttributes() const
+{
+ if ( !m_table )
+ {
+ return false;
+ }
+
+ return m_table->CanHaveAttributes();
+}
+
+void wxGrid::ClearAttrCache()
+{
+ if ( m_attrCache.row != -1 )
+ {
+ wxGridCellAttr *oldAttr = m_attrCache.attr;
+ m_attrCache.attr = NULL;
+ m_attrCache.row = -1;
+ // wxSafeDecRec(...) might cause event processing that accesses
+ // the cached attribute, if one exists (e.g. by deleting the
+ // editor stored within the attribute). Therefore it is important
+ // to invalidate the cache before calling wxSafeDecRef!
+ wxSafeDecRef(oldAttr);
+ }
+}
+
+void wxGrid::RefreshAttr(int row, int col)
+{
+ if ( m_attrCache.row == row && m_attrCache.col == col )
+ ClearAttrCache();
+}
+
+
+void wxGrid::CacheAttr(int row, int col, wxGridCellAttr *attr) const
+{
+ if ( attr != NULL )
+ {
+ wxGrid * const self = const_cast<wxGrid *>(this);
+
+ self->ClearAttrCache();
+ self->m_attrCache.row = row;
+ self->m_attrCache.col = col;
+ self->m_attrCache.attr = attr;
+ wxSafeIncRef(attr);
+ }
+}
+
+bool wxGrid::LookupAttr(int row, int col, wxGridCellAttr **attr) const
+{
+ if ( row == m_attrCache.row && col == m_attrCache.col )
+ {
+ *attr = m_attrCache.attr;
+ wxSafeIncRef(m_attrCache.attr);
+
+#ifdef DEBUG_ATTR_CACHE
+ gs_nAttrCacheHits++;
+#endif
+
+ return true;
+ }
+ else
+ {
+#ifdef DEBUG_ATTR_CACHE
+ gs_nAttrCacheMisses++;
+#endif
+
+ return false;
+ }
+}
+
+wxGridCellAttr *wxGrid::GetCellAttr(int row, int col) const
+{
+ wxGridCellAttr *attr = NULL;
+ // Additional test to avoid looking at the cache e.g. for
+ // wxNoCellCoords, as this will confuse memory management.
+ if ( row >= 0 )
+ {
+ if ( !LookupAttr(row, col, &attr) )
+ {
+ attr = m_table ? m_table->GetAttr(row, col, wxGridCellAttr::Any)
+ : NULL;
+ CacheAttr(row, col, attr);
+ }
+ }
+
+ if (attr)
+ {
+ attr->SetDefAttr(m_defaultCellAttr);
+ }
+ else
+ {
+ attr = m_defaultCellAttr;
+ attr->IncRef();
+ }
+
+ return attr;
+}
+
+wxGridCellAttr *wxGrid::GetOrCreateCellAttr(int row, int col) const
+{
+ wxGridCellAttr *attr = NULL;
+ bool canHave = ((wxGrid*)this)->CanHaveAttributes();
+
+ wxCHECK_MSG( canHave, attr, wxT("Cell attributes not allowed"));
+ wxCHECK_MSG( m_table, attr, wxT("must have a table") );
+
+ attr = m_table->GetAttr(row, col, wxGridCellAttr::Cell);
+ if ( !attr )
+ {
+ attr = new wxGridCellAttr(m_defaultCellAttr);
+
+ // artificially inc the ref count to match DecRef() in caller
+ attr->IncRef();
+ m_table->SetAttr(attr, row, col);
+ }
+
+ return attr;
+}
+
+// ----------------------------------------------------------------------------
+// setting column attributes (wrappers around SetColAttr)
+// ----------------------------------------------------------------------------
+
+void wxGrid::SetColFormatBool(int col)
+{
+ SetColFormatCustom(col, wxGRID_VALUE_BOOL);
+}
+
+void wxGrid::SetColFormatNumber(int col)
+{
+ SetColFormatCustom(col, wxGRID_VALUE_NUMBER);
+}
+
+void wxGrid::SetColFormatFloat(int col, int width, int precision)
+{
+ wxString typeName = wxGRID_VALUE_FLOAT;
+ if ( (width != -1) || (precision != -1) )
+ {
+ typeName << wxT(':') << width << wxT(',') << precision;