X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/bf19b714f0efa3f49333746e03f320681924c9e6..f155075229d771430f0793700f5048ad4be00e9d:/samples/dataview/mymodels.cpp?ds=sidebyside

diff --git a/samples/dataview/mymodels.cpp b/samples/dataview/mymodels.cpp
index 75d687bdf1..a3cb111198 100644
--- a/samples/dataview/mymodels.cpp
+++ b/samples/dataview/mymodels.cpp
@@ -1,382 +1,549 @@
-/////////////////////////////////////////////////////////////////////////////
-// 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 license
-/////////////////////////////////////////////////////////////////////////////
-
-
-// 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"
-
-
-// ----------------------------------------------------------------------------
-// MyMusicTreeModel
-// ----------------------------------------------------------------------------
-
-MyMusicTreeModel::MyMusicTreeModel()
-{
-    m_root = new MyMusicTreeModelNode( NULL, wxT("My Music" ));
-    m_pop = new MyMusicTreeModelNode( m_root, wxT("Pop music") );
-    m_root->Append( m_pop );
-    m_pop->Append( new MyMusicTreeModelNode( m_pop,
-        wxT("You are not alone"), wxT("Michael Jackson"), 1995 ) );
-    m_pop->Append( new MyMusicTreeModelNode( m_pop,
-        wxT("Take a bow"), wxT("Madonna"), 1994 ) );
-    m_classical = new MyMusicTreeModelNode( m_root, wxT("Classical music") );
-    m_root->Append( m_classical );
-    m_ninth = new MyMusicTreeModelNode( m_classical,
-        wxT("Ninth symphony"), wxT("Ludwig van Beethoven"), 1824 );
-    m_classical->Append( m_ninth );
-    m_classical->Append( new MyMusicTreeModelNode( m_classical,
-        wxT("German Requiem"), wxT("Johannes Brahms"), 1868 ) );
-    m_classicalMusicIsKnownToControl = false;
-}
-
-wxString MyMusicTreeModel::GetTitle( const wxDataViewItem &item ) const
-{
-    MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
-    if (!node)
-        return wxEmptyString;
-
-    return node->m_title;
-}
-
-int MyMusicTreeModel::GetYear( const wxDataViewItem &item ) const
-{
-    MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
-    if (!node)
-        return 2000;
-
-    return node->m_year;
-}
-
-void MyMusicTreeModel::AddToClassical( const wxString &title, const wxString &artist, int year )
-{
-    // add to data
-    MyMusicTreeModelNode *child_node =
-        new MyMusicTreeModelNode( m_classical, title, artist, year );
-
-    m_classical->Append( child_node );
-
-    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();
-    wxDataViewItem parent( node->GetParent() );
-
-    node->GetParent()->GetChildren().Remove( node );
-    delete node;
-
-    // notify control
-    ItemDeleted( parent, item );
-}
-
-int MyMusicTreeModel::Compare( const wxDataViewItem &item1, const wxDataViewItem &item2,
-                               unsigned int column, bool ascending )
-{
-    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
-{
-    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:
-            // wxMac doesn't conceal the popularity progress renderer, return 0 for containers
-            if (IsContainer(item))
-                variant = (long) 0;
-            else
-                variant = (long) 80;  // all music is very 80% popular
-            break;
-        case 5:
-            // Make size of red square depend on year
-            if (GetYear(item) < 1900)
-                variant = (long) 35;
-            else
-                variant = (long) 25;
-            break;
-        default:
-        {
-            wxLogError( wxT("MyMusicTreeModel::GetValue: wrong column %d"), col );
-
-            // provoke a crash when mouse button down
-            wxMouseState state = wxGetMouseState();
-            if (state.ShiftDown())
-            {
-                char *crash = 0;
-                *crash = 0;
-            }
-        }
-    }
-}
-
-bool MyMusicTreeModel::SetValue( const wxVariant &variant,
-                                 const wxDataViewItem &item, unsigned int col )
-{
-    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( wxT("MyMusicTreeModel::SetValue: wrong column") );
-    }
-    return false;
-}
-
-wxDataViewItem MyMusicTreeModel::GetParent( const wxDataViewItem &item ) const
-{
-    // the invisble 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();
-    unsigned int pos;
-    for (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;
-}
-
-MyListModel::MyListModel() :
-#ifdef __WXMAC__
-        wxDataViewVirtualListModel( 1000 + 100 )
-#else
-        wxDataViewVirtualListModel( 100000 + 100 )
-#endif
-{
-#ifdef __WXMAC__
-    m_virtualItems = 1000;
-#else
-    m_virtualItems = 100000;
-#endif
-
-    unsigned int i;
-    for (i = 0; i < 100; i++)
-    {
-        wxString str;
-        str.Printf( wxT("row number %d"), i );
-        m_array.Add( str );
-    }
-
-    m_icon = wxIcon( null_xpm );
-}
-
-void MyListModel::Prepend( const wxString &text )
-{
-    m_array.Insert( text, 0 );
-    RowPrepended();
-}
-
-void MyListModel::DeleteItem( const wxDataViewItem &item )
-{
-    unsigned int row = GetRow( item );
-    if (row >= m_array.GetCount())
-        return;
-
-    m_array.RemoveAt( row );
-    RowDeleted( row );
-}
-
-void MyListModel::DeleteItems( const wxDataViewItemArray &items )
-{
-    wxArrayInt rows;
-    unsigned int i;
-    for (i = 0; i < items.GetCount(); i++)
-    {
-        unsigned int row = GetRow( items[i] );
-        if (row < m_array.GetCount())
-            rows.Add( row );
-    }
-
-    // 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_array.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()
-{
-    m_virtualItems += 1000;
-    Reset( m_array.GetCount() + m_virtualItems );
-}
-
-void MyListModel::GetValueByRow( wxVariant &variant,
-                                 unsigned int row, unsigned int col ) const
-{
-    if (col==0)
-    {
-        if (row >= m_array.GetCount())
-        {
-            wxString str;
-            str.Printf(wxT("row %d"), row - m_array.GetCount() );
-            variant = str;
-        }
-        else
-        {
-            variant = m_array[ row ];
-        }
-    } else
-    if (col==1)
-    {
-        wxDataViewIconText data( wxT("test"), m_icon );
-        variant << data;
-    } else
-    if (col==2)
-    {
-        if (row >= m_array.GetCount())
-            variant = wxT("plain");
-        else
-            variant = wxT("blue");
-    }
-}
-
-bool MyListModel::GetAttrByRow( unsigned int row, unsigned int col, wxDataViewItemAttr &attr )
-{
-    if (col != 2)
-        return false;
-
-    if (row < m_array.GetCount())
-    {
-        attr.SetColour( *wxBLUE );
-        attr.SetItalic( true );
-    }
-
-    return true;
-}
-
-bool MyListModel::SetValueByRow( const wxVariant &variant,
-                                 unsigned int row, unsigned int col )
-{
-    if (col == 0)
-    {
-        if (row >= m_array.GetCount())
-            return false;
-
-        m_array[row] = variant.GetString();
-        return true;
-    }
-
-    return false;
-}
+/////////////////////////////////////////////////////////////////////////////
+// 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);
+}