X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/cd68daf58a724212159434ae1acc1e8a4024c27a..437a8892a107139e9f808f0a11792a56a55b4e25:/src/generic/grid.cpp diff --git a/src/generic/grid.cpp b/src/generic/grid.cpp index 3e8c74b0b7..1da201ad36 100644 --- a/src/generic/grid.cpp +++ b/src/generic/grid.cpp @@ -146,8 +146,10 @@ DEFINE_EVENT_TYPE(wxEVT_GRID_LABEL_RIGHT_DCLICK) DEFINE_EVENT_TYPE(wxEVT_GRID_ROW_SIZE) DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SIZE) DEFINE_EVENT_TYPE(wxEVT_GRID_COL_MOVE) +DEFINE_EVENT_TYPE(wxEVT_GRID_COL_SORT) DEFINE_EVENT_TYPE(wxEVT_GRID_RANGE_SELECT) -DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGE) +DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGING) +DEFINE_EVENT_TYPE(wxEVT_GRID_CELL_CHANGED) DEFINE_EVENT_TYPE(wxEVT_GRID_SELECT_CELL) DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_SHOWN) DEFINE_EVENT_TYPE(wxEVT_GRID_EDITOR_HIDDEN) @@ -183,18 +185,28 @@ public: virtual int GetFlags() const { - int flags = 0; + // we can't know in advance whether we can sort by this column or not + // with wxGrid API so suppose we can by default + int flags = wxCOL_SORTABLE; if ( m_grid->CanDragColSize() ) flags |= wxCOL_RESIZABLE; if ( m_grid->CanDragColMove() ) flags |= wxCOL_REORDERABLE; + if ( GetWidth() == 0 ) + flags |= wxCOL_HIDDEN; return flags; } - // TODO: currently there is no support for sorting - virtual bool IsSortKey() const { return false; } - virtual bool IsSortOrderAscending() const { return false; } + virtual bool IsSortKey() const + { + return m_grid->IsSortingBy(m_col); + } + + virtual bool IsSortOrderAscending() const + { + return m_grid->IsSortOrderAscending(); + } private: // these really should be const but are not because the column needs to be @@ -213,12 +225,13 @@ public: wxID_ANY, wxDefaultPosition, wxDefaultSize, - owner->CanDragColMove() ? wxHD_DRAGDROP : 0) + wxHD_ALLOW_HIDE | + (owner->CanDragColMove() ? wxHD_ALLOW_REORDER : 0)) { } protected: - virtual wxHeaderColumn& GetColumn(unsigned int idx) + virtual const wxHeaderColumn& GetColumn(unsigned int idx) const { return m_columns[idx]; } @@ -249,13 +262,37 @@ private: // override to implement column auto sizing virtual bool UpdateColumnWidthToFit(unsigned int idx, int widthTitle) { + // TODO: currently grid doesn't support computing the column best width + // from its contents so we just use the best label width as is GetOwner()->SetColSize(idx, widthTitle); return true; } + // overridden to react to the actions using the columns popup menu + virtual void UpdateColumnVisibility(unsigned int idx, bool show) + { + GetOwner()->SetColSize(idx, show ? wxGRID_AUTOSIZE : 0); + + // as this is done by the user we should notify the main program about + // it + GetOwner()->SendEvent(wxEVT_GRID_COL_SIZE, -1, idx); + } + + // overridden to react to the columns order changes in the customization + // dialog + virtual void UpdateColumnsOrder(const wxArrayInt& order) + { + GetOwner()->SetColumnsOrder(order); + } + // event handlers forwarding wxHeaderCtrl events to wxGrid + void OnClick(wxHeaderCtrlEvent& event) + { + GetOwner()->DoColHeaderClick(event.GetColumn()); + } + void OnBeginResize(wxHeaderCtrlEvent& event) { GetOwner()->DoStartResizeCol(event.GetColumn()); @@ -292,6 +329,8 @@ private: }; BEGIN_EVENT_TABLE(wxGridHeaderCtrl, wxHeaderCtrl) + EVT_HEADER_CLICK(wxID_ANY, wxGridHeaderCtrl::OnClick) + EVT_HEADER_BEGIN_RESIZE(wxID_ANY, wxGridHeaderCtrl::OnBeginResize) EVT_HEADER_RESIZING(wxID_ANY, wxGridHeaderCtrl::OnResizing) EVT_HEADER_END_RESIZE(wxID_ANY, wxGridHeaderCtrl::OnEndResize) @@ -1221,9 +1260,9 @@ void wxGridCellTextEditor::BeginEdit(int row, int col, wxGrid* grid) { wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); - m_startValue = grid->GetTable()->GetValue(row, col); + m_value = grid->GetTable()->GetValue(row, col); - DoBeginEdit(m_startValue); + DoBeginEdit(m_value); } void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue) @@ -1234,31 +1273,35 @@ void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue) Text()->SetFocus(); } -bool wxGridCellTextEditor::EndEdit(int row, int col, wxGrid* grid) +bool wxGridCellTextEditor::EndEdit(const wxString& WXUNUSED(oldval), + wxString *newval) { - wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); + wxCHECK_MSG( m_control, false, + "wxGridCellTextEditor must be created first!" ); - bool changed = false; - wxString value = Text()->GetValue(); - if (value != m_startValue) - changed = true; + const wxString value = Text()->GetValue(); + if ( value == m_value ) + return false; - if (changed) - grid->GetTable()->SetValue(row, col, value); + m_value = value; - m_startValue = wxEmptyString; + if ( newval ) + *newval = m_value; - // No point in setting the text of the hidden control - //Text()->SetValue(m_startValue); + return true; +} - return changed; +void wxGridCellTextEditor::ApplyEdit(int row, int col, wxGrid* grid) +{ + grid->GetTable()->SetValue(row, col, m_value); + m_value.clear(); } void wxGridCellTextEditor::Reset() { - wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); + wxASSERT_MSG( m_control, "wxGridCellTextEditor must be created first!" ); - DoReset(m_startValue); + DoReset(m_value); } void wxGridCellTextEditor::DoReset(const wxString& startValue) @@ -1400,13 +1443,13 @@ void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid) wxGridTableBase *table = grid->GetTable(); if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) ) { - m_valueOld = table->GetValueAsLong(row, col); + m_value = table->GetValueAsLong(row, col); } else { - m_valueOld = 0; + m_value = 0; wxString sValue = table->GetValue(row, col); - if (! sValue.ToLong(&m_valueOld) && ! sValue.empty()) + if (! sValue.ToLong(&m_value) && ! sValue.empty()) { wxFAIL_MSG( _T("this cell doesn't have numeric value") ); return; @@ -1416,7 +1459,7 @@ void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid) #if wxUSE_SPINCTRL if ( HasRange() ) { - Spin()->SetValue((int)m_valueOld); + Spin()->SetValue((int)m_value); Spin()->SetFocus(); } else @@ -1426,8 +1469,7 @@ void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid) } } -bool wxGridCellNumberEditor::EndEdit(int row, int col, - wxGrid* grid) +bool wxGridCellNumberEditor::EndEdit(const wxString& oldval, wxString *newval) { long value = 0; wxString text; @@ -1436,7 +1478,7 @@ bool wxGridCellNumberEditor::EndEdit(int row, int col, if ( HasRange() ) { value = Spin()->GetValue(); - if ( value == m_valueOld ) + if ( value == m_value ) return false; text.Printf(wxT("%ld"), value); @@ -1444,11 +1486,10 @@ bool wxGridCellNumberEditor::EndEdit(int row, int col, else // using unconstrained input #endif // wxUSE_SPINCTRL { - const wxString textOld(grid->GetCellValue(row, col)); text = Text()->GetValue(); if ( text.empty() ) { - if ( textOld.empty() ) + if ( oldval.empty() ) return false; } else // non-empty text now (maybe 0) @@ -1456,20 +1497,28 @@ bool wxGridCellNumberEditor::EndEdit(int row, int col, if ( !text.ToLong(&value) ) return false; - // if value == m_valueOld == 0 but old text was "" and new one is + // if value == m_value == 0 but old text was "" and new one is // "0" something still did change - if ( value == m_valueOld && (value || !textOld.empty()) ) + if ( value == m_value && (value || !oldval.empty()) ) return false; } } + m_value = value; + + if ( newval ) + *newval = text; + + return true; +} + +void wxGridCellNumberEditor::ApplyEdit(int row, int col, wxGrid* grid) +{ wxGridTableBase * const table = grid->GetTable(); if ( table->CanSetValueAs(row, col, wxGRID_VALUE_NUMBER) ) - table->SetValueAsLong(row, col, value); + table->SetValueAsLong(row, col, m_value); else - table->SetValue(row, col, text); - - return true; + table->SetValue(row, col, wxString::Format("%ld", m_value)); } void wxGridCellNumberEditor::Reset() @@ -1477,7 +1526,7 @@ void wxGridCellNumberEditor::Reset() #if wxUSE_SPINCTRL if ( HasRange() ) { - Spin()->SetValue((int)m_valueOld); + Spin()->SetValue((int)m_value); } else #endif @@ -1605,16 +1654,16 @@ void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid) wxGridTableBase * const table = grid->GetTable(); if ( table->CanGetValueAs(row, col, wxGRID_VALUE_FLOAT) ) { - m_valueOld = table->GetValueAsDouble(row, col); + m_value = table->GetValueAsDouble(row, col); } else { - m_valueOld = 0.0; + m_value = 0.0; const wxString value = table->GetValue(row, col); if ( !value.empty() ) { - if ( !value.ToDouble(&m_valueOld) ) + if ( !value.ToDouble(&m_value) ) { wxFAIL_MSG( _T("this cell doesn't have float value") ); return; @@ -1625,10 +1674,9 @@ void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid) DoBeginEdit(GetString()); } -bool wxGridCellFloatEditor::EndEdit(int row, int col, wxGrid* grid) +bool wxGridCellFloatEditor::EndEdit(const wxString& oldval, wxString *newval) { - const wxString text(Text()->GetValue()), - textOld(grid->GetCellValue(row, col)); + const wxString text(Text()->GetValue()); double value; if ( !text.empty() ) @@ -1638,7 +1686,7 @@ bool wxGridCellFloatEditor::EndEdit(int row, int col, wxGrid* grid) } else // new value is empty string { - if ( textOld.empty() ) + if ( oldval.empty() ) return false; // nothing changed value = 0.; @@ -1646,17 +1694,25 @@ bool wxGridCellFloatEditor::EndEdit(int row, int col, wxGrid* grid) // 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() ) + if ( wxIsSameDouble(value, m_value) && !text.empty() && !oldval.empty() ) return false; // nothing changed + m_value = value; + + if ( newval ) + *newval = text; + + return true; +} + +void wxGridCellFloatEditor::ApplyEdit(int row, int col, wxGrid* grid) +{ wxGridTableBase * const table = grid->GetTable(); if ( table->CanSetValueAs(row, col, wxGRID_VALUE_FLOAT) ) - table->SetValueAsDouble(row, col, value); + table->SetValueAsDouble(row, col, m_value); else - table->SetValue(row, col, text); - - return true; + table->SetValue(row, col, Text()->GetValue()); } void wxGridCellFloatEditor::Reset() @@ -1742,7 +1798,7 @@ wxString wxGridCellFloatEditor::GetString() const fmt = _T("%f"); } - return wxString::Format(fmt, m_valueOld); + return wxString::Format(fmt, m_value); } bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event) @@ -1890,16 +1946,16 @@ void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid) if (grid->GetTable()->CanGetValueAs(row, col, wxGRID_VALUE_BOOL)) { - m_startValue = grid->GetTable()->GetValueAsBool(row, col); + m_value = grid->GetTable()->GetValueAsBool(row, col); } else { wxString cellval( grid->GetTable()->GetValue(row, col) ); if ( cellval == ms_stringValues[false] ) - m_startValue = false; + m_value = false; else if ( cellval == ms_stringValues[true] ) - m_startValue = true; + m_value = true; else { // do not try to be smart here and convert it to true or false @@ -1910,31 +1966,32 @@ void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid) } } - CBox()->SetValue(m_startValue); + CBox()->SetValue(m_value); CBox()->SetFocus(); } -bool wxGridCellBoolEditor::EndEdit(int row, int col, - wxGrid* grid) +bool wxGridCellBoolEditor::EndEdit(const wxString& WXUNUSED(oldval), + wxString *newval) { - wxASSERT_MSG(m_control, - wxT("The wxGridCellEditor must be created first!")); - - bool changed = false; bool value = CBox()->GetValue(); - if ( value != m_startValue ) - changed = true; + if ( value == m_value ) + return false; - if ( changed ) - { - wxGridTableBase * const table = grid->GetTable(); - if ( table->CanGetValueAs(row, col, wxGRID_VALUE_BOOL) ) - table->SetValueAsBool(row, col, value); - else - table->SetValue(row, col, GetValue()); - } + m_value = value; - return changed; + if ( newval ) + *newval = GetValue(); + + return true; +} + +void wxGridCellBoolEditor::ApplyEdit(int row, int col, wxGrid* grid) +{ + wxGridTableBase * const table = grid->GetTable(); + if ( table->CanSetValueAs(row, col, wxGRID_VALUE_BOOL) ) + table->SetValueAsBool(row, col, m_value); + else + table->SetValue(row, col, GetValue()); } void wxGridCellBoolEditor::Reset() @@ -1942,7 +1999,7 @@ void wxGridCellBoolEditor::Reset() wxASSERT_MSG(m_control, wxT("The wxGridCellEditor must be created first!")); - CBox()->SetValue(m_startValue); + CBox()->SetValue(m_value); } void wxGridCellBoolEditor::StartingClick() @@ -2085,9 +2142,9 @@ void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid) if (evtHandler) evtHandler->SetInSetFocus(true); - m_startValue = grid->GetTable()->GetValue(row, col); + m_value = grid->GetTable()->GetValue(row, col); - Reset(); // this updates combo box to correspond to m_startValue + Reset(); // this updates combo box to correspond to m_value Combo()->SetFocus(); @@ -2101,29 +2158,37 @@ void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid) } } -bool wxGridCellChoiceEditor::EndEdit(int row, int col, - wxGrid* grid) +bool wxGridCellChoiceEditor::EndEdit(const wxString& WXUNUSED(oldval), + wxString *newval) { - wxString value = Combo()->GetValue(); - if ( value == m_startValue ) + const wxString value = Combo()->GetValue(); + if ( value == m_value ) return false; - grid->GetTable()->SetValue(row, col, value); + m_value = value; + + if ( newval ) + *newval = value; return true; } +void wxGridCellChoiceEditor::ApplyEdit(int row, int col, wxGrid* grid) +{ + grid->GetTable()->SetValue(row, col, m_value); +} + void wxGridCellChoiceEditor::Reset() { if (m_allowOthers) { - Combo()->SetValue(m_startValue); + Combo()->SetValue(m_value); 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); + int pos = Combo()->FindString(m_value); if (pos == wxNOT_FOUND) pos = 0; Combo()->SetSelection(pos); @@ -4786,7 +4851,7 @@ wxGrid::SetTable(wxGridTableBase *table, m_numCols = table->GetNumberCols(); if ( m_useNativeHeader ) - GetColHeader()->SetColumnCount(m_numCols); + GetGridColHeader()->SetColumnCount(m_numCols); m_table = table; m_table->SetView( this ); @@ -4884,6 +4949,9 @@ void wxGrid::Init() m_isDragging = false; m_startDragPos = wxDefaultPosition; + m_sortCol = wxNOT_FOUND; + m_sortIsAscending = true; + m_useNativeHeader = m_nativeColumnLabels = false; @@ -5105,20 +5173,6 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) // cell it might want to save that stuff to might no longer exist. HideCellEditControl(); -#if 0 - // if we were using the default widths/heights so far, we must change them - // now - if ( m_colWidths.IsEmpty() ) - { - InitColWidths(); - } - - if ( m_rowHeights.IsEmpty() ) - { - InitRowHeights(); - } -#endif - switch ( msg.GetId() ) { case wxGRIDTABLE_NOTIFY_ROWS_INSERTED: @@ -5270,7 +5324,7 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) m_numCols += numCols; if ( m_useNativeHeader ) - GetColHeader()->SetColumnCount(m_numCols); + GetGridColHeader()->SetColumnCount(m_numCols); if ( !m_colAt.IsEmpty() ) { @@ -5338,7 +5392,7 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int oldNumCols = m_numCols; m_numCols += numCols; if ( m_useNativeHeader ) - GetColHeader()->SetColumnCount(m_numCols); + GetGridColHeader()->SetColumnCount(m_numCols); if ( !m_colAt.IsEmpty() ) { @@ -5393,7 +5447,7 @@ bool wxGrid::Redimension( wxGridTableMessage& msg ) int numCols = msg.GetCommandInt2(); m_numCols -= numCols; if ( m_useNativeHeader ) - GetColHeader()->SetColumnCount(m_numCols); + GetGridColHeader()->SetColumnCount(m_numCols); if ( !m_colAt.IsEmpty() ) { @@ -5849,6 +5903,60 @@ void wxGrid::ProcessRowLabelMouseEvent( wxMouseEvent& event ) } } +void wxGrid::UpdateColumnSortingIndicator(int col) +{ + wxCHECK_RET( col != wxNOT_FOUND, "invalid column index" ); + + if ( m_useNativeHeader ) + GetGridColHeader()->UpdateColumn(col); + else if ( m_nativeColumnLabels ) + m_colWindow->Refresh(); + //else: sorting indicator display not yet implemented in grid version +} + +void wxGrid::SetSortingColumn(int col, bool ascending) +{ + if ( col == m_sortCol ) + { + // we are already using this column for sorting (or not sorting at all) + // but we might still change the sorting order, check for it + if ( m_sortCol != wxNOT_FOUND && ascending != m_sortIsAscending ) + { + m_sortIsAscending = ascending; + + UpdateColumnSortingIndicator(m_sortCol); + } + } + else // we're changing the column used for sorting + { + const int sortColOld = m_sortCol; + + // change it before updating the column as we want GetSortingColumn() + // to return the correct new value + m_sortCol = col; + + if ( sortColOld != wxNOT_FOUND ) + UpdateColumnSortingIndicator(sortColOld); + + if ( m_sortCol != wxNOT_FOUND ) + { + m_sortIsAscending = ascending; + UpdateColumnSortingIndicator(m_sortCol); + } + } +} + +void wxGrid::DoColHeaderClick(int col) +{ + // we consider that the grid was resorted if this event is processed and + // not vetoed + if ( SendEvent(wxEVT_GRID_COL_SORT, -1, col) == 1 ) + { + SetSortingColumn(col, IsSortingBy(col) ? !m_sortIsAscending : true); + Refresh(); + } +} + void wxGrid::DoStartResizeCol(int col) { m_dragRowOrCol = col; @@ -5882,10 +5990,11 @@ void wxGrid::DoUpdateResizeColWidth(int w) void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) { - int x, y, col; + int x, y; wxPoint pos( event.GetPosition() ); CalcUnscrolledPosition( pos.x, pos.y, &x, &y ); + int col = XToCol(x); if ( event.Dragging() ) { if (!m_isDragging) @@ -5893,8 +6002,8 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) m_isDragging = true; GetColLabelWindow()->CaptureMouse(); - if ( m_cursorMode == WXGRID_CURSOR_MOVE_COL ) - DoStartMoveCol(XToCol(x)); + if ( m_cursorMode == WXGRID_CURSOR_MOVE_COL && col != -1 ) + DoStartMoveCol(col); } if ( event.LeftIsDown() ) @@ -5907,7 +6016,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) case WXGRID_CURSOR_SELECT_COL: { - if ( (col = XToCol( x )) >= 0 ) + if ( col != -1 ) { if ( m_selection ) m_selection->SelectCol(col, event); @@ -6005,7 +6114,6 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // if ( XToEdgeOfCol(x) < 0 ) { - col = XToCol(x); if ( col >= 0 && !SendEvent( wxEVT_GRID_LABEL_LEFT_CLICK, -1, col, event ) ) { @@ -6059,10 +6167,9 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // if ( event.LeftDClick() ) { - col = XToEdgeOfCol(x); - if ( col < 0 ) + const int colEdge = XToEdgeOfCol(x); + if ( colEdge == -1 ) { - col = XToCol(x); if ( col >= 0 && ! SendEvent( wxEVT_GRID_LABEL_LEFT_DCLICK, -1, col, event ) ) { @@ -6072,7 +6179,7 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) else { // adjust column width depending on label text - AutoSizeColLabelSize( col ); + AutoSizeColLabelSize( colEdge ); ChangeCursorMode(WXGRID_CURSOR_SELECT_CELL, GetColLabelWindow()); m_dragLastPos = -1; @@ -6090,9 +6197,11 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) break; case WXGRID_CURSOR_MOVE_COL: - if ( m_dragLastPos == -1 ) + if ( m_dragLastPos == -1 || col == m_dragRowOrCol ) { - // The user clicked on the column but didn't actually drag + // the column didn't actually move anywhere + if ( col != -1 ) + DoColHeaderClick(col); m_colWindow->Refresh(); // "unpress" the column } else @@ -6105,7 +6214,8 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) case WXGRID_CURSOR_SELECT_CELL: case WXGRID_CURSOR_RESIZE_ROW: case WXGRID_CURSOR_SELECT_ROW: - // nothing to do (?) + if ( col != -1 ) + DoColHeaderClick(col); break; } @@ -6117,7 +6227,6 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // else if ( event.RightDown() ) { - col = XToCol(x); if ( col >= 0 && !SendEvent( wxEVT_GRID_LABEL_RIGHT_CLICK, -1, col, event ) ) { @@ -6129,7 +6238,6 @@ void wxGrid::ProcessColLabelMouseEvent( wxMouseEvent& event ) // else if ( event.RightDClick() ) { - col = XToCol(x); if ( col >= 0 && !SendEvent( wxEVT_GRID_LABEL_RIGHT_DCLICK, -1, col, event ) ) { @@ -6779,24 +6887,15 @@ void wxGrid::DoEndMoveCol(int pos) m_dragRowOrCol = -1; } -void wxGrid::SetColPos(int idx, int pos) +void wxGrid::RefreshAfterColPosChange() { - // we're going to need m_colAt now, initialize it if needed - if ( m_colAt.empty() ) - { - m_colAt.reserve(m_numCols); - for ( int i = 0; i < m_numCols; i++ ) - m_colAt.push_back(i); - } - - wxHeaderCtrl::MoveColumnInOrderArray(m_colAt, idx, pos); - - // also recalculate the column rights - if ( !m_colWidths.IsEmpty() ) + // recalculate the column rights as the column positions have changed, + // unless we calculate them dynamically because all columns widths are the + // same and it's easy to do + if ( !m_colWidths.empty() ) { int colRight = 0; - int colPos; - for ( colPos = 0; colPos < m_numCols; colPos++ ) + for ( int colPos = 0; colPos < m_numCols; colPos++ ) { int colID = GetColAt( colPos ); @@ -6807,40 +6906,65 @@ void wxGrid::SetColPos(int idx, int pos) // and make the changes visible if ( m_useNativeHeader ) - GetColHeader()->SetColumnsOrder(m_colAt); + { + if ( m_colAt.empty() ) + GetGridColHeader()->ResetColumnsOrder(); + else + GetGridColHeader()->SetColumnsOrder(m_colAt); + } else + { m_colWindow->Refresh(); + } m_gridWin->Refresh(); } +void wxGrid::SetColumnsOrder(const wxArrayInt& order) +{ + m_colAt = order; + RefreshAfterColPosChange(); +} + +void wxGrid::SetColPos(int idx, int pos) +{ + // we're going to need m_colAt now, initialize it if needed + if ( m_colAt.empty() ) + { + m_colAt.reserve(m_numCols); + for ( int i = 0; i < m_numCols; i++ ) + m_colAt.push_back(i); + } + + wxHeaderCtrl::MoveColumnInOrderArray(m_colAt, idx, pos); + + RefreshAfterColPosChange(); +} + +void wxGrid::ResetColPos() +{ + m_colAt.clear(); + + RefreshAfterColPosChange(); +} void wxGrid::EnableDragColMove( bool enable ) { if ( m_canDragColMove == enable ) return; - m_canDragColMove = enable; - - if ( !m_canDragColMove ) + if ( m_useNativeHeader ) { - m_colAt.Clear(); + // update all columns to make them [not] reorderable + GetGridColHeader()->SetColumnCount(m_numCols); + } - //Recalculate the column rights - if ( !m_colWidths.IsEmpty() ) - { - int colRight = 0; - int colPos; - for ( colPos = 0; colPos < m_numCols; colPos++ ) - { - colRight += m_colWidths[colPos]; - m_colRights[colPos] = colRight; - } - } + m_canDragColMove = enable; - m_colWindow->Refresh(); - m_gridWin->Refresh(); - } + // we use to call ResetColPos() from here if !enable but this doesn't seem + // right as it would mean there would be no way to "freeze" the current + // columns order by disabling moving them after putting them in the desired + // order, whereas now you can always call ResetColPos() manually if needed } @@ -7008,7 +7132,8 @@ wxGrid::SendEvent(const wxEventType type, // Generate a grid event of specified type, return value same as above // -int wxGrid::SendEvent(const wxEventType type, int row, int col) +int +wxGrid::SendEvent(const wxEventType type, int row, int col, const wxString& s) { bool claimed, vetoed; @@ -7024,6 +7149,7 @@ int wxGrid::SendEvent(const wxEventType type, int row, int col) else { wxGridEvent gridEvt( GetId(), type, this, row, col ); + gridEvt.SetString(s); claimed = GetEventHandler()->ProcessEvent(gridEvt); vetoed = !gridEvt.IsAllowed(); @@ -8117,7 +8243,7 @@ void wxGrid::UseNativeColHeader(bool native) CreateColumnWindow(); if ( m_useNativeHeader ) - GetColHeader()->SetColumnCount(m_numCols); + GetGridColHeader()->SetColumnCount(m_numCols); CalcWindowSizes(); } @@ -8185,7 +8311,18 @@ void wxGrid::DrawColLabel(wxDC& dc, int col) if ( m_nativeColumnLabels ) { - wxRendererNative::Get().DrawHeaderButton(GetColLabelWindow(), dc, rect, 0); + wxRendererNative::Get().DrawHeaderButton + ( + GetColLabelWindow(), + dc, + rect, + 0, + IsSortingBy(col) + ? IsSortOrderAscending() + ? wxHDR_SORT_ICON_UP + : wxHDR_SORT_ICON_DOWN + : wxHDR_SORT_ICON_NONE + ); } else { @@ -8465,7 +8602,6 @@ void wxGrid::EnableCellEditControl( bool enable ) } else { - //FIXME:add veto support SendEvent(wxEVT_GRID_EDITOR_HIDDEN); HideCellEditControl(); @@ -8698,19 +8834,26 @@ void wxGrid::SaveEditControlValue() wxGridCellAttr* attr = GetCellAttr(row, col); wxGridCellEditor* editor = attr->GetEditor(this, row, col); - bool changed = editor->EndEdit(row, col, this); - editor->DecRef(); - attr->DecRef(); + wxString newval; + bool changed = editor->EndEdit(oldval, &newval); - if (changed) + if ( changed && SendEvent(wxEVT_GRID_CELL_CHANGING, newval) != -1 ) { - if ( SendEvent(wxEVT_GRID_CELL_CHANGE) == -1 ) + editor->ApplyEdit(row, col, this); + + // for compatibility reasons dating back to wx 2.8 when this event + // was called wxEVT_GRID_CELL_CHANGE and wxEVT_GRID_CELL_CHANGING + // didn't exist we allow vetoing this one too + if ( SendEvent(wxEVT_GRID_CELL_CHANGED, oldval) == -1 ) { // Event has been vetoed, set the data back. SetCellValue(row, col, oldval); } } + + editor->DecRef(); + attr->DecRef(); } } @@ -9490,7 +9633,7 @@ void wxGrid::SetColLabelValue( int col, const wxString& s ) { if ( m_useNativeHeader ) { - GetColHeader()->UpdateColumn(col); + GetGridColHeader()->UpdateColumn(col); } else { @@ -10314,15 +10457,12 @@ void wxGrid::SetColSize( int col, int 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 - // what he is doing. However we should test against the weaker - // constraint of minimalAcceptableWidth, as this breaks rendering - // - // This test then fixes sf.net bug #645734 - - if ( width < GetColMinimalAcceptableWidth() ) + // we intentionally don't test whether the width is less than + // GetColMinimalWidth() here but we do compare it with + // GetColMinimalAcceptableWidth() as otherwise things currently break (see + // #651) -- and we also always allow the width of 0 as it has the special + // sense of hiding the column + if ( width > 0 && width < GetColMinimalAcceptableWidth() ) return; if ( m_colWidths.IsEmpty() ) @@ -10331,9 +10471,11 @@ void wxGrid::SetColSize( int col, int width ) InitColWidths(); } - int w = wxMax( 0, width ); - int diff = w - m_colWidths[col]; - m_colWidths[col] = w; + const int diff = width - m_colWidths[col]; + m_colWidths[col] = width; + if ( m_useNativeHeader ) + GetGridColHeader()->UpdateColumn(col); + //else: will be refreshed when the header is redrawn for ( int colPos = GetColPos(col); colPos < m_numCols; colPos++ ) { @@ -10499,7 +10641,7 @@ wxGrid::AutoSizeColOrRow(int colOrRow, bool setAsMin, wxGridDirection direction) { if ( m_useNativeHeader ) { - GetColHeader()->UpdateColumn(col); + GetGridColHeader()->UpdateColumn(col); } else {