From b7e9f8b136c02826c7e5b3bf9b339d2013ac05f6 Mon Sep 17 00:00:00 2001 From: Robert Roebling Date: Sun, 19 Aug 2007 19:03:01 +0000 Subject: [PATCH] Bo's patch adding Selection API and some more changes, doesn't compile yet git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@48182 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/dataview.h | 34 ++- include/wx/generic/dataview.h | 36 ++- samples/dataview/dataview.cpp | 102 ++++++- src/common/datavcmn.cpp | 3 + src/generic/datavgen.cpp | 484 ++++++++++++++++++++++------------ 5 files changed, 453 insertions(+), 206 deletions(-) diff --git a/include/wx/dataview.h b/include/wx/dataview.h index 34b489eaf5..86b9199a19 100644 --- a/include/wx/dataview.h +++ b/include/wx/dataview.h @@ -2,7 +2,7 @@ // Name: wx/dataview.h // Purpose: wxDataViewCtrl base classes // Author: Robert Roebling -// Modified by: +// Modified by: Bo Yang // Created: 08.01.06 // RCS-ID: $Id$ // Copyright: (c) Robert Roebling @@ -21,10 +21,11 @@ #include "wx/bitmap.h" #include "wx/variant.h" #include "wx/listctrl.h" +#include "wx/dynarray.h" #if defined(__WXGTK20__) // for testing - // #define wxUSE_GENERICDATAVIEWCTRL 1 + #define wxUSE_GENERICDATAVIEWCTRL 1 #elif defined(__WXMAC__) #else #define wxUSE_GENERICDATAVIEWCTRL 1 @@ -44,7 +45,6 @@ class WXDLLIMPEXP_FWD_ADV wxDataViewCtrl; class WXDLLIMPEXP_FWD_ADV wxDataViewColumn; class WXDLLIMPEXP_FWD_ADV wxDataViewRenderer; class WXDLLIMPEXP_FWD_ADV wxDataViewModelNotifier; -class wxDataViewEventModelNotifier; extern WXDLLIMPEXP_DATA_ADV(const wxChar) wxDataViewCtrlNameStr[]; @@ -396,6 +396,8 @@ protected: // wxDataViewCtrlBase // --------------------------------------------------------- +WX_DECLARE_OBJARRAY(wxDataViewItem, wxDataViewItemArray); + #define wxDV_SINGLE 0x0000 // for convenience #define wxDV_MULTIPLE 0x0001 // can select multiple items @@ -472,8 +474,29 @@ public: int GetIndent() const { return m_indent; } - // TODO selection code - virtual wxDataViewItem GetSelection() = 0; + //Selection Code + virtual int GetSelections( wxDataViewItemArray & sel ) const = 0; + virtual void SetSelections( const wxDataViewItemArray & sel ) = 0; + virtual void Select( const wxDataViewItem & item ) = 0; + virtual void Unselect( const wxDataViewItem & item ) = 0; + virtual bool IsSelected( const wxDataViewItem & item ) const = 0; + + virtual int GetSelections( wxArrayInt & sel ) const = 0; + virtual void SetSelections( const wxArrayInt & sel ) = 0; + virtual void Select( int row ) = 0; + virtual void Unselect( int row ) = 0; + virtual bool IsSelected( int row ) const = 0; + virtual void SelectRange( int from, int to ) = 0; + virtual void UnselectRange( int from, int to ) = 0; + + virtual void SelectAll() = 0; + virtual void UnselectAll() = 0; + + virtual void EnsureVisible( int row ) = 0; + virtual void EnsureVisible( const wxDataViewItem & item ) = 0; + + virtual wxDataViewItem GetItemByRow( unsigned int row ) const = 0; + virtual int GetRowByItem( const wxDataViewItem & item ) const = 0; protected: virtual void DoSetExpanderColumn() = 0 ; @@ -482,7 +505,6 @@ protected: private: wxDataViewModel *m_model; wxList m_cols; - wxDataViewEventModelNotifier *m_eventNotifier; unsigned int m_expander_column; int m_indent ; diff --git a/include/wx/generic/dataview.h b/include/wx/generic/dataview.h index 86f3803534..6d28f1c6c0 100644 --- a/include/wx/generic/dataview.h +++ b/include/wx/generic/dataview.h @@ -2,6 +2,7 @@ // Name: wx/generic/dataview.h // Purpose: wxDataViewCtrl generic implementation header // Author: Robert Roebling +// Modified By: Bo Yang // Id: $Id$ // Copyright: (c) 1998 Robert Roebling // Licence: wxWindows licence @@ -352,18 +353,29 @@ public: virtual void DoSetExpanderColumn(); virtual void DoSetIndent(); - virtual wxDataViewItem GetSelection() ; - -/********************selection code********************* - virtual void SetSelection( int row ); // -1 for unselect - virtual void SetSelectionRange( unsigned int from, unsigned int to ); - virtual void SetSelections( const wxArrayInt& aSelections); - virtual void Unselect( unsigned int row ); - - virtual bool IsSelected( unsigned int row ) const; - virtual int GetSelection() const; - virtual int GetSelections(wxArrayInt& aSelections) const; -*****************************************************/ + virtual int GetSelections( wxDataViewItemArray & sel ) const; + virtual void SetSelections( const wxDataViewItemArray & sel ); + virtual void Select( const wxDataViewItem & item ); + virtual void Unselect( const wxDataViewItem & item ); + virtual bool IsSelected( const wxDataViewItem & item ) const; + + virtual int GetSelections( wxArrayInt & sel ) const; + virtual void SetSelections( const wxArrayInt & sel ); + virtual void Select( int row ); + virtual void Unselect( int row ); + virtual bool IsSelected( int row ) const; + virtual void SelectRange( int from, int to ); + virtual void UnselectRange( int from, int to ); + + virtual void SelectAll(); + virtual void UnselectAll(); + + virtual void EnsureVisible( int row ); + virtual void EnsureVisible( const wxDataViewItem & item ); + + virtual wxDataViewItem GetItemByRow( unsigned int row ) const; + virtual int GetRowByItem( const wxDataViewItem & item ) const; + public: // utility functions not part of the API diff --git a/samples/dataview/dataview.cpp b/samples/dataview/dataview.cpp index b305bc4410..937efdc8f3 100644 --- a/samples/dataview/dataview.cpp +++ b/samples/dataview/dataview.cpp @@ -2,7 +2,7 @@ // Name: dataview.cpp // Purpose: wxDataViewCtrl wxWidgets sample // Author: Robert Roebling -// Modified by: Francesco Montorsi +// Modified by: Francesco Montorsi, Bo Yang // Created: 06/01/06 // RCS-ID: $Id$ // Copyright: (c) Robert Roebling @@ -146,6 +146,7 @@ public: // add to data MyMusicModelNode *child_node = new MyMusicModelNode( m_classical, title, artist, year ); + m_classical->Append( child_node ); if (m_classicalMusicIsKnownToControl) @@ -164,6 +165,11 @@ public: // notify control ItemDeleted( parent, item ); + //We must delete the node after we call ItemDeleted + //The reason is that: + //When we use wxSortedArray, the array find a node through binary search for speed. + //And when the array is searching for some node, it call the model's compare function. + //The compare function need the node to be compared. So we should delete the node later, here. node->GetParent()->GetChildren().Remove( node ); delete node; } @@ -417,6 +423,13 @@ public: void OnValueChanged( wxDataViewEvent &event ); void OnItemAdded( wxDataViewEvent &event ); void OnItemDeleted( wxDataViewEvent &event ); + void OnActivated( wxDataViewEvent &event ); + void OnHeaderClick( wxDataViewEvent &event ); + void OnHeaderRightClick( wxDataViewEvent &event ); + void OnSorted( wxDataViewEvent &event ); + + void OnRightClick( wxMouseEvent &event ); + void OnGoto( wxCommandEvent &event); private: wxDataViewCtrl* m_musicCtrl; @@ -426,6 +439,7 @@ private: wxObjectDataPtr m_list_model; wxTextCtrl * m_log; + wxLog *m_logOld; private: DECLARE_EVENT_TABLE() @@ -473,7 +487,8 @@ enum ID_DELETE_MUSIC = 101, ID_PREPEND_LIST = 200, - ID_DELETE_LIST = 201 + ID_DELETE_LIST = 201, + ID_GOTO = 202 }; BEGIN_EVENT_TABLE(MyFrame, wxFrame) @@ -483,9 +498,16 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame) EVT_BUTTON( ID_DELETE_MUSIC, MyFrame::OnDeleteMusic ) EVT_BUTTON( ID_PREPEND_LIST, MyFrame::OnPrependList ) EVT_BUTTON( ID_DELETE_LIST, MyFrame::OnDeleteList ) + EVT_BUTTON( ID_GOTO, MyFrame::OnGoto) EVT_DATAVIEW_MODEL_ITEM_ADDED( ID_MUSIC_CTRL, MyFrame::OnItemAdded ) EVT_DATAVIEW_MODEL_ITEM_DELETED( ID_MUSIC_CTRL, MyFrame::OnItemDeleted ) EVT_DATAVIEW_MODEL_VALUE_CHANGED( ID_MUSIC_CTRL, MyFrame::OnValueChanged ) + EVT_DATAVIEW_MODEL_ITEM_CHANGED( ID_MUSIC_CTRL, MyFrame::OnValueChanged ) + EVT_DATAVIEW_ITEM_ACTIVATED(ID_MUSIC_CTRL, MyFrame::OnActivated ) + EVT_DATAVIEW_COLUMN_HEADER_CLICK(ID_MUSIC_CTRL, MyFrame::OnHeaderClick) + EVT_DATAVIEW_COLUMN_HEADER_RIGHT_CLICKED(ID_MUSIC_CTRL, MyFrame::OnHeaderRightClick) + EVT_DATAVIEW_COLUMN_SORTED(ID_MUSIC_CTRL, MyFrame::OnSorted) + EVT_RIGHT_UP(MyFrame::OnRightClick) END_EVENT_TABLE() MyFrame::MyFrame(wxFrame *frame, wxChar *title, int x, int y, int w, int h): @@ -515,7 +537,7 @@ MyFrame::MyFrame(wxFrame *frame, wxChar *title, int x, int y, int w, int h): // MyMusic m_musicCtrl = new wxDataViewCtrl( this, ID_MUSIC_CTRL, wxDefaultPosition, - wxDefaultSize ); + wxDefaultSize, wxDV_MULTIPLE ); m_music_model = new MyMusicModel; m_musicCtrl->AssociateModel( m_music_model.get() ); @@ -534,7 +556,7 @@ MyFrame::MyFrame(wxFrame *frame, wxChar *title, int x, int y, int w, int h): // MyList m_listCtrl = new wxDataViewCtrl( this, wxID_ANY, wxDefaultPosition, - wxDefaultSize ); + wxDefaultSize, wxDV_MULTIPLE ); m_list_model = new MyListModel; m_listCtrl->AssociateModel( m_list_model.get() ); @@ -555,11 +577,14 @@ MyFrame::MyFrame(wxFrame *frame, wxChar *title, int x, int y, int w, int h): button_sizer->Add( 10, 10, 1 ); button_sizer->Add( new wxButton( this, ID_PREPEND_LIST, "Prepend"), 0, wxALL, 10 ); button_sizer->Add( new wxButton( this, ID_DELETE_LIST, "Delete selected"), 0, wxALL, 10 ); + button_sizer->Add( new wxButton( this, ID_GOTO, "Goto 50"), 0, wxALL, 10 ); main_sizer->Add( button_sizer, 0, wxGROW, 0 ); m_log = new wxTextCtrl( this, -1, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE ); - + m_logOld = wxLog::SetActiveTarget(new wxLogTextCtrl(m_log)); + wxLogMessage("This is the log window"); + main_sizer->Add( m_log, 1, wxGROW ); SetSizer( main_sizer ); @@ -577,9 +602,11 @@ void MyFrame::OnAddMozart(wxCommandEvent& WXUNUSED(event) ) void MyFrame::OnDeleteMusic(wxCommandEvent& WXUNUSED(event) ) { - wxDataViewItem item = m_musicCtrl->GetSelection(); - if (item.IsOk()) - m_music_model->Delete( item ); + wxDataViewItemArray items; + int len = m_musicCtrl->GetSelections( items ); + for( int i = 0; i < len; i ++ ) + if (items[i].IsOk()) + m_music_model->Delete( items[i] ); } void MyFrame::OnPrependList( wxCommandEvent& WXUNUSED(event) ) @@ -589,9 +616,11 @@ void MyFrame::OnPrependList( wxCommandEvent& WXUNUSED(event) ) void MyFrame::OnDeleteList( wxCommandEvent& WXUNUSED(event) ) { - wxDataViewItem item = m_listCtrl->GetSelection(); - if (item.IsOk()) - m_list_model->DeleteItem( item ); + wxDataViewItemArray items; + int len = m_listCtrl->GetSelections( items ); + for( int i = 0; i < len; i ++ ) + if (items[i].IsOk()) + m_list_model->DeleteItem( items[i] ); } void MyFrame::OnItemAdded( wxDataViewEvent &event ) @@ -599,7 +628,7 @@ void MyFrame::OnItemAdded( wxDataViewEvent &event ) if (!m_log) return; - m_log->AppendText( "EVT_DATAVIEW_MODEL_ITEM_ADDED\n" ); + wxLogMessage("wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_ADDED, Item Id: %d",event.GetItem().GetID()); } void MyFrame::OnItemDeleted( wxDataViewEvent &event ) @@ -607,7 +636,7 @@ void MyFrame::OnItemDeleted( wxDataViewEvent &event ) if (!m_log) return; - m_log->AppendText( "EVT_DATAVIEW_MODEL_ITEM_DELETED\n" ); + wxLogMessage( "EVT_DATAVIEW_MODEL_ITEM_DELETED, Item Id: %d", event.GetItem().GetID() ); } void MyFrame::OnValueChanged( wxDataViewEvent &event ) @@ -615,7 +644,52 @@ void MyFrame::OnValueChanged( wxDataViewEvent &event ) if (!m_log) return; - m_log->AppendText( "EVT_DATAVIEW_MODEL_VALUE_CHANGED\n" ); + wxLogMessage( "EVT_DATAVIEW_MODEL_VALUE_CHANGED, Item Id: %d; Column: %d", event.GetItem().GetID(), event.GetColumn() ); +} + +void MyFrame::OnActivated( wxDataViewEvent &event ) +{ + if(!m_log) + return; + + wxLogMessage("wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, Item Id: %d; Column: %d", event.GetItem().GetID(), event.GetColumn()); +} + +void MyFrame::OnHeaderClick( wxDataViewEvent &event ) +{ + if(!m_log) + return; + + wxLogMessage("wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK, Column: %d", event.GetColumn()); +} + +void MyFrame::OnHeaderRightClick( wxDataViewEvent &event ) +{ + if(!m_log) + return; + + wxLogMessage("wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK, Column: %d", event.GetColumn()); +} + +void MyFrame::OnSorted( wxDataViewEvent &event ) +{ + if(!m_log) + return; + + wxLogMessage("wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED, Column: %d", event.GetColumn()); +} + +void MyFrame::OnRightClick( wxMouseEvent &event ) +{ + if(!m_log) + return; + + wxLogMessage("wxEVT_MOUSE_RIGHT_UP, Click Point is X: %d, Y: %d", event.GetX(), event.GetY()); +} + +void MyFrame::OnGoto( wxCommandEvent &event) +{ + m_listCtrl->EnsureVisible(50); } void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event) ) diff --git a/src/common/datavcmn.cpp b/src/common/datavcmn.cpp index d6168328e9..f98deffbb6 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -533,6 +533,9 @@ void wxDataViewColumnBase::SetFlags(int flags) // wxDataViewCtrlBase // --------------------------------------------------------- +#include "wx/arrimpl.cpp" +WX_DEFINE_OBJARRAY(wxDataViewItemArray); + IMPLEMENT_ABSTRACT_CLASS(wxDataViewCtrlBase, wxControl) wxDataViewCtrlBase::wxDataViewCtrlBase() diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index 535fc5433f..2fb1c5b35a 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -66,7 +66,7 @@ static const int EXPANDER_MARGIN = 4; // wxDataViewHeaderWindow //----------------------------------------------------------------------------- -#define USE_NATIVE_HEADER_WINDOW 1 +#define USE_NATIVE_HEADER_WINDOW 0 // NB: for some reason, this class must be dllexport'ed or we get warnings from // MSVC in DLL build @@ -263,17 +263,17 @@ int LINKAGEMODE wxGenericTreeModelItemCmp( void * id1, void * id2); class wxDataViewTreeNode { public: - wxDataViewTreeNode( wxDataViewTreeNode * parent ) + wxDataViewTreeNode( wxDataViewTreeNode * parent = NULL ) :leaves( wxGenericTreeModelItemCmp ), nodes(wxGenericTreeModelNodeCmp) - { this->parent = parent; + { this->parent = parent; if( parent == NULL ) open = true; - else - open = false; + else + open = false; hasChildren = false; subTreeCount = 0; - } + } //I don't know what I need to do in the destructure ~wxDataViewTreeNode() { @@ -300,13 +300,13 @@ public: int GetIndentLevel() { int ret = 0 ; - wxDataViewTreeNode * node = this; - while( node->GetParent()->GetParent() != NULL ) - { - node = node->GetParent(); - ret ++; - } - return ret; + wxDataViewTreeNode * node = this; + while( node->GetParent()->GetParent() != NULL ) + { + node = node->GetParent(); + ret ++; + } + return ret; } bool IsOpen() @@ -357,7 +357,7 @@ public: int len = nds.GetCount(); if(len > 0) { - int i; + int i; for(i = 0; i < len; i ++) nodes.Add(nds[i]); for(i = 0; i < len; i ++) @@ -418,6 +418,7 @@ public: virtual ~wxDataViewMainWindow(); // notifications from wxDataViewModel + void SendModelEvent( wxEventType type, const wxDataViewItem & item); bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item ); bool ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item ); bool ItemChanged( const wxDataViewItem &item ); @@ -444,6 +445,7 @@ public: void OnRenameTimer(); void ScrollWindow( int dx, int dy, const wxRect *rect = NULL ); + void ScrollTo( int rows ); bool HasCurrentRow() { return m_currentRow != (unsigned int)-1; } void ChangeCurrentRow( unsigned int row ); @@ -459,7 +461,8 @@ public: unsigned int GetRowCount() ; wxDataViewItem GetSelection(); - + wxDataViewSelection GetSelections(){ return m_selection; } + void SetSelections( const wxDataViewSelection & sel ) { m_selection = sel; UpdateDisplay(); } void Select( const wxArrayInt& aSelections ); void SelectAllRows( bool on ); void SelectRow( unsigned int row, bool on ); @@ -482,7 +485,7 @@ public: //Some useful functions for row and item mapping wxDataViewItem GetItemByRow( unsigned int row ); - unsigned int GetRowByItem( const wxDataViewItem & item ); + int GetRowByItem( const wxDataViewItem & item ); //Methods for building the mapping tree void BuildTree( wxDataViewModel * model ); @@ -556,7 +559,7 @@ public: virtual bool Cleared() { return m_mainWindow->Cleared(); } virtual void Resort() - { m_mainWindow->Resort(); } + { m_mainWindow->Resort(); } wxDataViewMainWindow *m_mainWindow; }; @@ -1191,6 +1194,16 @@ void wxDataViewHeaderWindowMSW::UpdateDisplay() hdi.cxy = col->GetWidth(); hdi.cchTextMax = sizeof(hdi.pszText)/sizeof(hdi.pszText[0]); hdi.fmt = HDF_LEFT | HDF_STRING; + //hdi.fmt &= ~(HDF_SORTDOWN|HDF_SORTUP); + + //sorting support + if(model && model->GetSortingColumn() == i) + { + //The Microsoft Comctrl32.dll 6.0 support SORTUP/SORTDOWN, but they are not default + //see http://msdn2.microsoft.com/en-us/library/ms649534.aspx for more detail + //hdi.fmt |= model->GetSortOrderAscending()? HDF_SORTUP:HDF_SORTDOWN; + ; + } // lParam is reserved for application's use: // we store there the column index to use it later in MSWOnNotify @@ -1323,12 +1336,12 @@ bool wxDataViewHeaderWindowMSW::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARA { bool order = col->IsSortOrderAscending(); col->SetSortOrder(!order); - // model->SetSortOrderAscending(!order); + model->SetSortOrderAscending(!order); } else if(model) { model->SetSortingColumn(idx); - // model->SetSortOrderAscending(true); + model->SetSortOrderAscending(col->IsSortOrderAscending()); } } UpdateDisplay(); @@ -1492,7 +1505,7 @@ void wxGenericDataViewHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) int ch = h; wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE; - if (col->IsSortable()) + if (col->IsSortable() && GetOwner()->GetModel()->GetSortingColumn() == i) { if (col->IsSortOrderAscending()) sortArrow = wxHDR_SORT_ICON_UP; @@ -1645,10 +1658,37 @@ void wxGenericDataViewHeaderWindow::OnMouse( wxMouseEvent &event ) } else // click on a column { + wxDataViewModel * model = GetOwner()->GetModel(); wxEventType evt = event.LeftDown() ? wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK : wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK; SendEvent(evt, m_column); + + //Left click the header + if(event.LeftDown()) + { + wxDataViewColumn *col = GetColumn(m_column); + if(col->IsSortable()) + { + unsigned int colnum = model->GetSortingColumn(); + if(model && static_cast(colnum) == m_column) + { + bool order = col->IsSortOrderAscending(); + col->SetSortOrder(!order); + model->SetSortOrderAscending(!order); + } + else if(model) + { + model->SetSortingColumn(m_column); + model->SetSortOrderAscending(col->IsSortOrderAscending()); + } + } + UpdateDisplay(); + if(model) + model->Resort(); + //Send the column sorted event + SendEvent(wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED, m_column); + } } } else if (event.Moving()) @@ -1840,45 +1880,29 @@ public: virtual int operator() ( void * n ) = 0; }; -#if 0 -class ItemAddJob: public DoJob -{ -public: - ItemAddJob( const wxDataViewItem & parent, const wxDataViewItem & item, int * count ) - { this->parent = parent ; this->item = item ; m_count = count; } - virtual ~ItemAddJob(){}; - - virtual int operator() ( wxDataViewTreeNode * node ) - { - if( node->GetItem() == parent ) - { - node->SetHasChildren( true ); - wxDataViewTreeNode * newnode = new wxDataViewTreeNode( node ); - newnode->SetItem(item); - node->AppendChild( newnode); - *m_count = -1; - return OK; - } - return CONT; - } - -private: - int * m_count; - wxDataViewItem parent, item; -}; -#endif - bool Walker( wxDataViewTreeNode * node, DoJob & func ) { if( node==NULL || !node->HasChildren()) return false; + switch( func( node ) ) + { + case DoJob::OK : + return true ; + case DoJob::IGR: + return false; + case DoJob::CONT: + default: + ; + } + wxDataViewTreeNodes nodes = node->GetNodes(); wxDataViewTreeLeaves leaves = node->GetChildren(); int len_nodes = nodes.GetCount(); int len = leaves.GetCount(); int i = 0, nodes_i = 0; + for( ; i < len ; i ++ ) { void * n = leaves[i]; @@ -1887,17 +1911,6 @@ bool Walker( wxDataViewTreeNode * node, DoJob & func ) wxDataViewTreeNode * nd = nodes[nodes_i]; nodes_i++; - switch( func( nd ) ) - { - case DoJob::OK : - return true ; - case DoJob::IGR: - continue; - case DoJob::CONT: - default: - ; - } - if( Walker( nd , func ) ) return true; @@ -1917,12 +1930,25 @@ bool Walker( wxDataViewTreeNode * node, DoJob & func ) return false; } +void wxDataViewMainWindow::SendModelEvent( wxEventType type, const wxDataViewItem & item ) +{ + wxWindow *parent = GetParent(); + wxDataViewEvent le(type, parent->GetId()); + + le.SetEventObject(parent); + le.SetModel(GetOwner()->GetModel()); + le.SetItem( item ); + + parent->GetEventHandler()->ProcessEvent(le); +} + bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxDataViewItem & item) { g_model = GetOwner()->GetModel(); wxDataViewTreeNode * node; node = FindNode(parent); + SendModelEvent(wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_ADDED, item ); if( node == NULL ) return false; @@ -1933,6 +1959,7 @@ bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxData { wxDataViewTreeNode * newnode = new wxDataViewTreeNode( node ); newnode->SetItem(item); + newnode->SetHasChildren( true ); node->AddNode( newnode); } else @@ -1942,33 +1969,10 @@ bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxData m_count = -1; UpdateDisplay(); + return true; } -#if 0 -class ItemDeleteJob: public DoJob -{ -public: - ItemDeleteJob( const wxDataViewItem & item, int * count ) { m_item = item; m_count = count; } - virtual ~ItemDeleteJob(){} - virtual int operator() ( wxDataViewTreeNode * node ) - { - if( node->GetItem() == m_item ) - { - node->GetParent()->GetChildren().Remove( node ); - delete node; - *m_count = -1; - return DoJob::OK; - } - return DoJob::CONT; - } - -private: - int * m_count; - wxDataViewItem m_item; -}; -#endif - void DestroyTreeHelper( wxDataViewTreeNode * node); bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent, @@ -1978,6 +1982,7 @@ bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent, wxDataViewTreeNode * node; node = FindNode(parent); + SendModelEvent(wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_DELETED, item); if( node == NULL || node->GetChildren().Index( item.GetID() ) == wxNOT_FOUND ) { @@ -2025,13 +2030,14 @@ bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent, bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem & item) { g_model = GetOwner()->GetModel(); + g_model->Resort(); + + SendModelEvent(wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_CHANGED,item); - unsigned int row = GetRowByItem(item); - RefreshRow( row ); return true; } -bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem & item, unsigned int WXUNUSED(col) ) +bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem & item, unsigned int col ) { // NOTE: to be valid, we cannot use e.g. INT_MAX - 1 /*#define MAX_VIRTUAL_WIDTH 100000 @@ -2043,9 +2049,18 @@ bool wxDataViewMainWindow::ValueChanged( const wxDataViewItem & item, unsigned i return true; */ g_model = GetOwner()->GetModel(); + g_model->Resort(); + + //Send event + wxWindow *parent = GetParent(); + wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_MODEL_VALUE_CHANGED, parent->GetId()); + le.SetEventObject(parent); + le.SetModel(GetOwner()->GetModel()); + le.SetItem(item); + le.SetColumn(col); + le.SetDataViewColumn(GetOwner()->GetColumn(col)); + parent->GetEventHandler()->ProcessEvent(le); - unsigned int row = GetRowByItem(item); - RefreshRow( row ); return true; } @@ -2055,6 +2070,13 @@ bool wxDataViewMainWindow::Cleared() DestroyTree(); UpdateDisplay(); + + wxWindow *parent = GetParent(); + wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_MODEL_CLEARED, parent->GetId()); + le.SetEventObject(parent); + le.SetModel(GetOwner()->GetModel()); + parent->GetEventHandler()->ProcessEvent(le); + return true; } @@ -2100,6 +2122,14 @@ void wxDataViewMainWindow::ScrollWindow( int dx, int dy, const wxRect *rect ) GetOwner()->m_headerArea->ScrollWindow( dx, 0 ); } +void wxDataViewMainWindow::ScrollTo( int rows ) +{ + int x, y; + m_owner->GetScrollPixelsPerUnit( &x, &y ); + int sc = rows*m_lineHeight/y; + m_owner->Scroll(0, sc ); +} + void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) { wxDataViewModel *model = GetOwner()->GetModel(); @@ -2229,14 +2259,14 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) { // get the cell value and set it into the renderer wxVariant value; - wxDataViewTreeNode * node = GetTreeNodeByRow(item); - if( node == NULL ) - { - continue; - } + wxDataViewTreeNode * node = GetTreeNodeByRow(item); + if( node == NULL ) + { + continue; + } wxDataViewItem dataitem = node->GetItem(); - model->GetValue( value, dataitem, col->GetModelColumn()); + model->GetValue( value, dataitem, col->GetModelColumn()); cell->SetValue( value ); // update the y offset @@ -2604,7 +2634,7 @@ public: { current ++; if( current == static_cast(row)) - { + { ret = node->GetItem() ; return DoJob::OK; } @@ -2615,14 +2645,24 @@ public: return DoJob::IGR; } else + { + //If the current has no child node, we can find the desired item of the row number directly. + //This if can speed up finding in some case, and will has a very good effect when it comes to list view + if( node->GetNodes().GetCount() == 0) + { + int index = static_cast(row) - current - 1; + ret = node->GetChildren().Item( index ); + return DoJob::OK; + } return DoJob::CONT; + } } virtual int operator() ( void * n ) { current ++; if( current == static_cast(row)) - { + { ret = wxDataViewItem( n ) ; return DoJob::OK; } @@ -2637,7 +2677,7 @@ private: wxDataViewItem wxDataViewMainWindow::GetItemByRow(unsigned int row) { - RowToItemJob job( row, -1 ); + RowToItemJob job( row, -2 ); Walker( m_root , job ); return job.GetResult(); } @@ -2658,7 +2698,7 @@ public: { current ++; if( current == static_cast(row)) - { + { ret = node ; return DoJob::OK; } @@ -2671,16 +2711,28 @@ public: else { parent = node; + //If the current has no child node, we can find the desired item of the row number directly. + //This if can speed up finding in some case, and will has a very good effect when it comes to list view + if( node->GetNodes().GetCount() == 0) + { + int index = static_cast(row) - current - 1; + void * n = node->GetChildren().Item( index ); + ret = new wxDataViewTreeNode( parent ) ; + ret->SetItem( wxDataViewItem( n )); + ret->SetHasChildren(false); + return DoJob::OK; + } return DoJob::CONT; } + } virtual int operator() ( void * n ) { current ++; if( current == static_cast(row)) - { + { ret = new wxDataViewTreeNode( parent ) ; ret->SetItem( wxDataViewItem( n )); ret->SetHasChildren(false); @@ -2700,36 +2752,11 @@ private: wxDataViewTreeNode * wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row) { - RowToTreeNodeJob job( row , -1, m_root ); + RowToTreeNodeJob job( row , -2, m_root ); Walker( m_root , job ); return job.GetResult(); } -#if 0 -class CountJob : public DoJob -{ -public: - CountJob(){ count = 0 ; } - virtual ~CountJob(){}; - - virtual int operator () ( wxDataViewTreeNode * node ) - { - count ++; - if ( node->IsOpen()) - return DoJob::CONT; - else - return DoJob::IGR; - } - - unsigned int GetResult() - { - return count ; - } -private: - unsigned int count; -}; -#endif - void wxDataViewMainWindow::OnExpanding( unsigned int row ) { wxDataViewTreeNode * node = GetTreeNodeByRow(row); @@ -2775,10 +2802,13 @@ void wxDataViewMainWindow::OnCollapsing(unsigned int row) node = node->GetParent(); if( node != NULL ) { - int parent = GetRowByItem( node->GetItem()) ; - SelectRow( row, false); - SelectRow(parent , true ); - ChangeCurrentRow( parent ); + int parent = GetRowByItem( node->GetItem() ) ; + if( parent >= 0 ) + { + SelectRow( row, false); + SelectRow(parent , true ); + ChangeCurrentRow( parent ); + } } } if( !nd->HasChildren()) @@ -2805,7 +2835,6 @@ wxDataViewTreeNode * wxDataViewMainWindow::FindNode( const wxDataViewItem & item //Find the item along the parent-chain. //This algorithm is designed to speed up the node-finding method - bool found = true; wxDataViewTreeNode * node = m_root; for( ItemList::Node * n = list.GetFirst(); n; n = n->GetNext() ) { @@ -2814,23 +2843,14 @@ wxDataViewTreeNode * wxDataViewMainWindow::FindNode( const wxDataViewItem & item if( node->GetChildrenNumber() == 0 ) BuildTreeHelper(model, node->GetItem(), node); - int len = node->GetNodeNumber(); wxDataViewTreeNodes nodes = node->GetNodes(); - int j = 0; - for( ; j < len; j ++) - { - if( nodes[j]->GetItem() == *(n->GetData())) - { - node = nodes[j]; - break; - } - } - // Whenever we can't find the node in any level, return NULL to indicate the item can't be found - if( j == len ) - { - found = false; + //The wxSortedArray search a node in binary search, so using Item() is more efficient + wxDataViewTreeNode temp; + temp.SetItem(*(n->GetData())); + int index = nodes.Index( &temp ); + if( index == wxNOT_FOUND ) return NULL; - } + node = nodes[index]; } else return NULL; @@ -2847,9 +2867,10 @@ class ItemToRowJob : public DoJob { public: ItemToRowJob(const wxDataViewItem & item, ItemList::Node * node ) - { this->item = item ; ret = 0 ; nd = node ; } + { this->item = item ; ret = -1 ; nd = node ; } virtual ~ItemToRowJob(){}; + //Maybe binary search will help to speed up this process virtual int operator() ( wxDataViewTreeNode * node) { ret ++; @@ -2887,22 +2908,28 @@ private: }; -unsigned int wxDataViewMainWindow::GetRowByItem(const wxDataViewItem & item) +int wxDataViewMainWindow::GetRowByItem(const wxDataViewItem & item) { wxDataViewModel * model = GetOwner()->GetModel(); if( model == NULL ) return 0; + if( !item.IsOk() ) + return -1; + //Compose the a parent-chain of the finding item ItemList list; + wxDataViewItem * pItem = NULL; list.DeleteContents( true ); wxDataViewItem it( item ); while( it.IsOk() ) { - wxDataViewItem * pItem = new wxDataViewItem( it ); + pItem = new wxDataViewItem( it ); list.Insert( pItem ); it = model->GetParent( it ); } + pItem = new wxDataViewItem( ); + list.Insert( pItem ); ItemToRowJob job( item, list.GetFirst() ); Walker(m_root , job ); @@ -3007,11 +3034,11 @@ void wxDataViewMainWindow::OnChar( wxKeyEvent &event ) break; //Add the process for tree expanding/collapsing case WXK_LEFT: - OnCollapsing(m_currentRow); - break; - case WXK_RIGHT: - OnExpanding( m_currentRow); - break; + OnCollapsing(m_currentRow); + break; + case WXK_RIGHT: + OnExpanding( m_currentRow); + break; case WXK_END: if (!IsEmpty()) OnArrowChar( GetRowCount() - 1, event ); @@ -3142,6 +3169,16 @@ void wxDataViewMainWindow::OnMouse( wxMouseEvent &event ) wxRect cell_rect( xpos, current * m_lineHeight, col->GetWidth(), m_lineHeight ); cell->Activate( cell_rect, model, item, col->GetModelColumn() ); + + wxWindow *parent = GetParent(); + wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, parent->GetId()); + + le.SetEventObject(parent); + le.SetColumn(col->GetModelColumn()); + le.SetDataViewColumn(col); + le.SetModel(GetOwner()->GetModel()); + + parent->GetEventHandler()->ProcessEvent(le); } return; } @@ -3456,54 +3493,153 @@ void wxDataViewCtrl::DoSetIndent() m_clientArea->UpdateDisplay(); } -wxDataViewItem wxDataViewCtrl::GetSelection() +//Selection code with wxDataViewItem as parameters +int wxDataViewCtrl::GetSelections( wxDataViewItemArray & sel ) const +{ + sel.Empty(); + wxDataViewSelection selection = m_clientArea->GetSelections(); + int len = selection.GetCount(); + for( int i = 0; i < len; i ++) + { + unsigned int row = selection[i]; + sel.Add( m_clientArea->GetItemByRow( row ) ); + } + return len; +} + +void wxDataViewCtrl::SetSelections( const wxDataViewItemArray & sel ) +{ + wxDataViewSelection selection(wxDataViewSelectionCmp) ; + int len = sel.GetCount(); + for( int i = 0; i < len; i ++ ) + { + int row = m_clientArea->GetRowByItem( sel[i] ); + if( row >= 0 ) + selection.Add( static_cast(row) ); + } + m_clientArea->SetSelections( selection ); +} + +void wxDataViewCtrl::Select( const wxDataViewItem & item ) { - return m_clientArea->GetSelection(); + int row = m_clientArea->GetRowByItem( item ); + if( row >= 0 ) + m_clientArea->SelectRow(row, true); } -/******************************************************************** -void wxDataViewCtrl::SetSelection( int row ) +void wxDataViewCtrl::Unselect( const wxDataViewItem & item ) { - m_clientArea->SelectRow(row, true); + int row = m_clientArea->GetRowByItem( item ); + if( row >= 0 ) + m_clientArea->SelectRow(row, false); } -void wxDataViewCtrl::SetSelectionRange( unsigned int from, unsigned int to ) +bool wxDataViewCtrl::IsSelected( const wxDataViewItem & item ) const { - m_clientArea->SelectRows(from, to, true); + int row = m_clientArea->GetRowByItem( item ); + if( row >= 0 ) + { + return m_clientArea->IsRowSelected(row); + } + return false; } -void wxDataViewCtrl::SetSelections( const wxArrayInt& aSelections ) +//Selection code with row number as parameter +int wxDataViewCtrl::GetSelections( wxArrayInt & sel ) const { - m_clientArea->Select(aSelections); + sel.Empty(); + wxDataViewSelection selection = m_clientArea->GetSelections(); + int len = selection.GetCount(); + for( int i = 0; i < len; i ++) + { + unsigned int row = selection[i]; + sel.Add( row ); + } + return len; } -void wxDataViewCtrl::Unselect( unsigned int WXUNUSED(row) ) +void wxDataViewCtrl::SetSelections( const wxArrayInt & sel ) { - // FIXME - TODO + wxDataViewSelection selection(wxDataViewSelectionCmp) ; + int len = sel.GetCount(); + for( int i = 0; i < len; i ++ ) + { + int row = sel[i]; + if( row >= 0 ) + selection.Add( static_cast(row) ); + } + m_clientArea->SetSelections( selection ); } -bool wxDataViewCtrl::IsSelected( unsigned int WXUNUSED(row) ) const +void wxDataViewCtrl::Select( int row ) { - // FIXME - TODO + if( row >= 0 ) + m_clientArea->SelectRow( row, true ); +} +void wxDataViewCtrl::Unselect( int row ) +{ + if( row >= 0 ) + m_clientArea->SelectRow(row, false); +} + +bool wxDataViewCtrl::IsSelected( int row ) const +{ + if( row >= 0 ) + return m_clientArea->IsRowSelected(row); return false; } -int wxDataViewCtrl::GetSelection() const +void wxDataViewCtrl::SelectRange( int from, int to ) { - // FIXME - TODO + wxArrayInt sel; + for( int i = from; i < to; i ++ ) + sel.Add( i ); + m_clientArea->Select(sel); +} - return -1; +void wxDataViewCtrl::UnselectRange( int from, int to ) +{ + wxDataViewSelection sel = m_clientArea->GetSelections(); + for( int i = from; i < to; i ++ ) + if( sel.Index( i ) != wxNOT_FOUND ) + sel.Remove( i ); + m_clientArea->SetSelections(sel); } -int wxDataViewCtrl::GetSelections(wxArrayInt& WXUNUSED(aSelections) ) const +void wxDataViewCtrl::SelectAll() { - // FIXME - TODO + m_clientArea->SelectAllRows(true); +} - return 0; +void wxDataViewCtrl::UnselectAll() +{ + m_clientArea->SelectAllRows(false); } -*********************************************************************/ -#endif + +void wxDataViewCtrl::EnsureVisible( int row ) +{ + m_clientArea->ScrollTo( row ); +} + +void wxDataViewCtrl::EnsureVisible( const wxDataViewItem & item ) +{ + int row = m_clientArea->GetRowByItem(item); + if( row >= 0 ) + EnsureVisible(row); +} + +wxDataViewItem wxDataViewCtrl::GetItemByRow( unsigned int row ) const +{ + return m_clientArea->GetItemByRow( row ); +} + +int wxDataViewCtrl::GetRowByItem( const wxDataViewItem & item ) const +{ + return m_clientArea->GetRowByItem( item ); +} + + #endif // !wxUSE_GENERICDATAVIEWCTRL #endif -- 2.45.2