+void wxDataViewMainWindow::RefreshRows( unsigned int from, unsigned int to )
+{
+ if (from > to)
+ {
+ unsigned int tmp = to;
+ to = from;
+ from = tmp;
+ }
+
+ wxRect rect( 0, from*m_lineHeight, GetEndOfLastCol(), (to-from+1) * m_lineHeight );
+ m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
+
+ wxSize client_size = GetClientSize();
+ wxRect client_rect( 0, 0, client_size.x, client_size.y );
+ wxRect intersect_rect = client_rect.Intersect( rect );
+ if (intersect_rect.width > 0)
+ Refresh( true, &intersect_rect );
+}
+
+void wxDataViewMainWindow::RefreshRowsAfter( unsigned int firstRow )
+{
+ unsigned int count = GetRowCount();
+ if (firstRow > count)
+ return;
+
+ wxRect rect( 0, firstRow*m_lineHeight, GetEndOfLastCol(), count * m_lineHeight );
+ m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
+
+ wxSize client_size = GetClientSize();
+ wxRect client_rect( 0, 0, client_size.x, client_size.y );
+ wxRect intersect_rect = client_rect.Intersect( rect );
+ if (intersect_rect.width > 0)
+ Refresh( true, &intersect_rect );
+}
+
+void wxDataViewMainWindow::OnArrowChar(unsigned int newCurrent, const wxKeyEvent& event)
+{
+ wxCHECK_RET( newCurrent < GetRowCount(),
+ _T("invalid item index in OnArrowChar()") );
+
+ // if there is no selection, we cannot move it anywhere
+ if (!HasCurrentRow())
+ return;
+
+ unsigned int oldCurrent = m_currentRow;
+
+ // in single selection we just ignore Shift as we can't select several
+ // items anyhow
+ if ( event.ShiftDown() && !IsSingleSel() )
+ {
+ RefreshRow( oldCurrent );
+
+ ChangeCurrentRow( newCurrent );
+
+ // select all the items between the old and the new one
+ if ( oldCurrent > newCurrent )
+ {
+ newCurrent = oldCurrent;
+ oldCurrent = m_currentRow;
+ }
+
+ SelectRows( oldCurrent, newCurrent, true );
+ if (oldCurrent!=newCurrent)
+ SendSelectionChangedEvent(GetItemByRow(m_selection[0]));
+ }
+ else // !shift
+ {
+ RefreshRow( oldCurrent );
+
+ // all previously selected items are unselected unless ctrl is held
+ if ( !event.ControlDown() )
+ SelectAllRows(false);
+
+ ChangeCurrentRow( newCurrent );
+
+ if ( !event.ControlDown() )
+ {
+ SelectRow( m_currentRow, true );
+ SendSelectionChangedEvent(GetItemByRow(m_currentRow));
+ }
+ else
+ RefreshRow( m_currentRow );
+ }
+
+ GetOwner()->EnsureVisible( m_currentRow, -1 );
+}
+
+wxRect wxDataViewMainWindow::GetLineRect( unsigned int row ) const
+{
+ wxRect rect;
+ rect.x = 0;
+ rect.y = m_lineHeight * row;
+ rect.width = GetEndOfLastCol();
+ rect.height = m_lineHeight;
+
+ return rect;
+}
+
+class RowToItemJob: public DoJob
+{
+public:
+ RowToItemJob( unsigned int row , int current ) { this->row = row; this->current = current ;}
+ virtual ~RowToItemJob(){};
+
+ virtual int operator() ( wxDataViewTreeNode * node )
+ {
+ current ++;
+ if( current == static_cast<int>(row))
+ {
+ ret = node->GetItem() ;
+ return DoJob::OK;
+ }
+
+ if( node->GetSubTreeCount() + current < static_cast<int>(row) )
+ {
+ current += node->GetSubTreeCount();
+ 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<int>(row) - current - 1;
+ ret = node->GetChildren().Item( index );
+ return DoJob::OK;
+ }
+ return DoJob::CONT;
+ }
+ }
+
+ virtual int operator() ( void * n )
+ {
+ current ++;
+ if( current == static_cast<int>(row))
+ {
+ ret = wxDataViewItem( n ) ;
+ return DoJob::OK;
+ }
+ return DoJob::CONT;
+ }
+ wxDataViewItem GetResult(){ return ret; }
+private:
+ unsigned int row;
+ int current ;
+ wxDataViewItem ret;
+};
+
+wxDataViewItem wxDataViewMainWindow::GetItemByRow(unsigned int row) const
+{
+ if (!m_root)
+ {
+ return wxDataViewItem( (void*) row );
+ }
+ else
+ {
+ RowToItemJob job( row, -2 );
+ Walker( m_root , job );
+ return job.GetResult();
+ }
+}
+
+class RowToTreeNodeJob: public DoJob
+{
+public:
+ RowToTreeNodeJob( unsigned int row , int current, wxDataViewTreeNode * node )
+ {
+ this->row = row;
+ this->current = current ;
+ ret = NULL ;
+ parent = node;
+ }
+ virtual ~RowToTreeNodeJob(){};
+
+ virtual int operator() ( wxDataViewTreeNode * node )
+ {
+ current ++;
+ if( current == static_cast<int>(row))
+ {
+ ret = node ;
+ return DoJob::OK;
+ }
+
+ if( node->GetSubTreeCount() + current < static_cast<int>(row) )
+ {
+ current += node->GetSubTreeCount();
+ return DoJob::IGR;
+ }
+ 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<int>(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<int>(row))
+ {
+ ret = new wxDataViewTreeNode( parent ) ;
+ ret->SetItem( wxDataViewItem( n ));
+ ret->SetHasChildren(false);
+ return DoJob::OK;
+ }
+
+ return DoJob::CONT;
+ }
+ wxDataViewTreeNode * GetResult(){ return ret; }
+private:
+ unsigned int row;
+ int current ;
+ wxDataViewTreeNode * ret;
+ wxDataViewTreeNode * parent ;
+};
+
+
+wxDataViewTreeNode * wxDataViewMainWindow::GetTreeNodeByRow(unsigned int row)
+{
+ if (!m_root)
+ {
+ return NULL;
+ }
+ else
+ {
+ RowToTreeNodeJob job( row , -2, m_root );
+ Walker( m_root , job );
+ return job.GetResult();
+ }
+}
+
+wxDataViewEvent wxDataViewMainWindow::SendExpanderEvent( 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);
+ return le;
+}
+
+void wxDataViewMainWindow::OnExpanding( unsigned int row )
+{
+ wxDataViewTreeNode * node = GetTreeNodeByRow(row);
+ if( node != NULL )
+ {
+ if( node->HasChildren())
+ {
+ if( !node->IsOpen())
+ {
+ wxDataViewEvent e = SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING,node->GetItem());
+ //Check if the user prevent expanding
+ if( e.GetSkipped() )
+ return;
+
+ node->ToggleOpen();
+ //Here I build the children of current node
+ if( node->GetChildrenNumber() == 0 )
+ {
+ SortPrepare();
+ BuildTreeHelper(GetOwner()->GetModel(), node->GetItem(), node);
+ }
+ m_count = -1;
+ UpdateDisplay();
+ //Send the expanded event
+ SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED,node->GetItem());
+ }
+ else
+ {
+ SelectRow( row, false );
+ SelectRow( row + 1, true );
+ ChangeCurrentRow( row + 1 );
+ SendSelectionChangedEvent( GetItemByRow(row+1));
+ }
+ }
+ else
+ delete node;
+ }
+}
+
+void wxDataViewMainWindow::OnCollapsing(unsigned int row)
+{
+ wxDataViewTreeNode * node = GetTreeNodeByRow(row);
+ if( node != NULL )
+ {
+ wxDataViewTreeNode * nd = node;
+
+ if( node->HasChildren() && node->IsOpen() )
+ {
+ wxDataViewEvent e = SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING,node->GetItem());
+ if( e.GetSkipped() )
+ return;
+ node->ToggleOpen();
+ m_count = -1;
+ UpdateDisplay();
+ SendExpanderEvent(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED,nd->GetItem());
+ }
+ else
+ {
+ node = node->GetParent();
+ if( node != NULL )
+ {
+ int parent = GetRowByItem( node->GetItem() ) ;
+ if( parent >= 0 )
+ {
+ SelectRow( row, false);
+ SelectRow(parent , true );
+ ChangeCurrentRow( parent );
+ SendSelectionChangedEvent( node->GetItem() );
+ }
+ }
+ }
+ if( !nd->HasChildren())
+ delete nd;
+ }
+}
+
+wxDataViewTreeNode * wxDataViewMainWindow::FindNode( const wxDataViewItem & item )
+{
+ wxDataViewModel * model = GetOwner()->GetModel();
+ if( model == NULL )
+ return NULL;
+
+ //Compose the a parent-chain of the finding item
+ ItemList list;
+ list.DeleteContents( true );
+ wxDataViewItem it( item );
+ while( it.IsOk() )
+ {
+ wxDataViewItem * pItem = new wxDataViewItem( it );
+ list.Insert( pItem );
+ it = model->GetParent( it );
+ }
+
+ //Find the item along the parent-chain.
+ //This algorithm is designed to speed up the node-finding method
+ wxDataViewTreeNode * node = m_root;
+ for( ItemList::const_iterator iter = list.begin(); iter !=list.end() ; iter++ )
+ {
+ if( node->HasChildren() )
+ {
+ if( node->GetChildrenNumber() == 0 )
+ {
+ SortPrepare();
+ BuildTreeHelper(model, node->GetItem(), node);
+ }
+
+ wxDataViewTreeNodes nodes = node->GetNodes();
+ unsigned int i = 0;
+ for (; i < nodes.GetCount(); i ++)
+ {
+ if (nodes[i]->GetItem() == (**iter))
+ {
+ node = nodes[i];
+ break;
+ }
+ }
+ if (i == nodes.GetCount())
+ return NULL;
+ }
+ else
+ return NULL;
+ }
+ return node;
+}
+
+void wxDataViewMainWindow::HitTest( const wxPoint & point, wxDataViewItem & item, wxDataViewColumn* &column )
+{
+ wxDataViewColumn *col = NULL;
+ unsigned int cols = GetOwner()->GetColumnCount();
+ unsigned int colnum = 0;
+ unsigned int x_start = 0;
+ int x, y;
+ m_owner->CalcUnscrolledPosition( point.x, point.y, &x, &y );
+ for (x_start = 0; colnum < cols; colnum++)
+ {
+ col = GetOwner()->GetColumn(colnum);
+ if (col->IsHidden())
+ continue; // skip it!
+
+ unsigned int w = col->GetWidth();
+ if (x_start+w >= (unsigned int)x)
+ break;
+
+ x_start += w;
+ }
+
+ column = col;
+ item = GetItemByRow( y/m_lineHeight );
+}
+
+wxRect wxDataViewMainWindow::GetItemRect( const wxDataViewItem & item, const wxDataViewColumn* column )
+{
+ int row = GetRowByItem(item);
+ int y = row*m_lineHeight;
+ int h = m_lineHeight;
+ int x = 0;
+ wxDataViewColumn *col = NULL;
+ for( int i = 0, cols = GetOwner()->GetColumnCount(); i < cols; i ++ )
+ {
+ col = GetOwner()->GetColumn( i );
+ x += col->GetWidth();
+ if( GetOwner()->GetColumn(i+1) == column )
+ break;
+ }
+ int w = col->GetWidth();
+ m_owner->CalcScrolledPosition( x, y, &x, &y );
+ return wxRect(x, y, w, h);
+}
+
+int wxDataViewMainWindow::RecalculateCount()
+{
+ if (!m_root)
+ {
+ wxDataViewIndexListModel *list_model = (wxDataViewIndexListModel*) GetOwner()->GetModel();
+ return list_model->GetLastIndex();
+ }
+ else
+ {
+ return m_root->GetSubTreeCount();
+ }
+}
+
+class ItemToRowJob : public DoJob
+{
+public:
+ ItemToRowJob(const wxDataViewItem & item, ItemList::const_iterator iter )
+ { this->item = item ; ret = -1 ; m_iter = iter ; }
+ virtual ~ItemToRowJob(){};
+
+ //Maybe binary search will help to speed up this process
+ virtual int operator() ( wxDataViewTreeNode * node)
+ {
+ ret ++;
+ if( node->GetItem() == item )
+ {
+ return DoJob::OK;
+ }
+
+ if( node->GetItem() == **m_iter )
+ {
+ m_iter++ ;
+ return DoJob::CONT;
+ }
+ else
+ {
+ ret += node->GetSubTreeCount();
+ return DoJob::IGR;
+ }
+
+ }
+
+ virtual int operator() ( void * n )
+ {
+ ret ++;
+ if( n == item.GetID() )
+ return DoJob::OK;
+ return DoJob::CONT;
+ }
+ //the row number is begin from zero
+ int GetResult(){ return ret -1 ; }
+private:
+ ItemList::const_iterator m_iter;
+ wxDataViewItem item;
+ int ret;
+
+};
+
+int wxDataViewMainWindow::GetRowByItem(const wxDataViewItem & item)