From 3b6280beb2561836b296b4b01493b053ed4bf69e Mon Sep 17 00:00:00 2001 From: Robert Roebling Date: Thu, 12 Jul 2007 12:58:28 +0000 Subject: [PATCH] Bo's patch for generic code, more sorting code, WIP git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@47374 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/dataview.h | 18 +- include/wx/generic/dataview.h | 3 + include/wx/gtk/dataview.h | 7 +- src/common/datavcmn.cpp | 2 + src/generic/datavgen.cpp | 345 +++++++++++++++++++++++++++------- src/gtk/dataview.cpp | 98 +++++++++- 6 files changed, 397 insertions(+), 76 deletions(-) diff --git a/include/wx/dataview.h b/include/wx/dataview.h index 0a6a5a8f54..459885406b 100644 --- a/include/wx/dataview.h +++ b/include/wx/dataview.h @@ -410,13 +410,29 @@ public: virtual bool ClearColumns(); virtual wxDataViewColumn* GetColumn( unsigned int pos ); + void SetExpanderColumn( unsigned int col ) + { m_expander_column = col ; DoSetExpanderColumn(); } + unsigned int GetExpanderColumn() const + { return m_expander_column; } + + void SetIndent( int indent ) + { m_indent = indent ; DoSetIndent(); } + int GetIndent() const + { return m_indent; } + // TODO selection code +protected: + virtual void DoSetExpanderColumn() = 0 ; + virtual void DoSetIndent() = 0; + private: wxDataViewModel *m_model; wxList m_cols; wxDataViewEventModelNotifier *m_eventNotifier; - + unsigned int m_expander_column; + int m_indent ; + protected: DECLARE_DYNAMIC_CLASS_NO_COPY(wxDataViewCtrlBase) }; diff --git a/include/wx/generic/dataview.h b/include/wx/generic/dataview.h index 82837366ea..10ddc2071c 100644 --- a/include/wx/generic/dataview.h +++ b/include/wx/generic/dataview.h @@ -349,6 +349,9 @@ public: virtual bool AssociateModel( wxDataViewModel *model ); virtual bool AppendColumn( wxDataViewColumn *col ); + virtual void DoSetExpanderColumn(); + virtual void DoSetIndent(); + /********************selection code********************* virtual void SetSelection( int row ); // -1 for unselect virtual void SetSelectionRange( unsigned int from, unsigned int to ); diff --git a/include/wx/gtk/dataview.h b/include/wx/gtk/dataview.h index c9e544bb91..ab007a505a 100644 --- a/include/wx/gtk/dataview.h +++ b/include/wx/gtk/dataview.h @@ -312,13 +312,18 @@ public: GtkWidget *GtkGetTreeView() { return m_treeview; } wxWindow *GetMainWindow() { return (wxWindow*) this; } - + +protected: + virtual void DoSetExpanderColumn(); + virtual void DoSetIndent(); + private: friend class wxDataViewCtrlDC; friend class wxDataViewColumn; friend class wxGtkDataViewModelNotifier; GtkWidget *m_treeview; wxDataViewModelNotifier *m_notifier; + virtual void OnInternalIdle(); diff --git a/src/common/datavcmn.cpp b/src/common/datavcmn.cpp index 684c4bea29..9cd318eb0f 100644 --- a/src/common/datavcmn.cpp +++ b/src/common/datavcmn.cpp @@ -372,6 +372,8 @@ wxDataViewCtrlBase::wxDataViewCtrlBase() m_model = NULL; m_cols.DeleteContents( true ); m_eventNotifier = NULL; + m_expander_column = 0; + m_indent = 8; } wxDataViewCtrlBase::~wxDataViewCtrlBase() diff --git a/src/generic/datavgen.cpp b/src/generic/datavgen.cpp index 22efe3dfd2..e590c950fa 100644 --- a/src/generic/datavgen.cpp +++ b/src/generic/datavgen.cpp @@ -57,6 +57,8 @@ static const int PADDING_RIGHTLEFT = 3; // the cell padding on the top/bottom static const int PADDING_TOPBOTTOM = 1; +// the expander space margin +static const int EXPANDER_MARGIN = 4; bool operator == ( const wxDataViewItem & left, const wxDataViewItem & right ) { @@ -284,8 +286,20 @@ public: void SetItem( wxDataViewItem & item ) { this->item = item; } unsigned int GetChildrenNumber() { return children.GetCount(); } + int GetIndentLevel() + { + int ret = 0 ; + wxDataViewTreeNode * node = this; + while( node->GetParent()->GetParent() != NULL ) + { + node = node->GetParent(); + ret ++; + } + return ret; + } bool IsOpen() { return open; } + void ToggleOpen(){ open = !open; } bool HasChildren() { return children.GetCount() != 0; } private: wxDataViewTreeNode * parent; @@ -346,8 +360,9 @@ public: int GetCountPerPage() const; int GetEndOfLastCol() const; unsigned int GetFirstVisibleRow() const; - unsigned int GetLastVisibleRow() const; - unsigned int GetRowCount() const; + //I change this method to un const because in the tree view, the displaying number of the tree are changing along with the expanding/collapsing of the tree nodes + unsigned int GetLastVisibleRow(); + unsigned int GetRowCount() ; void Select( const wxArrayInt& aSelections ); void SelectAllRows( bool on ); @@ -376,6 +391,14 @@ public: //Methods for building the mapping tree void BuildTree( wxDataViewModel * model ); void DestroyTree(); +private: + wxDataViewTreeNode * GetTreeNodeByRow( unsigned int row ); + wxDataViewTreeNode * GetTreeNodeByItem( const wxDataViewItem & item ) { return NULL; } + + int RecalculateCount() ; + + void OnExpanding( unsigned int row ); + void OnCollapsing( unsigned int row ); private: wxDataViewCtrl *m_owner; @@ -402,9 +425,12 @@ private: // the pen used to draw horiz/vertical rules wxPen m_penRule; + // the pen used to draw the expander and the lines + wxPen m_penExpander; + //This is the tree structure of the model wxDataViewTreeNode * m_root; - unsigned int m_count; + int m_count; private: DECLARE_DYNAMIC_CLASS(wxDataViewMainWindow) DECLARE_EVENT_TABLE() @@ -1620,9 +1646,12 @@ wxDataViewMainWindow::wxDataViewMainWindow( wxDataViewCtrl *parent, wxWindowID i m_penRule = wxPen(GetRuleColour(), 1, wxSOLID); + //Here I compose a pen can draw black lines, maybe there are something system colour to use + m_penExpander = wxPen( wxColour(0,0,0), 1, wxSOLID ); //Some new added code to deal with the tree structure m_root = new wxDataViewTreeNode( NULL ); - m_count = 0 ; + //Make m_count = -1 will cause the class recaculate the real displaying number of rows. + m_count = -1 ; UpdateDisplay(); } @@ -1665,7 +1694,7 @@ class DoJob { public: DoJob(){}; - virtual ~DoJob(){}; + virtual ~DoJob() { } virtual bool operator() ( wxDataViewTreeNode * node ) = 0 ; }; @@ -1674,27 +1703,28 @@ class ItemAddJob: public DoJob { public: ItemAddJob( const wxDataViewItem & parent, const wxDataViewItem & item ) - { this->parent = parent ; this->item = item ; } - virtual ~ItemAddJob(){}; + { this->parent = parent ; this->item = item; } + virtual ~ItemAddJob() { } virtual bool operator() ( wxDataViewTreeNode * node ) { if( node->GetItem() == parent ) { wxDataViewTreeNode * newnode = new wxDataViewTreeNode( node ); - newnode->SetItem(item); - node->AppendChild( newnode); - return true; + newnode->SetItem(item); + node->AppendChild( newnode); + return true; } - return false; + return false; } + private: wxDataViewItem parent, item; }; bool Walker( wxDataViewTreeNode * node, DoJob & func ) { - if( !node->HasChildren()) + if( node==NULL || !node->HasChildren()) return false; wxDataViewTreeNodes nodes = node->GetChildren(); @@ -1712,7 +1742,6 @@ bool Walker( wxDataViewTreeNode * node, DoJob & func ) } - bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxDataViewItem & item) { ItemAddJob job( parent, item); @@ -1814,7 +1843,7 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) unsigned int item_start = wxMax( 0, (update.y / m_lineHeight) ); unsigned int item_count = wxMin( (int)(((update.y + update.height) / m_lineHeight) - item_start + 1), - (int)(m_count- item_start) ); + (int)(GetRowCount( )- item_start) ); unsigned int item_last = item_start + item_count; // compute which columns needs to be redrawn @@ -1925,16 +1954,53 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) { // get the cell value and set it into the renderer wxVariant value; - wxDataViewItem dataitem = GetItemByRow(item); - model->GetValue( value, dataitem, col->GetModelColumn()); + wxDataViewTreeNode * node = GetTreeNodeByRow(item); + if( node == NULL ) + continue; + + wxDataViewItem dataitem = node->GetItem(); + model->GetValue( value, dataitem, col->GetModelColumn()); cell->SetValue( value ); // update the y offset cell_rect.y = item * m_lineHeight; - // cannot be bigger than allocated space + //Draw the expander here. Please notice that I use const number for all pixel data. When the final API are determined + //I will change this to the data member of the class wxDataViewCtrl + int indent = node->GetIndentLevel(); + if( col->GetModelColumn() == GetOwner()->GetExpanderColumn() ) + { + //Calculate the indent first + indent = cell_rect.x + GetOwner()->GetIndent() * indent; + + int expander_width = m_lineHeight - 2*EXPANDER_MARGIN; + // change the cell_rect.x to the appropriate pos + int expander_x = indent + EXPANDER_MARGIN , expander_y = cell_rect.y + EXPANDER_MARGIN ; + indent = indent + m_lineHeight ; //try to use the m_lineHeight as the expander space + dc.SetPen( m_penExpander ); + dc.SetBrush( wxNullBrush ); + if( node->HasChildren() ) + { + dc.DrawRoundedRectangle( expander_x,expander_y,expander_width,expander_width, 1.0); + dc.DrawLine( expander_x + 2 , expander_y + expander_width/2, expander_x + expander_width - 2, expander_y + expander_width/2 ); + + if( !node->IsOpen() ) + dc.DrawLine( expander_x + expander_width/2, expander_y + 2, expander_x + expander_width/2, expander_y + expander_width -2 ); + } + else + { + // I am wandering whether we should draw dot lines between tree nodes + } + + //force the expander column to left-center align + cell->SetAlignment( wxALIGN_CENTER_VERTICAL ); + } + + + // cannot be bigger than allocated space wxSize size = cell->GetSize(); - size.x = wxMin( size.x + 2*PADDING_RIGHTLEFT, cell_rect.width ); + // Because of the tree structure indent, here we should minus the width of the cell for drawing + size.x = wxMin( size.x + 2*PADDING_RIGHTLEFT, cell_rect.width - indent ); size.y = wxMin( size.y + 2*PADDING_TOPBOTTOM, cell_rect.height ); wxRect item_rect(cell_rect.GetTopLeft(), size); @@ -1962,6 +2028,9 @@ void wxDataViewMainWindow::OnPaint( wxPaintEvent &WXUNUSED(event) ) item_rect.width = size.x - 2 * PADDING_RIGHTLEFT; item_rect.height = size.y - 2 * PADDING_TOPBOTTOM; + //Here we add the tree indent + item_rect.x += indent; + int state = 0; if (m_selection.Index(item) != wxNOT_FOUND) state |= wxDATAVIEW_CELL_SELECTED; @@ -2012,7 +2081,7 @@ unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const return y / m_lineHeight; } -unsigned int wxDataViewMainWindow::GetLastVisibleRow() const +unsigned int wxDataViewMainWindow::GetLastVisibleRow() { wxSize client_size = GetClientSize(); m_owner->CalcUnscrolledPosition( client_size.x, client_size.y, @@ -2021,10 +2090,18 @@ unsigned int wxDataViewMainWindow::GetLastVisibleRow() const return wxMin( GetRowCount()-1, ((unsigned)client_size.y/m_lineHeight)+1 ); } -unsigned int wxDataViewMainWindow::GetRowCount() const +unsigned int wxDataViewMainWindow::GetRowCount() { + if ( m_count == -1 ) + { + m_count = RecalculateCount(); + int width, height; + GetVirtualSize( &width, &height ); + height = m_count * m_lineHeight; + + SetVirtualSize( width, height ); + } return m_count; - //return wx_const_cast(wxDataViewCtrl*, GetOwner())->GetModel()->GetRowCount(); } void wxDataViewMainWindow::ChangeCurrentRow( unsigned int row ) @@ -2237,31 +2314,6 @@ wxRect wxDataViewMainWindow::GetLineRect( unsigned int row ) const return rect; } -/* -static int tree_walk_current ; -wxDataViewTreeNode * TreeWalk( unsigned int row , wxDataViewTreeNode * node ) -{ - wxDataViewTreeNode * ret ; - if( tree_walk_current == row ) - return node; - - if( node->HasChildren() && node->IsOpen()) - { - wxDataViewTreeNodes nodes = node->GetChildren(); - int len = nodes.GetCount(); - int i = 0 ; - for( ; i < len; i ++) - { - tree_walk_current ++; - ret = TreeWalk( row, nodes[i] ); - if( ret != NULL ) - return ret; - } - } - return NULL; -} -*/ - class RowToItemJob: public DoJob { public: @@ -2270,16 +2322,17 @@ public: virtual bool operator() ( wxDataViewTreeNode * node ) { - if( current == row) - { - ret = node->GetItem() ; - return true; - } - current ++; - return false; - } - - wxDataViewItem GetResult(){ return ret; } + if ( current == row) + { + ret = node->GetItem() ; + return true; + } + current ++; + return false; + } + + wxDataViewItem GetResult() { return ret; } + private: unsigned int row; int current ; @@ -2293,22 +2346,130 @@ wxDataViewItem wxDataViewMainWindow::GetItemByRow(unsigned int row) return job.GetResult(); } +class RowToTreeNodeJob: public DoJob +{ +public: + RowToTreeNodeJob( unsigned int row , int current ) + { this->row = row; this->current = current ; ret = NULL ; } + virtual ~RowToTreeNodeJob() { } + + virtual int operator() ( wxDataViewTreeNode * node ) + { + if( current == row) + { + ret = node ; + return DoJob::OK; + } + current ++; + if ( node->IsOpen()) + return DoJob::CONT; + else + return DoJob::IGR; + } + + wxDataViewTreeNode * GetResult(){ return ret; } +private: + unsigned int row; + int current ; + wxDataViewTreeNode * ret; +}; + + +wxDataViewTreeNode * wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row) +{ + RowToTreeNodeJob job( row , 0 ); + Walker( m_root , job ); + return job.GetResult(); +} + +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; +}; + +void wxDataViewMainWindow::OnExpanding( unsigned int row ) +{ + wxDataViewTreeNode * node = GetTreeNodeByRow(row); + if( node != NULL ) + { + if (node->HasChildren()) + if (!node->IsOpen()) + { + node->ToggleOpen(); + m_count = -1; + Refresh(); + // RefreshRows(row,GetLastVisibleRow()); + } + } +} + +void wxDataViewMainWindow::OnCollapsing(unsigned int row) +{ + wxDataViewTreeNode * node = GetTreeNodeByRow(row); + if (node != NULL) + { + if( node->HasChildren() && node->IsOpen() ) + { + node->ToggleOpen(); + m_count = -1; + Refresh(); + //RefreshRows(row,GetLastVisibleRow()); + } + else + { + node = node->GetParent(); + if( node != NULL ) + { + int parent = GetRowByItem( node->GetItem()) ; + SelectRow( row, false); + SelectRow(parent , true ); + ChangeCurrentRow( parent ); + } + } + } +} + +int wxDataViewMainWindow::RecalculateCount() +{ + CountJob job; + Walker( m_root, job ); + return job.GetResult(); +} + class ItemToRowJob : public DoJob { public: - ItemToRowJob(const wxDataViewItem & item){ this->item = item ; } + ItemToRowJob(const wxDataViewItem & item){ this->item = item ; ret = 0 ; } virtual ~ItemToRowJob(){}; virtual bool operator() ( wxDataViewTreeNode * node) { ret ++; if( node->GetItem() == item ) - return true; - - return false; + return true; + return false; } - int GetResult(){ return ret; } + //the row number is begin from zero + int GetResult(){ return ret -1 ; } private: wxDataViewItem item; int ret; @@ -2331,11 +2492,11 @@ unsigned int BuildTreeHelper( wxDataViewModel * model, wxDataViewItem & item, w while( i.IsOk() ) { wxDataViewTreeNode * n = new wxDataViewTreeNode( node ); - n->SetItem(i); - node->AppendChild(n); - int num = BuildTreeHelper( model, i, n) + 1; - sum += num ; - i = model->GetNextSibling( i ); + n->SetItem(i); + node->AppendChild(n); + int num = BuildTreeHelper( model, i, n) + 1; + sum += num ; + i = model->GetNextSibling( i ); } return sum; } @@ -2344,7 +2505,8 @@ void wxDataViewMainWindow::BuildTree(wxDataViewModel * model) { //First we define a invalid item to fetch the top-level elements wxDataViewItem item; - m_count = BuildTreeHelper( model, item, m_root); + BuildTreeHelper( model, item, m_root); + m_count = -1 ; } void DestroyTreeHelper( wxDataViewTreeNode * node ) @@ -2352,9 +2514,9 @@ void DestroyTreeHelper( wxDataViewTreeNode * node ) if( node->HasChildren() ) { int len = node->GetChildrenNumber(); - int i = 0 ; - wxDataViewTreeNodes nodes = node->GetChildren(); - for( ; i < len; i ++ ) + int i = 0 ; + wxDataViewTreeNodes nodes = node->GetChildren(); + for( ; i < len; i ++ ) { DestroyTreeHelper(nodes[i]); } @@ -2403,7 +2565,13 @@ void wxDataViewMainWindow::OnChar( wxKeyEvent &event ) if ( m_currentRow < GetRowCount() - 1 ) OnArrowChar( m_currentRow + 1, event ); break; - + //Add the process for tree expanding/collapsing + case WXK_LEFT: + OnCollapsing(m_currentRow); + break; + case WXK_RIGHT: + OnExpanding( m_currentRow); + break; case WXK_END: if (!IsEmpty()) OnArrowChar( GetRowCount() - 1, event ); @@ -2554,7 +2722,28 @@ void wxDataViewMainWindow::OnMouse( wxMouseEvent &event ) SelectRow( m_lineSelectSingleOnUp, true ); } - if (m_lastOnSame) + //Process the event of user clicking the expander + bool expander = false; + wxDataViewTreeNode * node = GetTreeNodeByRow(current); + if( node!=NULL && node->HasChildren() ) + { + int indent = node->GetIndentLevel(); + indent = GetOwner()->GetIndent()*indent; + wxRect rect( xpos + indent + EXPANDER_MARGIN, current * m_lineHeight + EXPANDER_MARGIN, m_lineHeight-2*EXPANDER_MARGIN,m_lineHeight-2*EXPANDER_MARGIN); + if( rect.Contains( x, y) ) + { + expander = true; + node->ToggleOpen(); + m_count = -1; //make the current row number fail + + Refresh(); + //int last_row = GetLastVisibleRow(); + //RefreshRows( current, last_row ); + } + } + + //If the user click the expander, we do not do editing even if the column with expander are editable + if (m_lastOnSame && !expander ) { if ((col == m_currentCol) && (current == m_currentRow) && (cell->GetMode() == wxDATAVIEW_CELL_EDITABLE) ) @@ -2810,6 +2999,18 @@ void wxDataViewCtrl::OnColumnChange() m_clientArea->UpdateDisplay(); } + +void wxDataViewCtrl::DoSetExpanderColumn() +{ + m_clientArea->UpdateDisplay(); +} + +void wxDataViewCtrl::DoSetIndent() +{ + m_clientArea->UpdateDisplay(); +} + + /******************************************************************** void wxDataViewCtrl::SetSelection( int row ) { diff --git a/src/gtk/dataview.cpp b/src/gtk/dataview.cpp index 7ab2a3eeda..20eccb9d22 100644 --- a/src/gtk/dataview.cpp +++ b/src/gtk/dataview.cpp @@ -42,7 +42,94 @@ // classes //----------------------------------------------------------------------------- -class wxDataViewCtrl; +//----------------------------------------------------------------------------- +// wxGtkTreeModelNode +//----------------------------------------------------------------------------- + +class wxGtkTreeModelNode; +WX_DEFINE_ARRAY_PTR( wxGtkTreeModelNode*, wxGtkTreeModelNodes ); + +class wxGtkTreeModelNode +{ +public: + wxGtkTreeModelNode( wxGtkTreeModelNode* parent ) + { + m_parent = parent; + } + + ~wxGtkTreeModelNode() + { + size_t count = m_children.GetCount(); + size_t i; + for (i = 0; i < count; i++) + { + wxGtkTreeModelNode *child = m_children[i]; + delete child; + } + } + + wxGtkTreeModelNode* GetParent() + { return m_parent; } + wxGtkTreeModelNodes &GetChildren() + { return m_children; } + wxGtkTreeModelNode* GetNthChild( unsigned int n ) + { return m_children.Item( n ); } + void Insert( wxGtkTreeModelNode* child, unsigned int n) + { m_children.Insert( child, n); } + void Append( wxGtkTreeModelNode* child ) + { m_children.Add( child ); } + + unsigned int GetChildCount() { return m_children.GetCount(); } + + wxDataViewItem &GetItem() { return m_item; } + void SetItem( wxDataViewItem& item ) { m_item = item; } + + bool HasChildren() { return m_hasChildren; } + void SetHasChildren( bool has ) { m_hasChildren = has; } + +private: + wxGtkTreeModelNode *m_parent; + wxGtkTreeModelNodes m_children; + wxDataViewItem m_item; + bool m_hasChildren; +}; + + +extern "C" { +typedef struct _GtkWxTreeModel GtkWxTreeModel; +} + +class wxGtkTreeModel +{ +public: + wxGtkTreeModel( wxDataViewModel *wx_model, GtkWxTreeModel *gtk_model ) + { + m_wx_model = wx_model; + m_gtk_model = gtk_model; + m_root = NULL; + InitTree(); + } + + ~wxGtkTreeModel(); + + gboolean get_iter( GtkTreeIter *iter, GtkTreePath *path ); + GtkTreePath *get_path( GtkTreeIter *iter); + gboolean iter_next( GtkTreeIter *iter ); + gboolean iter_children( GtkTreeIter *iter, GtkTreeIter *parent); + gboolean iter_has_child( GtkTreeIter *iter ); + gint iter_n_children( GtkTreeIter *iter ); + gboolean iter_nth_child( GtkTreeIter *iter, GtkTreeIter *parent, gint n ); + gboolean iter_parent( GtkTreeIter *iter, GtkTreeIter *child ); + +protected: + void InitTree(); + wxGtkTreeModelNode *FindNode( GtkTreeIter *iter ); + +private: + wxGtkTreeModelNode *m_root; + wxDataViewModel *m_wx_model; + GtkWxTreeModel *m_gtk_model; +}; //----------------------------------------------------------------------------- // data @@ -65,7 +152,6 @@ extern "C" { GType gtk_wx_tree_model_get_type (void); -typedef struct _GtkWxTreeModel GtkWxTreeModel; typedef struct _GtkWxTreeModelClass GtkWxTreeModelClass; struct _GtkWxTreeModel @@ -2300,6 +2386,14 @@ bool wxDataViewCtrl::AppendColumn( wxDataViewColumn *col ) return true; } +void wxDataViewCtrl::DoSetExpanderColumn() +{ +} + +void wxDataViewCtrl::DoSetIndent() +{ +} + void wxDataViewCtrl::GtkDisableSelectionEvents() { GtkTreeSelection *selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(m_treeview) ); -- 2.45.2