X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7d2c43731bd3d78b2d67c63ac48d7d65de092365..c95340c23404e3bc64993dc01d97969ed3c87e58:/src/generic/grid.cpp diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 33f31d9f2a..bdd93204b5 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -83,13 +83,26 @@ struct wxGridCellWithAttr wxGridCellWithAttr& operator=(const wxGridCellWithAttr& other) { coords = other.coords; - attr->DecRef(); - attr = other.attr; - attr->IncRef(); - + if (attr != other.attr) + { + attr->DecRef(); + attr = other.attr; + attr->IncRef(); + } return *this; } + void ChangeAttr(wxGridCellAttr* new_attr) + { + if (attr != new_attr) + { + // "Delete" (i.e. DecRef) the old attribute. + attr->DecRef(); + attr = new_attr; + // Take ownership of the new attribute, i.e. no IncRef. + } + } + ~wxGridCellWithAttr() { attr->DecRef(); @@ -659,10 +672,7 @@ void wxGridCellTextEditor::DoCreate(wxWindow* parent, wxEvtHandler* evtHandler, long style) { - style |= wxTE_PROCESS_ENTER | - wxTE_PROCESS_TAB | - wxTE_AUTO_SCROLL | - wxNO_BORDER; + style |= wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxNO_BORDER; m_control = new wxTextCtrl(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize, @@ -943,7 +953,6 @@ void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid) bool wxGridCellNumberEditor::EndEdit(int row, int col, wxGrid* grid) { - bool changed; long value = 0; wxString text; @@ -951,26 +960,40 @@ bool wxGridCellNumberEditor::EndEdit(int row, int col, if ( HasRange() ) { value = Spin()->GetValue(); - changed = value != m_valueOld; - if (changed) - text = wxString::Format(wxT("%ld"), value); + if ( value == m_valueOld ) + return false; + + text.Printf(wxT("%ld"), value); } - else -#endif + else // using unconstrained input +#endif // wxUSE_SPINCTRL { + const wxString textOld(grid->GetCellValue(row, col)); text = Text()->GetValue(); - changed = (text.empty() || text.ToLong(&value)) && (value != m_valueOld); - } + if ( text.empty() ) + { + if ( textOld.empty() ) + return false; + } + else // non-empty text now (maybe 0) + { + if ( !text.ToLong(&value) ) + return false; - if ( changed ) - { - if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER)) - grid->GetTable()->SetValueAsLong(row, col, value); - else - grid->GetTable()->SetValue(row, col, text); + // if value == m_valueOld == 0 but old text was "" and new one is + // "0" something still did change + if ( value == m_valueOld && (value || !textOld.empty()) ) + return false; + } } - return changed; + wxGridTableBase * const table = grid->GetTable(); + if ( table->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER) ) + table->SetValueAsLong(row, col, value); + else + table->SetValue(row, col, text); + + return true; } void wxGridCellNumberEditor::Reset() @@ -1103,7 +1126,7 @@ void wxGridCellFloatEditor::Create(wxWindow* parent, void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid) { // first get the value - wxGridTableBase *table = grid->GetTable(); + wxGridTableBase * const table = grid->GetTable(); if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) ) { m_valueOld = table->GetValueAsDouble(row, col); @@ -1111,35 +1134,53 @@ void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid) else { m_valueOld = 0.0; - wxString sValue = table->GetValue(row, col); - if (! sValue.ToDouble(&m_valueOld) && ! sValue.empty()) + + const wxString value = table->GetValue(row, col); + if ( !value.empty() ) { - wxFAIL_MSG( _T("this cell doesn't have float value") ); - return; + if ( !value.ToDouble(&m_valueOld) ) + { + wxFAIL_MSG( _T("this cell doesn't have float value") ); + return; + } } } DoBeginEdit(GetString()); } -bool wxGridCellFloatEditor::EndEdit(int row, int col, - wxGrid* grid) +bool wxGridCellFloatEditor::EndEdit(int row, int col, wxGrid* grid) { - double value = 0.0; - wxString text(Text()->GetValue()); + const wxString text(Text()->GetValue()), + textOld(grid->GetCellValue(row, col)); - if ( (text.empty() || text.ToDouble(&value)) && - !wxIsSameDouble(value, m_valueOld) ) + double value; + if ( !text.empty() ) { - if (grid->GetTable()->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT)) - grid->GetTable()->SetValueAsDouble(row, col, value); - else - grid->GetTable()->SetValue(row, col, text); + if ( !text.ToDouble(&value) ) + return false; + } + else // new value is empty string + { + if ( textOld.empty() ) + return false; // nothing changed - return true; + value = 0.; } - return false; + // the test for empty strings ensures that we don't skip the value setting + // when "" is replaced by "0" or vice versa as "" numeric value is also 0. + if ( wxIsSameDouble(value, m_valueOld) && !text.empty() && !textOld.empty() ) + return false; // nothing changed + + wxGridTableBase * const table = grid->GetTable(); + + if ( table->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT) ) + table->SetValueAsDouble(row, col, value); + else + table->SetValue(row, col, text); + + return true; } void wxGridCellFloatEditor::Reset() @@ -1570,19 +1611,7 @@ void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid) m_startValue = grid->GetTable()->GetValue(row, col); - if (m_allowOthers) - { - Combo()->SetValue(m_startValue); - Combo()->SetInsertionPointEnd(); - } - else // the combobox is read-only - { - // find the right position, or default to the first if not found - int pos = Combo()->FindString(m_startValue); - if (pos == wxNOT_FOUND) - pos = 0; - Combo()->SetSelection(pos); - } + Reset(); // this updates combo box to correspond to m_startValue Combo()->SetFocus(); @@ -1610,8 +1639,19 @@ bool wxGridCellChoiceEditor::EndEdit(int row, int col, void wxGridCellChoiceEditor::Reset() { - Combo()->SetValue(m_startValue); - Combo()->SetInsertionPointEnd(); + if (m_allowOthers) + { + Combo()->SetValue(m_startValue); + Combo()->SetInsertionPointEnd(); + } + else // the combobox is read-only + { + // find the right position, or default to the first if not found + int pos = Combo()->FindString(m_startValue); + if (pos == wxNOT_FOUND) + pos = 0; + Combo()->SetSelection(pos); + } } void wxGridCellChoiceEditor::SetParameters(const wxString& params) @@ -2601,6 +2641,9 @@ wxGridCellEditor* wxGridCellAttr::GetEditor(const wxGrid* grid, int row, int col void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col) { + // Note: contrary to wxGridRowOrColAttrData::SetAttr, we must not + // touch attribute's reference counting explicitly, since this + // is managed by class wxGridCellWithAttr int n = FindIndex(row, col); if ( n == wxNOT_FOUND ) { @@ -2616,7 +2659,7 @@ void wxGridCellAttrData::SetAttr(wxGridCellAttr *attr, int row, int col) if ( attr ) { // change the attribute - m_attrs[(size_t)n].attr = attr; + m_attrs[(size_t)n].ChangeAttr(attr); } else { @@ -2757,7 +2800,8 @@ void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol) { if ( attr ) { - // add the attribute + // add the attribute - no need to do anything to reference count + // since we take ownership of the attribute. m_rowsOrCols.Add(rowOrCol); m_attrs.Add(attr); } @@ -2766,15 +2810,19 @@ void wxGridRowOrColAttrData::SetAttr(wxGridCellAttr *attr, int rowOrCol) else { size_t n = (size_t)i; + if ( m_attrs[n] == attr ) + // nothing to do + return; if ( attr ) { - // change the attribute + // change the attribute, handling reference count manually, + // taking ownership of the new attribute. m_attrs[n]->DecRef(); m_attrs[n] = attr; } else { - // remove this attribute + // remove this attribute, handling reference count manually m_attrs[n]->DecRef(); m_rowsOrCols.RemoveAt(n); m_attrs.RemoveAt(n); @@ -5999,7 +6047,8 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) } - else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) + else if ( event.LeftIsDown() && + m_cursorMode == WXGRID_CURSOR_RESIZE_ROW ) { int cw, ch, left, dummy; m_gridWin->GetClientSize( &cw, &ch ); @@ -6017,7 +6066,8 @@ void wxGrid::ProcessGridCellMouseEvent( wxMouseEvent& event ) dc.DrawLine( left, y, left+cw, y ); m_dragLastPos = y; } - else if ( m_cursorMode == WXGRID_CURSOR_RESIZE_COL ) + else if ( event.LeftIsDown() && + m_cursorMode == WXGRID_CURSOR_RESIZE_COL ) { int cw, ch, dummy, top; m_gridWin->GetClientSize( &cw, &ch ); @@ -9894,9 +9944,14 @@ void wxGrid::ClearAttrCache() { if ( m_attrCache.row != -1 ) { - wxSafeDecRef(m_attrCache.attr); + 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); } } @@ -10139,7 +10194,7 @@ void wxGrid::SetCellSize( int row, int col, int num_rows, int num_cols ) wxT("wxGrid::SetCellSize setting cell size to < 1")); // if this was already a multicell then "turn off" the other cells first - if ((cell_rows > 1) || (cell_rows > 1)) + if ((cell_rows > 1) || (cell_cols > 1)) { int i, j; for (j=row; j < row + cell_rows; j++) @@ -10302,6 +10357,19 @@ void wxGrid::SetRowSize( int row, int height ) { wxCHECK_RET( row >= 0 && row < m_numRows, _T("invalid row index") ); + // if < 0 then calculate new height from label + if ( height < 0 ) + { + long w, h; + wxArrayString lines; + wxClientDC dc(m_rowLabelWin); + dc.SetFont(GetLabelFont()); + StringToLines(GetRowLabelValue( row ), lines); + GetTextBoxSize( dc, lines, &w, &h ); + //check that it is not less than the minimal height + height = wxMax(h, GetRowMinimalAcceptableHeight()); + } + // See comment in SetColSize if ( height < GetRowMinimalAcceptableHeight()) return; @@ -10347,6 +10415,23 @@ void wxGrid::SetColSize( int col, int width ) { wxCHECK_RET( col >= 0 && col < m_numCols, _T("invalid column index") ); + // if < 0 then calculate new width from label + if ( width < 0 ) + { + long w, h; + wxArrayString lines; + wxClientDC dc(m_colLabelWin); + dc.SetFont(GetLabelFont()); + StringToLines(GetColLabelValue(col), lines); + if ( GetColLabelTextOrientation() == wxHORIZONTAL ) + GetTextBoxSize( dc, lines, &w, &h ); + else + GetTextBoxSize( dc, lines, &h, &w ); + width = w + 6; + //check that it is not less than the minimal width + width = wxMax(width, GetColMinimalAcceptableWidth()); + } + // should we check that it's bigger than GetColMinimalWidth(col) here? // (VZ) // No, because it is reasonable to assume the library user know's @@ -10364,18 +10449,6 @@ void wxGrid::SetColSize( int col, int width ) InitColWidths(); } - // if < 0 then calculate new width from label - if ( width < 0 ) - { - long w, h; - wxArrayString lines; - wxClientDC dc(m_colLabelWin); - dc.SetFont(GetLabelFont()); - StringToLines(GetColLabelValue(col), lines); - GetTextBoxSize(dc, lines, &w, &h); - width = w + 6; - } - int w = wxMax( 0, width ); int diff = w - m_colWidths[col]; m_colWidths[col] = w; @@ -10743,9 +10816,6 @@ void wxGrid::AutoSize() void wxGrid::AutoSizeRowLabelSize( int row ) { - wxArrayString lines; - long w, h; - // Hide the edit control, so it // won't interfere with drag-shrinking. if ( IsCellEditControlShown() ) @@ -10755,20 +10825,12 @@ void wxGrid::AutoSizeRowLabelSize( int row ) } // autosize row height depending on label text - StringToLines( GetRowLabelValue( row ), lines ); - wxClientDC dc( m_rowLabelWin ); - GetTextBoxSize( dc, lines, &w, &h ); - if ( h < m_defaultRowHeight ) - h = m_defaultRowHeight; - SetRowSize(row, h); + SetRowSize(row, -1); ForceRefresh(); } void wxGrid::AutoSizeColLabelSize( int col ) { - wxArrayString lines; - long w, h; - // Hide the edit control, so it // won't interfere with drag-shrinking. if ( IsCellEditControlShown() ) @@ -10778,15 +10840,7 @@ void wxGrid::AutoSizeColLabelSize( int col ) } // autosize column width depending on label text - StringToLines( GetColLabelValue( col ), lines ); - wxClientDC dc( m_colLabelWin ); - if ( GetColLabelTextOrientation() == wxHORIZONTAL ) - GetTextBoxSize( dc, lines, &w, &h ); - else - GetTextBoxSize( dc, lines, &h, &w ); - if ( w < m_defaultColWidth ) - w = m_defaultColWidth; - SetColSize(col, w); + SetColSize(col, -1); ForceRefresh(); } @@ -11019,9 +11073,13 @@ wxArrayInt wxGrid::GetSelectedCols() const void wxGrid::ClearSelection() { + wxRect r1 = BlockToDeviceRect( m_selectingTopLeft, m_selectingBottomRight); + wxRect r2 = BlockToDeviceRect( m_currentCellCoords, m_selectingKeyboard ); m_selectingTopLeft = m_selectingBottomRight = m_selectingKeyboard = wxGridNoCellCoords; + Refresh( false, &r1 ); + Refresh( false, &r2 ); if ( m_selection ) m_selection->ClearSelection(); }