+ GetOwner()->CalcScrolledPosition( labelRect.x, labelRect.y,
+ &labelRect.x, &labelRect.y);
+
+ wxDataViewItem item = GetItemByRow( m_currentRow );
+ m_currentCol->GetRenderer()->StartEditing( item, labelRect );
+
+}
+
+//------------------------------------------------------------------
+// Helper class for do operation on the tree node
+//------------------------------------------------------------------
+class DoJob
+{
+public:
+ DoJob(){};
+ virtual ~DoJob(){};
+
+ //The return value control how the tree-walker tranverse the tree
+ // 0: Job done, stop tranverse and return
+ // 1: Ignore the current node's subtree and continue
+ // 2: Job not done, continue
+ enum { OK = 0 , IGR = 1, CONT = 2 };
+ virtual int operator() ( wxDataViewTreeNode * node ) = 0 ;
+ virtual int operator() ( void * n ) = 0;
+};
+
+bool Walker( wxDataViewTreeNode * node, DoJob & func )
+{
+ if( node==NULL )
+ 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];
+ if( nodes_i < len_nodes && n == nodes[nodes_i]->GetItem().GetID() )
+ {
+ wxDataViewTreeNode * nd = nodes[nodes_i];
+ nodes_i++;
+
+ if( Walker( nd , func ) )
+ return true;
+
+ }
+ else
+ switch( func( n ) )
+ {
+ case DoJob::OK :
+ return true ;
+ case DoJob::IGR:
+ continue;
+ case DoJob::CONT:
+ default:
+ ;
+ }
+ }
+ return false;
+}
+
+bool wxDataViewMainWindow::ItemAdded(const wxDataViewItem & parent, const wxDataViewItem & item)
+{
+ if (!m_root)
+ {
+ m_count++;
+ UpdateDisplay();
+ return true;
+ }
+
+ SortPrepare();
+
+ wxDataViewTreeNode * node;
+ node = FindNode(parent);
+
+ if( node == NULL )
+ return false;
+
+ node->SetHasChildren( true );
+
+ if( g_model->IsContainer( item ) )
+ {
+ wxDataViewTreeNode * newnode = new wxDataViewTreeNode( node );
+ newnode->SetItem(item);
+ newnode->SetHasChildren( true );
+ node->AddNode( newnode);
+ }
+ else
+ node->AddLeaf( item.GetID() );
+
+ node->ChangeSubTreeCount(1);
+
+ m_count = -1;
+ UpdateDisplay();
+
+ return true;
+}
+
+static void DestroyTreeHelper( wxDataViewTreeNode * node);
+
+bool wxDataViewMainWindow::ItemDeleted(const wxDataViewItem& parent,
+ const wxDataViewItem& item)
+{
+ if (!m_root)
+ {
+ m_count--;
+ if( m_currentRow > GetRowCount() )
+ m_currentRow = m_count - 1;
+
+ m_selection.Empty();
+
+ UpdateDisplay();
+
+ return true;
+ }
+
+ wxDataViewTreeNode * node = FindNode(parent);
+
+ wxCHECK_MSG( node != NULL, false, "item not found" );
+ wxCHECK_MSG( node->GetChildren().Index( item.GetID() ) != wxNOT_FOUND, false, "item not found" );
+
+ int sub = -1;
+ node->GetChildren().Remove( item.GetID() );
+ //Manuplate selection
+ if( m_selection.GetCount() > 1 )
+ {
+ m_selection.Empty();
+ }
+ bool isContainer = false;
+ wxDataViewTreeNodes nds = node->GetNodes();
+ for (size_t i = 0; i < nds.GetCount(); i ++)
+ {
+ if (nds[i]->GetItem() == item)
+ {
+ isContainer = true;
+ break;
+ }
+ }
+ if( isContainer )
+ {
+ wxDataViewTreeNode * n = NULL;
+ wxDataViewTreeNodes nodes = node->GetNodes();
+ int len = nodes.GetCount();
+ for( int i = 0 ; i < len; i ++)
+ {
+ if( nodes[i]->GetItem() == item )
+ {
+ n = nodes[i];
+ break;
+ }
+ }
+
+ wxCHECK_MSG( n != NULL, false, "item not found" );
+
+ node->GetNodes().Remove( n );
+ sub -= n->GetSubTreeCount();
+ ::DestroyTreeHelper(n);
+ }
+ //Make the row number invalid and get a new valid one when user call GetRowCount
+ m_count = -1;
+ node->ChangeSubTreeCount(sub);
+
+ //Change the current row to the last row if the current exceed the max row number
+ if( m_currentRow > GetRowCount() )
+ m_currentRow = m_count - 1;
+
+ UpdateDisplay();
+
+ return true;
+}
+
+bool wxDataViewMainWindow::ItemChanged(const wxDataViewItem & item)
+{
+ SortPrepare();
+ g_model->Resort();
+
+ //Send event
+ wxWindow *parent = GetParent();
+ wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED, parent->GetId());
+ le.SetEventObject(parent);
+ le.SetModel(GetOwner()->GetModel());
+ le.SetItem(item);
+ parent->GetEventHandler()->ProcessEvent(le);
+
+ return true;
+}
+
+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
+
+ wxRect rect( 0, row*m_lineHeight, MAX_VIRTUAL_WIDTH, m_lineHeight );
+ m_owner->CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y );
+ Refresh( true, &rect );
+
+ return true;
+*/
+ SortPrepare();
+ g_model->Resort();
+
+ //Send event
+ wxWindow *parent = GetParent();
+ wxDataViewEvent le(wxEVT_COMMAND_DATAVIEW_ITEM_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);
+
+ return true;
+}
+
+bool wxDataViewMainWindow::Cleared()
+{
+ DestroyTree();
+
+ SortPrepare();
+ BuildTree( GetOwner()->GetModel() );
+
+ UpdateDisplay();
+
+ return true;
+}
+
+void wxDataViewMainWindow::UpdateDisplay()
+{
+ m_dirty = true;
+}
+
+void wxDataViewMainWindow::OnInternalIdle()
+{
+ wxWindow::OnInternalIdle();
+
+ if (m_dirty)
+ {
+ RecalculateDisplay();
+ m_dirty = false;
+ }
+}
+
+void wxDataViewMainWindow::RecalculateDisplay()
+{
+ wxDataViewModel *model = GetOwner()->GetModel();
+ if (!model)
+ {
+ Refresh();
+ return;
+ }
+
+ int width = GetEndOfLastCol();
+ int height = GetLineStart( GetRowCount() );
+
+ SetVirtualSize( width, height );
+ GetOwner()->SetScrollRate( 10, m_lineHeight );
+
+ Refresh();
+}
+
+void wxDataViewMainWindow::ScrollWindow( int dx, int dy, const wxRect *rect )
+{
+ wxWindow::ScrollWindow( dx, dy, rect );
+
+ if (GetOwner()->m_headerArea)
+ GetOwner()->m_headerArea->ScrollWindow( dx, 0 );
+}
+
+void wxDataViewMainWindow::ScrollTo( int rows, int column )
+{
+ int x, y;
+ m_owner->GetScrollPixelsPerUnit( &x, &y );
+ int sy = GetLineStart( rows )/y;
+ int sx = 0;
+ if( column != -1 )
+ {
+ wxRect rect = GetClientRect();
+ int colnum = 0;
+ int x_start = 0, x_end = 0, w = 0;
+ int xx, yy, xe;
+ m_owner->CalcUnscrolledPosition( rect.x, rect.y, &xx, &yy );
+ for (x_start = 0; colnum < column; colnum++)
+ {
+ wxDataViewColumn *col = GetOwner()->GetColumn(colnum);
+ if (col->IsHidden())
+ continue; // skip it!
+
+ w = col->GetWidth();
+ x_start += w;
+ }
+
+ x_end = x_start + w;
+ xe = xx + rect.width;
+ if( x_end > xe )
+ {
+ sx = ( xx + x_end - xe )/x;
+ }
+ if( x_start < xx )
+ {
+ sx = x_start/x;
+ }
+ }
+ m_owner->Scroll( sx, sy );
+}
+
+int wxDataViewMainWindow::GetCountPerPage() const
+{
+ wxSize size = GetClientSize();
+ return size.y / m_lineHeight;
+}
+
+int wxDataViewMainWindow::GetEndOfLastCol() const
+{
+ int width = 0;
+ unsigned int i;
+ for (i = 0; i < GetOwner()->GetColumnCount(); i++)
+ {
+ const wxDataViewColumn *c =
+ wx_const_cast(wxDataViewCtrl*, GetOwner())->GetColumn( i );
+
+ if (!c->IsHidden())
+ width += c->GetWidth();
+ }
+ return width;
+}
+
+unsigned int wxDataViewMainWindow::GetFirstVisibleRow() const
+{