-/////////////////////////////////////////////////////////////////////////////\r
-// Name: mymodels.cpp\r
-// Purpose: wxDataViewCtrl wxWidgets sample\r
-// Author: Robert Roebling\r
-// Modified by: Francesco Montorsi, Bo Yang\r
-// Created: 06/01/06\r
-// RCS-ID: $Id$\r
-// Copyright: (c) Robert Roebling\r
-// Licence: wxWindows license\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-// For compilers that support precompilation, includes "wx/wx.h".\r
-#include "wx/wxprec.h"\r
-\r
-#ifdef __BORLANDC__\r
-#pragma hdrstop\r
-#endif\r
-\r
-#ifndef WX_PRECOMP\r
- #include "wx/wx.h"\r
-#endif\r
-\r
-#include "wx/dataview.h"\r
-#include "mymodels.h"\r
-\r
-// ----------------------------------------------------------------------------\r
-// resources\r
-// ----------------------------------------------------------------------------\r
-\r
-#include "null.xpm"\r
-#include "wx_small.xpm"\r
-\r
-\r
-// ----------------------------------------------------------------------------\r
-// MyMusicTreeModel\r
-// ----------------------------------------------------------------------------\r
-\r
-MyMusicTreeModel::MyMusicTreeModel()\r
-{\r
- m_root = new MyMusicTreeModelNode( NULL, wxT("My Music" ));\r
-\r
- // setup pop music\r
- m_pop = new MyMusicTreeModelNode( m_root, wxT("Pop music") );\r
- m_pop->Append( \r
- new MyMusicTreeModelNode( m_pop, wxT("You are not alone"), wxT("Michael Jackson"), 1995 ) );\r
- m_pop->Append( \r
- new MyMusicTreeModelNode( m_pop, wxT("Take a bow"), wxT("Madonna"), 1994 ) );\r
- m_root->Append( m_pop );\r
-\r
- // setup classical music\r
- m_classical = new MyMusicTreeModelNode( m_root, wxT("Classical music") );\r
- m_ninth = new MyMusicTreeModelNode( m_classical, wxT("Ninth symphony"), \r
- wxT("Ludwig van Beethoven"), 1824 );\r
- m_classical->Append( m_ninth );\r
- m_classical->Append( new MyMusicTreeModelNode( m_classical, wxT("German Requiem"), \r
- wxT("Johannes Brahms"), 1868 ) );\r
- m_root->Append( m_classical );\r
-\r
- m_classicalMusicIsKnownToControl = false;\r
-}\r
-\r
-wxString MyMusicTreeModel::GetTitle( const wxDataViewItem &item ) const\r
-{\r
- MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();\r
- if (!node) // happens if item.IsOk()==false\r
- return wxEmptyString;\r
-\r
- return node->m_title;\r
-}\r
-\r
-int MyMusicTreeModel::GetYear( const wxDataViewItem &item ) const\r
-{\r
- MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();\r
- if (!node) // happens if item.IsOk()==false\r
- return 2000;\r
-\r
- return node->m_year;\r
-}\r
-\r
-void MyMusicTreeModel::AddToClassical( const wxString &title, const wxString &artist, \r
- unsigned int year )\r
-{\r
- if (!m_classical)\r
- {\r
- wxASSERT(m_root);\r
-\r
- // it was removed: restore it\r
- m_classical = new MyMusicTreeModelNode( m_root, wxT("Classical music") );\r
- m_root->Append( m_classical );\r
- }\r
-\r
- // add to the classical music node a new node:\r
- MyMusicTreeModelNode *child_node =\r
- new MyMusicTreeModelNode( m_classical, title, artist, year );\r
- m_classical->Append( child_node );\r
-\r
- if (m_classicalMusicIsKnownToControl)\r
- {\r
- // notify control\r
- wxDataViewItem child( (void*) child_node );\r
- wxDataViewItem parent( (void*) m_classical );\r
- ItemAdded( parent, child );\r
- }\r
-}\r
-\r
-void MyMusicTreeModel::Delete( const wxDataViewItem &item )\r
-{\r
- MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();\r
- if (!node) // happens if item.IsOk()==false\r
- return;\r
-\r
- wxDataViewItem parent( node->GetParent() );\r
- if (!parent.IsOk())\r
- {\r
- wxASSERT(node == m_root);\r
-\r
- // don't make the control completely empty: \r
- wxLogError("Cannot remove the root item!");\r
- return;\r
- }\r
-\r
- // is the node one of those we keep stored in special pointers?\r
- if (node == m_pop)\r
- m_pop = NULL;\r
- else if (node == m_classical)\r
- m_classical = NULL;\r
- else if (node == m_ninth)\r
- m_ninth = NULL;\r
-\r
- // first remove the node from the parent's array of children;\r
- // NOTE: MyMusicTreeModelNodePtrArray is only an array of _pointers_\r
- // thus removing the node from it doesn't result in freeing it\r
- node->GetParent()->GetChildren().Remove( node );\r
-\r
- // free the node\r
- delete node;\r
-\r
- // notify control\r
- ItemDeleted( parent, item );\r
-}\r
-\r
-int MyMusicTreeModel::Compare( const wxDataViewItem &item1, const wxDataViewItem &item2,\r
- unsigned int column, bool ascending )\r
-{\r
- wxASSERT(item1.IsOk() && item2.IsOk());\r
- // should never happen\r
-\r
- if (IsContainer(item1) && IsContainer(item2))\r
- {\r
- wxVariant value1, value2;\r
- GetValue( value1, item1, 0 );\r
- GetValue( value2, item2, 0 );\r
-\r
- wxString str1 = value1.GetString();\r
- wxString str2 = value2.GetString();\r
- int res = str1.Cmp( str2 );\r
- if (res) return res;\r
-\r
- // items must be different\r
- wxUIntPtr litem1 = (wxUIntPtr) item1.GetID();\r
- wxUIntPtr litem2 = (wxUIntPtr) item2.GetID();\r
-\r
- return litem1-litem2;\r
- }\r
-\r
- return wxDataViewModel::Compare( item1, item2, column, ascending );\r
-}\r
-\r
-void MyMusicTreeModel::GetValue( wxVariant &variant,\r
- const wxDataViewItem &item, unsigned int col ) const\r
-{\r
- wxASSERT(item.IsOk());\r
-\r
- MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();\r
- switch (col)\r
- {\r
- case 0:\r
- variant = node->m_title; \r
- break;\r
- case 1: \r
- variant = node->m_artist; \r
- break;\r
- case 2: \r
- variant = (long) node->m_year; \r
- break;\r
- case 3: \r
- variant = node->m_quality; \r
- break;\r
- case 4:\r
- // wxMac doesn't conceal the popularity progress renderer, return 0 for containers\r
- if (IsContainer(item))\r
- variant = (long) 0;\r
- else\r
- variant = (long) 80; // all music is very 80% popular\r
- break;\r
- case 5:\r
- // Make size of red square depend on year\r
- if (GetYear(item) < 1900)\r
- variant = (long) 35;\r
- else\r
- variant = (long) 25;\r
- break;\r
-\r
- default:\r
- wxLogError( wxT("MyMusicTreeModel::GetValue: wrong column %d"), col );\r
- }\r
-}\r
-\r
-bool MyMusicTreeModel::SetValue( const wxVariant &variant,\r
- const wxDataViewItem &item, unsigned int col )\r
-{\r
- wxASSERT(item.IsOk());\r
-\r
- MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();\r
- switch (col)\r
- {\r
- case 0: \r
- node->m_title = variant.GetString(); \r
- return true;\r
- case 1: \r
- node->m_artist = variant.GetString(); \r
- return true;\r
- case 2: \r
- node->m_year = variant.GetLong(); \r
- return true;\r
- case 3: \r
- node->m_quality = variant.GetString(); \r
- return true;\r
-\r
- default: \r
- wxLogError( wxT("MyMusicTreeModel::SetValue: wrong column") );\r
- }\r
- return false;\r
-}\r
-\r
-wxDataViewItem MyMusicTreeModel::GetParent( const wxDataViewItem &item ) const\r
-{\r
- // the invisible root node has no parent\r
- if (!item.IsOk())\r
- return wxDataViewItem(0);\r
-\r
- MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();\r
-\r
- // "MyMusic" also has no parent\r
- if (node == m_root)\r
- return wxDataViewItem(0);\r
-\r
- return wxDataViewItem( (void*) node->GetParent() );\r
-}\r
-\r
-bool MyMusicTreeModel::IsContainer( const wxDataViewItem &item ) const\r
-{\r
- // the invisble root node can have children\r
- // (in our model always "MyMusic")\r
- if (!item.IsOk())\r
- return true;\r
-\r
- MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();\r
- return node->IsContainer();\r
-}\r
-\r
-unsigned int MyMusicTreeModel::GetChildren( const wxDataViewItem &parent, \r
- wxDataViewItemArray &array ) const\r
-{\r
- MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) parent.GetID();\r
- if (!node)\r
- {\r
- array.Add( wxDataViewItem( (void*) m_root ) );\r
- return 1;\r
- }\r
-\r
- if (node == m_classical)\r
- {\r
- MyMusicTreeModel *model = (MyMusicTreeModel*)(const MyMusicTreeModel*) this;\r
- model->m_classicalMusicIsKnownToControl = true;\r
- }\r
-\r
- if (node->GetChildCount() == 0)\r
- {\r
- return 0;\r
- }\r
-\r
- unsigned int count = node->GetChildren().GetCount();\r
- for (unsigned int pos = 0; pos < count; pos++)\r
- {\r
- MyMusicTreeModelNode *child = node->GetChildren().Item( pos );\r
- array.Add( wxDataViewItem( (void*) child ) );\r
- }\r
-\r
- return count;\r
-}\r
-\r
-\r
-\r
-// ----------------------------------------------------------------------------\r
-// MyListModel\r
-// ----------------------------------------------------------------------------\r
-\r
-static int my_sort_reverse( int *v1, int *v2 )\r
-{\r
- return *v2-*v1;\r
-}\r
-\r
-static int my_sort( int *v1, int *v2 )\r
-{\r
- return *v1-*v2;\r
-}\r
-\r
-#ifdef __WXMAC__\r
- #define INITIAL_NUMBER_OF_ITEMS 100\r
-#else\r
- #define INITIAL_NUMBER_OF_ITEMS 100000\r
-#endif\r
-\r
-MyListModel::MyListModel() :\r
- wxDataViewVirtualListModel( INITIAL_NUMBER_OF_ITEMS )\r
-{\r
- m_virtualItems = INITIAL_NUMBER_OF_ITEMS;\r
-\r
- // the first 100 items are really stored in this model;\r
- // all the others are synthetized on request \r
- for (unsigned int i = 0; i < 100; i++)\r
- {\r
- wxString str;\r
- str.Printf( wxT("real row %d"), i );\r
- m_array.Add( str );\r
- }\r
-\r
- m_icon[0] = wxIcon( null_xpm );\r
- m_icon[1] = wxIcon( wx_small_xpm );\r
-}\r
-\r
-void MyListModel::Prepend( const wxString &text )\r
-{\r
- m_array.Insert( text, 0 );\r
- RowPrepended();\r
-}\r
-\r
-void MyListModel::DeleteItem( const wxDataViewItem &item )\r
-{\r
- unsigned int row = GetRow( item );\r
- if (row >= m_array.GetCount())\r
- return;\r
-\r
- m_array.RemoveAt( row );\r
- RowDeleted( row );\r
-}\r
-\r
-void MyListModel::DeleteItems( const wxDataViewItemArray &items )\r
-{\r
- wxArrayInt rows;\r
- for (unsigned int i = 0; i < items.GetCount(); i++)\r
- {\r
- unsigned int row = GetRow( items[i] );\r
- if (row < m_array.GetCount())\r
- rows.Add( row );\r
- }\r
-\r
- if (rows.GetCount() == 0)\r
- {\r
- // none of the selected items were in the range of the items\r
- // which we store... for simplicity, don't allow removing them\r
- wxLogError("Cannot remove rows with an index greater than %d", m_array.GetCount());\r
- return;\r
- }\r
-\r
- // Sort in descending order so that the last\r
- // row will be deleted first. Otherwise the\r
- // remaining indeces would all be wrong.\r
- rows.Sort( my_sort_reverse );\r
- for (unsigned int i = 0; i < rows.GetCount(); i++)\r
- m_array.RemoveAt( rows[i] );\r
-\r
- // This is just to test if wxDataViewCtrl can\r
- // cope with removing rows not sorted in\r
- // descending order\r
- rows.Sort( my_sort );\r
- RowsDeleted( rows );\r
-}\r
-\r
-void MyListModel::AddMany()\r
-{\r
- m_virtualItems += 1000;\r
- Reset( m_array.GetCount() + m_virtualItems );\r
-}\r
-\r
-void MyListModel::GetValueByRow( wxVariant &variant,\r
- unsigned int row, unsigned int col ) const\r
-{\r
- if (col==0)\r
- {\r
- if (row >= m_array.GetCount())\r
- variant = wxString::Format( wxT("virtual row %d"), row );\r
- else\r
- variant = m_array[ row ];\r
- } \r
- else if (col==1)\r
- {\r
- wxDataViewIconText data( wxT("test"), m_icon[ row%2 ] );\r
- variant << data;\r
- } \r
- else if (col==2)\r
- {\r
- if (row >= m_array.GetCount())\r
- variant = wxT("plain");\r
- else\r
- variant = wxT("blue/green/red");\r
- }\r
-}\r
-\r
-bool MyListModel::GetAttrByRow( unsigned int row, unsigned int col, \r
- wxDataViewItemAttr &attr )\r
-{\r
- if (col != 2)\r
- return false;\r
-\r
- if (row < m_array.GetCount())\r
- {\r
- attr.SetColour( (row%2) == 0 ? *wxBLUE :\r
- ((row%3) == 0 ? *wxGREEN : *wxRED) );\r
- attr.SetItalic( (row%2) == 5 );\r
- }\r
-\r
- return true;\r
-}\r
-\r
-bool MyListModel::SetValueByRow( const wxVariant &variant,\r
- unsigned int row, unsigned int col )\r
-{\r
- if (col == 0)\r
- {\r
- if (row >= m_array.GetCount())\r
- {\r
- // the item is not in the range of the items\r
- // which we store... for simplicity, don't allow editing it\r
- wxLogError("Cannot edit rows with an index greater than %d", m_array.GetCount());\r
- return false;\r
- }\r
-\r
- m_array[row] = variant.GetString();\r
- return true;\r
- }\r
-\r
- return false;\r
-}\r
+/////////////////////////////////////////////////////////////////////////////
+// Name: mymodels.cpp
+// Purpose: wxDataViewCtrl wxWidgets sample
+// Author: Robert Roebling
+// Modified by: Francesco Montorsi, Bo Yang
+// Created: 06/01/06
+// RCS-ID: $Id$
+// Copyright: (c) Robert Roebling
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+
+// For compilers that support precompilation, includes "wx/wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif
+
+#include "wx/dataview.h"
+#include "mymodels.h"
+
+// ----------------------------------------------------------------------------
+// resources
+// ----------------------------------------------------------------------------
+
+#include "null.xpm"
+#include "wx_small.xpm"
+
+
+// ----------------------------------------------------------------------------
+// MyMusicTreeModel
+// ----------------------------------------------------------------------------
+
+MyMusicTreeModel::MyMusicTreeModel()
+{
+ m_root = new MyMusicTreeModelNode( NULL, "My Music" );
+
+ // setup pop music
+ m_pop = new MyMusicTreeModelNode( m_root, "Pop music" );
+ m_pop->Append(
+ new MyMusicTreeModelNode( m_pop, "You are not alone", "Michael Jackson", 1995 ) );
+ m_pop->Append(
+ new MyMusicTreeModelNode( m_pop, "Take a bow", "Madonna", 1994 ) );
+ m_root->Append( m_pop );
+
+ // setup classical music
+ m_classical = new MyMusicTreeModelNode( m_root, "Classical music" );
+ m_ninth = new MyMusicTreeModelNode( m_classical, "Ninth symphony",
+ "Ludwig van Beethoven", 1824 );
+ m_classical->Append( m_ninth );
+ m_classical->Append( new MyMusicTreeModelNode( m_classical, "German Requiem",
+ "Johannes Brahms", 1868 ) );
+ m_root->Append( m_classical );
+
+ m_classicalMusicIsKnownToControl = false;
+}
+
+wxString MyMusicTreeModel::GetTitle( const wxDataViewItem &item ) const
+{
+ MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
+ if (!node) // happens if item.IsOk()==false
+ return wxEmptyString;
+
+ return node->m_title;
+}
+
+wxString MyMusicTreeModel::GetArtist( const wxDataViewItem &item ) const
+{
+ MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
+ if (!node) // happens if item.IsOk()==false
+ return wxEmptyString;
+
+ return node->m_artist;
+}
+
+int MyMusicTreeModel::GetYear( const wxDataViewItem &item ) const
+{
+ MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
+ if (!node) // happens if item.IsOk()==false
+ return 2000;
+
+ return node->m_year;
+}
+
+void MyMusicTreeModel::AddToClassical( const wxString &title, const wxString &artist,
+ unsigned int year )
+{
+ if (!m_classical)
+ {
+ wxASSERT(m_root);
+
+ // it was removed: restore it
+ m_classical = new MyMusicTreeModelNode( m_root, "Classical music" );
+ m_root->Append( m_classical );
+
+ // notify control
+ wxDataViewItem child( (void*) m_classical );
+ wxDataViewItem parent( (void*) m_root );
+ ItemAdded( parent, child );
+ }
+
+ // add to the classical music node a new node:
+ MyMusicTreeModelNode *child_node =
+ new MyMusicTreeModelNode( m_classical, title, artist, year );
+ m_classical->Append( child_node );
+
+ // FIXME: what's m_classicalMusicIsKnownToControl for?
+ if (m_classicalMusicIsKnownToControl)
+ {
+ // notify control
+ wxDataViewItem child( (void*) child_node );
+ wxDataViewItem parent( (void*) m_classical );
+ ItemAdded( parent, child );
+ }
+}
+
+void MyMusicTreeModel::Delete( const wxDataViewItem &item )
+{
+ MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
+ if (!node) // happens if item.IsOk()==false
+ return;
+
+ wxDataViewItem parent( node->GetParent() );
+ if (!parent.IsOk())
+ {
+ wxASSERT(node == m_root);
+
+ // don't make the control completely empty:
+ wxLogError( "Cannot remove the root item!" );
+ return;
+ }
+
+ // is the node one of those we keep stored in special pointers?
+ if (node == m_pop)
+ m_pop = NULL;
+ else if (node == m_classical)
+ m_classical = NULL;
+ else if (node == m_ninth)
+ m_ninth = NULL;
+
+ // first remove the node from the parent's array of children;
+ // NOTE: MyMusicTreeModelNodePtrArray is only an array of _pointers_
+ // thus removing the node from it doesn't result in freeing it
+ node->GetParent()->GetChildren().Remove( node );
+
+ // free the node
+ delete node;
+
+ // notify control
+ ItemDeleted( parent, item );
+}
+
+int MyMusicTreeModel::Compare( const wxDataViewItem &item1, const wxDataViewItem &item2,
+ unsigned int column, bool ascending ) const
+{
+ wxASSERT(item1.IsOk() && item2.IsOk());
+ // should never happen
+
+ if (IsContainer(item1) && IsContainer(item2))
+ {
+ wxVariant value1, value2;
+ GetValue( value1, item1, 0 );
+ GetValue( value2, item2, 0 );
+
+ wxString str1 = value1.GetString();
+ wxString str2 = value2.GetString();
+ int res = str1.Cmp( str2 );
+ if (res) return res;
+
+ // items must be different
+ wxUIntPtr litem1 = (wxUIntPtr) item1.GetID();
+ wxUIntPtr litem2 = (wxUIntPtr) item2.GetID();
+
+ return litem1-litem2;
+ }
+
+ return wxDataViewModel::Compare( item1, item2, column, ascending );
+}
+
+void MyMusicTreeModel::GetValue( wxVariant &variant,
+ const wxDataViewItem &item, unsigned int col ) const
+{
+ wxASSERT(item.IsOk());
+
+ MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
+ switch (col)
+ {
+ case 0:
+ variant = node->m_title;
+ break;
+ case 1:
+ variant = node->m_artist;
+ break;
+ case 2:
+ variant = (long) node->m_year;
+ break;
+ case 3:
+ variant = node->m_quality;
+ break;
+ case 4:
+ variant = 80L; // all music is very 80% popular
+ break;
+ case 5:
+ if (GetYear(item) < 1900)
+ variant = "old";
+ else
+ variant = "new";
+ break;
+
+ default:
+ wxLogError( "MyMusicTreeModel::GetValue: wrong column %d", col );
+ }
+}
+
+bool MyMusicTreeModel::SetValue( const wxVariant &variant,
+ const wxDataViewItem &item, unsigned int col )
+{
+ wxASSERT(item.IsOk());
+
+ MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
+ switch (col)
+ {
+ case 0:
+ node->m_title = variant.GetString();
+ return true;
+ case 1:
+ node->m_artist = variant.GetString();
+ return true;
+ case 2:
+ node->m_year = variant.GetLong();
+ return true;
+ case 3:
+ node->m_quality = variant.GetString();
+ return true;
+
+ default:
+ wxLogError( "MyMusicTreeModel::SetValue: wrong column" );
+ }
+ return false;
+}
+
+bool MyMusicTreeModel::IsEnabled( const wxDataViewItem &item,
+ unsigned int col ) const
+{
+ wxASSERT(item.IsOk());
+
+ MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
+
+ // disable Beethoven's ratings, his pieces can only be good
+ return !(col == 3 && node->m_artist.EndsWith("Beethoven"));
+}
+
+wxDataViewItem MyMusicTreeModel::GetParent( const wxDataViewItem &item ) const
+{
+ // the invisible root node has no parent
+ if (!item.IsOk())
+ return wxDataViewItem(0);
+
+ MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
+
+ // "MyMusic" also has no parent
+ if (node == m_root)
+ return wxDataViewItem(0);
+
+ return wxDataViewItem( (void*) node->GetParent() );
+}
+
+bool MyMusicTreeModel::IsContainer( const wxDataViewItem &item ) const
+{
+ // the invisble root node can have children
+ // (in our model always "MyMusic")
+ if (!item.IsOk())
+ return true;
+
+ MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
+ return node->IsContainer();
+}
+
+unsigned int MyMusicTreeModel::GetChildren( const wxDataViewItem &parent,
+ wxDataViewItemArray &array ) const
+{
+ MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) parent.GetID();
+ if (!node)
+ {
+ array.Add( wxDataViewItem( (void*) m_root ) );
+ return 1;
+ }
+
+ if (node == m_classical)
+ {
+ MyMusicTreeModel *model = (MyMusicTreeModel*)(const MyMusicTreeModel*) this;
+ model->m_classicalMusicIsKnownToControl = true;
+ }
+
+ if (node->GetChildCount() == 0)
+ {
+ return 0;
+ }
+
+ unsigned int count = node->GetChildren().GetCount();
+ for (unsigned int pos = 0; pos < count; pos++)
+ {
+ MyMusicTreeModelNode *child = node->GetChildren().Item( pos );
+ array.Add( wxDataViewItem( (void*) child ) );
+ }
+
+ return count;
+}
+
+
+
+// ----------------------------------------------------------------------------
+// MyListModel
+// ----------------------------------------------------------------------------
+
+static int my_sort_reverse( int *v1, int *v2 )
+{
+ return *v2-*v1;
+}
+
+static int my_sort( int *v1, int *v2 )
+{
+ return *v1-*v2;
+}
+
+#define INITIAL_NUMBER_OF_ITEMS 10000
+
+MyListModel::MyListModel() :
+ wxDataViewVirtualListModel( INITIAL_NUMBER_OF_ITEMS )
+{
+ // the first 100 items are really stored in this model;
+ // all the others are synthesized on request
+ static const unsigned NUMBER_REAL_ITEMS = 100;
+
+ m_textColValues.reserve(NUMBER_REAL_ITEMS);
+ m_textColValues.push_back("first row with long label to test ellipsization");
+ for (unsigned int i = 1; i < NUMBER_REAL_ITEMS; i++)
+ {
+ m_textColValues.push_back(wxString::Format("real row %d", i));
+ }
+
+ m_iconColValues.assign(NUMBER_REAL_ITEMS, "test");
+
+ m_icon[0] = wxIcon( null_xpm );
+ m_icon[1] = wxIcon( wx_small_xpm );
+}
+
+void MyListModel::Prepend( const wxString &text )
+{
+ m_textColValues.Insert( text, 0 );
+ RowPrepended();
+}
+
+void MyListModel::DeleteItem( const wxDataViewItem &item )
+{
+ unsigned int row = GetRow( item );
+
+ if (row >= m_textColValues.GetCount())
+ return;
+
+ m_textColValues.RemoveAt( row );
+ RowDeleted( row );
+}
+
+void MyListModel::DeleteItems( const wxDataViewItemArray &items )
+{
+ unsigned i;
+ wxArrayInt rows;
+ for (i = 0; i < items.GetCount(); i++)
+ {
+ unsigned int row = GetRow( items[i] );
+ if (row < m_textColValues.GetCount())
+ rows.Add( row );
+ }
+
+ if (rows.GetCount() == 0)
+ {
+ // none of the selected items were in the range of the items
+ // which we store... for simplicity, don't allow removing them
+ wxLogError( "Cannot remove rows with an index greater than %d", m_textColValues.GetCount() );
+ return;
+ }
+
+ // Sort in descending order so that the last
+ // row will be deleted first. Otherwise the
+ // remaining indeces would all be wrong.
+ rows.Sort( my_sort_reverse );
+ for (i = 0; i < rows.GetCount(); i++)
+ m_textColValues.RemoveAt( rows[i] );
+
+ // This is just to test if wxDataViewCtrl can
+ // cope with removing rows not sorted in
+ // descending order
+ rows.Sort( my_sort );
+ RowsDeleted( rows );
+}
+
+void MyListModel::AddMany()
+{
+ Reset( GetCount()+1000 );
+}
+
+void MyListModel::GetValueByRow( wxVariant &variant,
+ unsigned int row, unsigned int col ) const
+{
+ switch ( col )
+ {
+ case Col_EditableText:
+ if (row >= m_textColValues.GetCount())
+ variant = wxString::Format( "virtual row %d", row );
+ else
+ variant = m_textColValues[ row ];
+ break;
+
+ case Col_IconText:
+ {
+ wxString text;
+ if ( row >= m_iconColValues.GetCount() )
+ text = "virtual icon";
+ else
+ text = m_iconColValues[row];
+
+ variant << wxDataViewIconText(text, m_icon[row % 2]);
+ }
+ break;
+
+ case Col_TextWithAttr:
+ {
+ static const char *labels[5] =
+ {
+ "blue", "green", "red", "bold cyan", "default",
+ };
+
+ variant = labels[row % 5];
+ }
+ break;
+
+ case Col_Custom:
+ variant = wxString::Format("%d", row % 100);
+ break;
+
+ case Col_Max:
+ wxFAIL_MSG( "invalid column" );
+ }
+}
+
+bool MyListModel::GetAttrByRow( unsigned int row, unsigned int col,
+ wxDataViewItemAttr &attr ) const
+{
+ switch ( col )
+ {
+ case Col_EditableText:
+ return false;
+
+ case Col_IconText:
+ if ( !(row % 2) )
+ return false;
+ attr.SetColour(*wxLIGHT_GREY);
+ break;
+
+ case Col_TextWithAttr:
+ case Col_Custom:
+ // do what the labels defined in GetValueByRow() hint at
+ switch ( row % 5 )
+ {
+ case 0:
+ attr.SetColour(*wxBLUE);
+ break;
+
+ case 1:
+ attr.SetColour(*wxGREEN);
+ break;
+
+ case 2:
+ attr.SetColour(*wxRED);
+ break;
+
+ case 3:
+ attr.SetColour(*wxCYAN);
+ attr.SetBold(true);
+ break;
+
+ case 4:
+ return false;
+ }
+ break;
+
+ case Col_Max:
+ wxFAIL_MSG( "invalid column" );
+ }
+
+ return true;
+}
+
+bool MyListModel::SetValueByRow( const wxVariant &variant,
+ unsigned int row, unsigned int col )
+{
+ switch ( col )
+ {
+ case Col_EditableText:
+ case Col_IconText:
+ if (row >= m_textColValues.GetCount())
+ {
+ // the item is not in the range of the items
+ // which we store... for simplicity, don't allow editing it
+ wxLogError( "Cannot edit rows with an index greater than %d",
+ m_textColValues.GetCount() );
+ return false;
+ }
+
+ if ( col == Col_EditableText )
+ {
+ m_textColValues[row] = variant.GetString();
+ }
+ else // col == Col_IconText
+ {
+ wxDataViewIconText iconText;
+ iconText << variant;
+ m_iconColValues[row] = iconText.GetText();
+ }
+ return true;
+
+ case Col_TextWithAttr:
+ case Col_Custom:
+ wxLogError("Cannot edit the column %d", col);
+ break;
+
+ case Col_Max:
+ wxFAIL_MSG( "invalid column" );
+ }
+
+ return false;
+}
+
+
+// ----------------------------------------------------------------------------
+// MyListStoreDerivedModel
+// ----------------------------------------------------------------------------
+
+bool MyListStoreDerivedModel::IsEnabledByRow(unsigned int row, unsigned int col) const
+{
+ // disabled the last two checkboxes
+ return !(col == 0 && 8 <= row && row <= 9);
+}