+ 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();
+#ifndef __WXMAC__
+ return list_model->GetLastIndex() + 1;
+#else
+ return list_model->GetLastIndex() - 1;
+#endif
+ }
+ 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)
+{
+ wxDataViewModel * model = GetOwner()->GetModel();
+ if( model == NULL )
+ return -1;
+
+ if (!m_root)
+ {
+ return wxPtrToUInt( item.GetID() );
+ }
+ else
+ {
+ 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() )
+ {
+ pItem = new wxDataViewItem( it );
+ list.Insert( pItem );
+ it = model->GetParent( it );
+ }
+ pItem = new wxDataViewItem( );
+ list.Insert( pItem );
+
+ ItemToRowJob job( item, list.begin() );
+ Walker(m_root , job );
+ return job.GetResult();
+ }
+}
+
+void BuildTreeHelper( wxDataViewModel * model, wxDataViewItem & item, wxDataViewTreeNode * node)
+{
+ if( !model->IsContainer( item ) )
+ return ;
+
+ wxDataViewItemArray children;
+ unsigned int num = model->GetChildren( item, children);
+ unsigned int index = 0;
+ while( index < num )
+ {
+ if( model->IsContainer( children[index] ) )
+ {
+ wxDataViewTreeNode * n = new wxDataViewTreeNode( node );
+ n->SetItem(children[index]);
+ n->SetHasChildren( true ) ;
+ node->AddNode( n );
+ }
+ else
+ {
+ node->AddLeaf( children[index].GetID() );
+ }
+ index ++;
+ }
+ node->SetSubTreeCount( num );
+ wxDataViewTreeNode * n = node->GetParent();
+ if( n != NULL)
+ n->ChangeSubTreeCount(num);
+
+}
+
+void wxDataViewMainWindow::BuildTree(wxDataViewModel * model)
+{
+ DestroyTree();
+
+ if (GetOwner()->GetModel()->IsIndexListModel())
+ {
+ m_count = -1 ;
+ return;
+ }
+
+ m_root = new wxDataViewTreeNode( NULL );
+ m_root->SetHasChildren(true);
+
+ //First we define a invalid item to fetch the top-level elements
+ wxDataViewItem item;
+ SortPrepare();
+ BuildTreeHelper( model, item, m_root);
+ m_count = -1 ;
+}
+
+void DestroyTreeHelper( wxDataViewTreeNode * node )
+{
+ if( node->GetNodeNumber() != 0 )
+ {
+ int len = node->GetNodeNumber();
+ int i = 0 ;
+ wxDataViewTreeNodes nodes = node->GetNodes();
+ for( ; i < len; i ++ )
+ {
+ DestroyTreeHelper(nodes[i]);
+ }
+ }
+ delete node;
+}
+
+void wxDataViewMainWindow::DestroyTree()
+{
+ if (m_root)
+ {
+ DestroyTreeHelper(m_root);
+ m_count = 0;
+ m_root = NULL;
+ }
+}
+
+void wxDataViewMainWindow::OnChar( wxKeyEvent &event )
+{
+ if (event.GetKeyCode() == WXK_TAB)
+ {
+ wxNavigationKeyEvent nevent;
+ nevent.SetWindowChange( event.ControlDown() );
+ nevent.SetDirection( !event.ShiftDown() );
+ nevent.SetEventObject( GetParent()->GetParent() );
+ nevent.SetCurrentFocus( m_parent );
+ if (GetParent()->GetParent()->GetEventHandler()->ProcessEvent( nevent ))
+ return;
+ }
+
+ // no item -> nothing to do
+ if (!HasCurrentRow())
+ {
+ event.Skip();
+ return;
+ }
+
+ // don't use m_linesPerPage directly as it might not be computed yet
+ const int pageSize = GetCountPerPage();
+ wxCHECK_RET( pageSize, _T("should have non zero page size") );
+
+ switch ( event.GetKeyCode() )
+ {
+ case WXK_RETURN:
+ {
+ if (m_currentRow > 0)
+ {
+ wxWindow *parent = GetParent();
+ wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED, parent->GetId());
+ le.SetItem( GetItemByRow(m_currentRow) );
+ le.SetEventObject(parent);
+ le.SetModel(GetOwner()->GetModel());
+
+ parent->GetEventHandler()->ProcessEvent(le);
+ }
+ break;
+ }
+ case WXK_UP:
+ if ( m_currentRow > 0 )
+ OnArrowChar( m_currentRow - 1, event );
+ break;
+
+ case WXK_DOWN:
+ 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;