1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxDataViewCtrl wxWidgets sample
4 // Author: Robert Roebling
5 // Modified by: Francesco Montorsi, Bo Yang
7 // Copyright: (c) Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
23 #include "wx/dataview.h"
26 // ----------------------------------------------------------------------------
28 // ----------------------------------------------------------------------------
31 #include "wx_small.xpm"
34 // ----------------------------------------------------------------------------
36 // ----------------------------------------------------------------------------
38 MyMusicTreeModel::MyMusicTreeModel()
40 m_root
= new MyMusicTreeModelNode( NULL
, "My Music" );
43 m_pop
= new MyMusicTreeModelNode( m_root
, "Pop music" );
45 new MyMusicTreeModelNode( m_pop
, "You are not alone", "Michael Jackson", 1995 ) );
47 new MyMusicTreeModelNode( m_pop
, "Take a bow", "Madonna", 1994 ) );
48 m_root
->Append( m_pop
);
50 // setup classical music
51 m_classical
= new MyMusicTreeModelNode( m_root
, "Classical music" );
52 m_ninth
= new MyMusicTreeModelNode( m_classical
, "Ninth symphony",
53 "Ludwig van Beethoven", 1824 );
54 m_classical
->Append( m_ninth
);
55 m_classical
->Append( new MyMusicTreeModelNode( m_classical
, "German Requiem",
56 "Johannes Brahms", 1868 ) );
57 m_root
->Append( m_classical
);
59 m_classicalMusicIsKnownToControl
= false;
62 wxString
MyMusicTreeModel::GetTitle( const wxDataViewItem
&item
) const
64 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
65 if (!node
) // happens if item.IsOk()==false
71 wxString
MyMusicTreeModel::GetArtist( const wxDataViewItem
&item
) const
73 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
74 if (!node
) // happens if item.IsOk()==false
77 return node
->m_artist
;
80 int MyMusicTreeModel::GetYear( const wxDataViewItem
&item
) const
82 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
83 if (!node
) // happens if item.IsOk()==false
89 void MyMusicTreeModel::AddToClassical( const wxString
&title
, const wxString
&artist
,
96 // it was removed: restore it
97 m_classical
= new MyMusicTreeModelNode( m_root
, "Classical music" );
98 m_root
->Append( m_classical
);
101 wxDataViewItem
child( (void*) m_classical
);
102 wxDataViewItem
parent( (void*) m_root
);
103 ItemAdded( parent
, child
);
106 // add to the classical music node a new node:
107 MyMusicTreeModelNode
*child_node
=
108 new MyMusicTreeModelNode( m_classical
, title
, artist
, year
);
109 m_classical
->Append( child_node
);
111 // FIXME: what's m_classicalMusicIsKnownToControl for?
112 if (m_classicalMusicIsKnownToControl
)
115 wxDataViewItem
child( (void*) child_node
);
116 wxDataViewItem
parent( (void*) m_classical
);
117 ItemAdded( parent
, child
);
121 void MyMusicTreeModel::Delete( const wxDataViewItem
&item
)
123 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
124 if (!node
) // happens if item.IsOk()==false
127 wxDataViewItem
parent( node
->GetParent() );
130 wxASSERT(node
== m_root
);
132 // don't make the control completely empty:
133 wxLogError( "Cannot remove the root item!" );
137 // is the node one of those we keep stored in special pointers?
140 else if (node
== m_classical
)
142 else if (node
== m_ninth
)
145 // first remove the node from the parent's array of children;
146 // NOTE: MyMusicTreeModelNodePtrArray is only an array of _pointers_
147 // thus removing the node from it doesn't result in freeing it
148 node
->GetParent()->GetChildren().Remove( node
);
154 ItemDeleted( parent
, item
);
157 int MyMusicTreeModel::Compare( const wxDataViewItem
&item1
, const wxDataViewItem
&item2
,
158 unsigned int column
, bool ascending
) const
160 wxASSERT(item1
.IsOk() && item2
.IsOk());
161 // should never happen
163 if (IsContainer(item1
) && IsContainer(item2
))
165 wxVariant value1
, value2
;
166 GetValue( value1
, item1
, 0 );
167 GetValue( value2
, item2
, 0 );
169 wxString str1
= value1
.GetString();
170 wxString str2
= value2
.GetString();
171 int res
= str1
.Cmp( str2
);
174 // items must be different
175 wxUIntPtr litem1
= (wxUIntPtr
) item1
.GetID();
176 wxUIntPtr litem2
= (wxUIntPtr
) item2
.GetID();
178 return litem1
-litem2
;
181 return wxDataViewModel::Compare( item1
, item2
, column
, ascending
);
184 void MyMusicTreeModel::GetValue( wxVariant
&variant
,
185 const wxDataViewItem
&item
, unsigned int col
) const
187 wxASSERT(item
.IsOk());
189 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
193 variant
= node
->m_title
;
196 variant
= node
->m_artist
;
199 variant
= (long) node
->m_year
;
202 variant
= node
->m_quality
;
205 variant
= 80L; // all music is very 80% popular
208 if (GetYear(item
) < 1900)
215 wxLogError( "MyMusicTreeModel::GetValue: wrong column %d", col
);
219 bool MyMusicTreeModel::SetValue( const wxVariant
&variant
,
220 const wxDataViewItem
&item
, unsigned int col
)
222 wxASSERT(item
.IsOk());
224 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
228 node
->m_title
= variant
.GetString();
231 node
->m_artist
= variant
.GetString();
234 node
->m_year
= variant
.GetLong();
237 node
->m_quality
= variant
.GetString();
241 wxLogError( "MyMusicTreeModel::SetValue: wrong column" );
246 bool MyMusicTreeModel::IsEnabled( const wxDataViewItem
&item
,
247 unsigned int col
) const
249 wxASSERT(item
.IsOk());
251 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
253 // disable Beethoven's ratings, his pieces can only be good
254 return !(col
== 3 && node
->m_artist
.EndsWith("Beethoven"));
257 wxDataViewItem
MyMusicTreeModel::GetParent( const wxDataViewItem
&item
) const
259 // the invisible root node has no parent
261 return wxDataViewItem(0);
263 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
265 // "MyMusic" also has no parent
267 return wxDataViewItem(0);
269 return wxDataViewItem( (void*) node
->GetParent() );
272 bool MyMusicTreeModel::IsContainer( const wxDataViewItem
&item
) const
274 // the invisble root node can have children
275 // (in our model always "MyMusic")
279 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
280 return node
->IsContainer();
283 unsigned int MyMusicTreeModel::GetChildren( const wxDataViewItem
&parent
,
284 wxDataViewItemArray
&array
) const
286 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) parent
.GetID();
289 array
.Add( wxDataViewItem( (void*) m_root
) );
293 if (node
== m_classical
)
295 MyMusicTreeModel
*model
= (MyMusicTreeModel
*)(const MyMusicTreeModel
*) this;
296 model
->m_classicalMusicIsKnownToControl
= true;
299 if (node
->GetChildCount() == 0)
304 unsigned int count
= node
->GetChildren().GetCount();
305 for (unsigned int pos
= 0; pos
< count
; pos
++)
307 MyMusicTreeModelNode
*child
= node
->GetChildren().Item( pos
);
308 array
.Add( wxDataViewItem( (void*) child
) );
316 // ----------------------------------------------------------------------------
318 // ----------------------------------------------------------------------------
320 static int my_sort_reverse( int *v1
, int *v2
)
325 static int my_sort( int *v1
, int *v2
)
330 #define INITIAL_NUMBER_OF_ITEMS 10000
332 MyListModel::MyListModel() :
333 wxDataViewVirtualListModel( INITIAL_NUMBER_OF_ITEMS
)
335 // the first 100 items are really stored in this model;
336 // all the others are synthesized on request
337 static const unsigned NUMBER_REAL_ITEMS
= 100;
339 m_textColValues
.reserve(NUMBER_REAL_ITEMS
);
340 m_textColValues
.push_back("first row with long label to test ellipsization");
341 for (unsigned int i
= 1; i
< NUMBER_REAL_ITEMS
; i
++)
343 m_textColValues
.push_back(wxString::Format("real row %d", i
));
346 m_iconColValues
.assign(NUMBER_REAL_ITEMS
, "test");
348 m_icon
[0] = wxIcon( null_xpm
);
349 m_icon
[1] = wxIcon( wx_small_xpm
);
352 void MyListModel::Prepend( const wxString
&text
)
354 m_textColValues
.Insert( text
, 0 );
358 void MyListModel::DeleteItem( const wxDataViewItem
&item
)
360 unsigned int row
= GetRow( item
);
362 if (row
>= m_textColValues
.GetCount())
365 m_textColValues
.RemoveAt( row
);
369 void MyListModel::DeleteItems( const wxDataViewItemArray
&items
)
373 for (i
= 0; i
< items
.GetCount(); i
++)
375 unsigned int row
= GetRow( items
[i
] );
376 if (row
< m_textColValues
.GetCount())
380 if (rows
.GetCount() == 0)
382 // none of the selected items were in the range of the items
383 // which we store... for simplicity, don't allow removing them
384 wxLogError( "Cannot remove rows with an index greater than %d", m_textColValues
.GetCount() );
388 // Sort in descending order so that the last
389 // row will be deleted first. Otherwise the
390 // remaining indeces would all be wrong.
391 rows
.Sort( my_sort_reverse
);
392 for (i
= 0; i
< rows
.GetCount(); i
++)
393 m_textColValues
.RemoveAt( rows
[i
] );
395 // This is just to test if wxDataViewCtrl can
396 // cope with removing rows not sorted in
398 rows
.Sort( my_sort
);
402 void MyListModel::AddMany()
404 Reset( GetCount()+1000 );
407 void MyListModel::GetValueByRow( wxVariant
&variant
,
408 unsigned int row
, unsigned int col
) const
412 case Col_EditableText
:
413 if (row
>= m_textColValues
.GetCount())
414 variant
= wxString::Format( "virtual row %d", row
);
416 variant
= m_textColValues
[ row
];
422 if ( row
>= m_iconColValues
.GetCount() )
423 text
= "virtual icon";
425 text
= m_iconColValues
[row
];
427 variant
<< wxDataViewIconText(text
, m_icon
[row
% 2]);
431 case Col_TextWithAttr
:
433 static const char *labels
[5] =
435 "blue", "green", "red", "bold cyan", "default",
438 variant
= labels
[row
% 5];
443 variant
= wxString::Format("%d", row
% 100);
447 wxFAIL_MSG( "invalid column" );
451 bool MyListModel::GetAttrByRow( unsigned int row
, unsigned int col
,
452 wxDataViewItemAttr
&attr
) const
456 case Col_EditableText
:
462 attr
.SetColour(*wxLIGHT_GREY
);
465 case Col_TextWithAttr
:
467 // do what the labels defined in GetValueByRow() hint at
471 attr
.SetColour(*wxBLUE
);
475 attr
.SetColour(*wxGREEN
);
479 attr
.SetColour(*wxRED
);
483 attr
.SetColour(*wxCYAN
);
493 wxFAIL_MSG( "invalid column" );
499 bool MyListModel::SetValueByRow( const wxVariant
&variant
,
500 unsigned int row
, unsigned int col
)
504 case Col_EditableText
:
506 if (row
>= m_textColValues
.GetCount())
508 // the item is not in the range of the items
509 // which we store... for simplicity, don't allow editing it
510 wxLogError( "Cannot edit rows with an index greater than %d",
511 m_textColValues
.GetCount() );
515 if ( col
== Col_EditableText
)
517 m_textColValues
[row
] = variant
.GetString();
519 else // col == Col_IconText
521 wxDataViewIconText iconText
;
523 m_iconColValues
[row
] = iconText
.GetText();
527 case Col_TextWithAttr
:
529 wxLogError("Cannot edit the column %d", col
);
533 wxFAIL_MSG( "invalid column" );
540 // ----------------------------------------------------------------------------
541 // MyListStoreDerivedModel
542 // ----------------------------------------------------------------------------
544 bool MyListStoreDerivedModel::IsEnabledByRow(unsigned int row
, unsigned int col
) const
546 // disabled the last two checkboxes
547 return !(col
== 0 && 8 <= row
&& row
<= 9);