1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: wxDataViewCtrl wxWidgets sample
4 // Author: Robert Roebling
5 // Modified by: Francesco Montorsi, Bo Yang
8 // Copyright: (c) Robert Roebling
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 // For compilers that support precompilation, includes "wx/wx.h".
14 #include "wx/wxprec.h"
24 #include "wx/dataview.h"
27 // ----------------------------------------------------------------------------
29 // ----------------------------------------------------------------------------
32 #include "wx_small.xpm"
35 // ----------------------------------------------------------------------------
37 // ----------------------------------------------------------------------------
39 MyMusicTreeModel::MyMusicTreeModel()
41 m_root
= new MyMusicTreeModelNode( NULL
, "My Music" );
44 m_pop
= new MyMusicTreeModelNode( m_root
, "Pop music" );
46 new MyMusicTreeModelNode( m_pop
, "You are not alone", "Michael Jackson", 1995 ) );
48 new MyMusicTreeModelNode( m_pop
, "Take a bow", "Madonna", 1994 ) );
49 m_root
->Append( m_pop
);
51 // setup classical music
52 m_classical
= new MyMusicTreeModelNode( m_root
, "Classical music" );
53 m_ninth
= new MyMusicTreeModelNode( m_classical
, "Ninth symphony",
54 "Ludwig van Beethoven", 1824 );
55 m_classical
->Append( m_ninth
);
56 m_classical
->Append( new MyMusicTreeModelNode( m_classical
, "German Requiem",
57 "Johannes Brahms", 1868 ) );
58 m_root
->Append( m_classical
);
60 m_classicalMusicIsKnownToControl
= false;
63 wxString
MyMusicTreeModel::GetTitle( const wxDataViewItem
&item
) const
65 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
66 if (!node
) // happens if item.IsOk()==false
72 wxString
MyMusicTreeModel::GetArtist( const wxDataViewItem
&item
) const
74 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
75 if (!node
) // happens if item.IsOk()==false
78 return node
->m_artist
;
81 int MyMusicTreeModel::GetYear( const wxDataViewItem
&item
) const
83 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
84 if (!node
) // happens if item.IsOk()==false
90 void MyMusicTreeModel::AddToClassical( const wxString
&title
, const wxString
&artist
,
97 // it was removed: restore it
98 m_classical
= new MyMusicTreeModelNode( m_root
, "Classical music" );
99 m_root
->Append( m_classical
);
102 wxDataViewItem
child( (void*) m_classical
);
103 wxDataViewItem
parent( (void*) m_root
);
104 ItemAdded( parent
, child
);
107 // add to the classical music node a new node:
108 MyMusicTreeModelNode
*child_node
=
109 new MyMusicTreeModelNode( m_classical
, title
, artist
, year
);
110 m_classical
->Append( child_node
);
112 // FIXME: what's m_classicalMusicIsKnownToControl for?
113 if (m_classicalMusicIsKnownToControl
)
116 wxDataViewItem
child( (void*) child_node
);
117 wxDataViewItem
parent( (void*) m_classical
);
118 ItemAdded( parent
, child
);
122 void MyMusicTreeModel::Delete( const wxDataViewItem
&item
)
124 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
125 if (!node
) // happens if item.IsOk()==false
128 wxDataViewItem
parent( node
->GetParent() );
131 wxASSERT(node
== m_root
);
133 // don't make the control completely empty:
134 wxLogError( "Cannot remove the root item!" );
138 // is the node one of those we keep stored in special pointers?
141 else if (node
== m_classical
)
143 else if (node
== m_ninth
)
146 // first remove the node from the parent's array of children;
147 // NOTE: MyMusicTreeModelNodePtrArray is only an array of _pointers_
148 // thus removing the node from it doesn't result in freeing it
149 node
->GetParent()->GetChildren().Remove( node
);
155 ItemDeleted( parent
, item
);
158 int MyMusicTreeModel::Compare( const wxDataViewItem
&item1
, const wxDataViewItem
&item2
,
159 unsigned int column
, bool ascending
) const
161 wxASSERT(item1
.IsOk() && item2
.IsOk());
162 // should never happen
164 if (IsContainer(item1
) && IsContainer(item2
))
166 wxVariant value1
, value2
;
167 GetValue( value1
, item1
, 0 );
168 GetValue( value2
, item2
, 0 );
170 wxString str1
= value1
.GetString();
171 wxString str2
= value2
.GetString();
172 int res
= str1
.Cmp( str2
);
175 // items must be different
176 wxUIntPtr litem1
= (wxUIntPtr
) item1
.GetID();
177 wxUIntPtr litem2
= (wxUIntPtr
) item2
.GetID();
179 return litem1
-litem2
;
182 return wxDataViewModel::Compare( item1
, item2
, column
, ascending
);
185 void MyMusicTreeModel::GetValue( wxVariant
&variant
,
186 const wxDataViewItem
&item
, unsigned int col
) const
188 wxASSERT(item
.IsOk());
190 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
194 variant
= node
->m_title
;
197 variant
= node
->m_artist
;
200 variant
= (long) node
->m_year
;
203 variant
= node
->m_quality
;
206 variant
= 80L; // all music is very 80% popular
209 if (GetYear(item
) < 1900)
216 wxLogError( "MyMusicTreeModel::GetValue: wrong column %d", col
);
220 bool MyMusicTreeModel::SetValue( const wxVariant
&variant
,
221 const wxDataViewItem
&item
, unsigned int col
)
223 wxASSERT(item
.IsOk());
225 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
229 node
->m_title
= variant
.GetString();
232 node
->m_artist
= variant
.GetString();
235 node
->m_year
= variant
.GetLong();
238 node
->m_quality
= variant
.GetString();
242 wxLogError( "MyMusicTreeModel::SetValue: wrong column" );
247 wxDataViewItem
MyMusicTreeModel::GetParent( const wxDataViewItem
&item
) const
249 // the invisible root node has no parent
251 return wxDataViewItem(0);
253 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
255 // "MyMusic" also has no parent
257 return wxDataViewItem(0);
259 return wxDataViewItem( (void*) node
->GetParent() );
262 bool MyMusicTreeModel::IsContainer( const wxDataViewItem
&item
) const
264 // the invisble root node can have children
265 // (in our model always "MyMusic")
269 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) item
.GetID();
270 return node
->IsContainer();
273 unsigned int MyMusicTreeModel::GetChildren( const wxDataViewItem
&parent
,
274 wxDataViewItemArray
&array
) const
276 MyMusicTreeModelNode
*node
= (MyMusicTreeModelNode
*) parent
.GetID();
279 array
.Add( wxDataViewItem( (void*) m_root
) );
283 if (node
== m_classical
)
285 MyMusicTreeModel
*model
= (MyMusicTreeModel
*)(const MyMusicTreeModel
*) this;
286 model
->m_classicalMusicIsKnownToControl
= true;
289 if (node
->GetChildCount() == 0)
294 unsigned int count
= node
->GetChildren().GetCount();
295 for (unsigned int pos
= 0; pos
< count
; pos
++)
297 MyMusicTreeModelNode
*child
= node
->GetChildren().Item( pos
);
298 array
.Add( wxDataViewItem( (void*) child
) );
306 // ----------------------------------------------------------------------------
308 // ----------------------------------------------------------------------------
310 static int my_sort_reverse( int *v1
, int *v2
)
315 static int my_sort( int *v1
, int *v2
)
320 #define INITIAL_NUMBER_OF_ITEMS 100000
322 MyListModel::MyListModel() :
323 wxDataViewVirtualListModel( INITIAL_NUMBER_OF_ITEMS
)
325 m_virtualItems
= INITIAL_NUMBER_OF_ITEMS
;
327 // the first 100 items are really stored in this model;
328 // all the others are synthesized on request
329 static const unsigned NUMBER_REAL_ITEMS
= 100;
331 m_textColValues
.reserve(NUMBER_REAL_ITEMS
);
332 m_textColValues
.push_back("first row with long label to test ellipsization");
333 for (unsigned int i
= 1; i
< NUMBER_REAL_ITEMS
; i
++)
335 m_textColValues
.push_back(wxString::Format("real row %d", i
));
338 m_iconColValues
.assign(NUMBER_REAL_ITEMS
, "test");
340 m_icon
[0] = wxIcon( null_xpm
);
341 m_icon
[1] = wxIcon( wx_small_xpm
);
344 void MyListModel::Prepend( const wxString
&text
)
346 m_textColValues
.Insert( text
, 0 );
350 void MyListModel::DeleteItem( const wxDataViewItem
&item
)
352 unsigned int row
= GetRow( item
);
353 if (row
>= m_textColValues
.GetCount())
356 m_textColValues
.RemoveAt( row
);
360 void MyListModel::DeleteItems( const wxDataViewItemArray
&items
)
364 for (i
= 0; i
< items
.GetCount(); i
++)
366 unsigned int row
= GetRow( items
[i
] );
367 if (row
< m_textColValues
.GetCount())
371 if (rows
.GetCount() == 0)
373 // none of the selected items were in the range of the items
374 // which we store... for simplicity, don't allow removing them
375 wxLogError( "Cannot remove rows with an index greater than %d", m_textColValues
.GetCount() );
379 // Sort in descending order so that the last
380 // row will be deleted first. Otherwise the
381 // remaining indeces would all be wrong.
382 rows
.Sort( my_sort_reverse
);
383 for (i
= 0; i
< rows
.GetCount(); i
++)
384 m_textColValues
.RemoveAt( rows
[i
] );
386 // This is just to test if wxDataViewCtrl can
387 // cope with removing rows not sorted in
389 rows
.Sort( my_sort
);
393 void MyListModel::AddMany()
395 m_virtualItems
+= 1000;
396 Reset( m_textColValues
.GetCount() + m_virtualItems
);
399 void MyListModel::GetValueByRow( wxVariant
&variant
,
400 unsigned int row
, unsigned int col
) const
404 case Col_EditableText
:
405 if (row
>= m_textColValues
.GetCount())
406 variant
= wxString::Format( "virtual row %d", row
);
408 variant
= m_textColValues
[ row
];
414 if ( row
>= m_iconColValues
.GetCount() )
415 text
= "virtual icon";
417 text
= m_iconColValues
[row
];
419 variant
<< wxDataViewIconText(text
, m_icon
[row
% 2]);
423 case Col_TextWithAttr
:
425 static const char *labels
[5] =
427 "blue", "green", "red", "bold cyan", "default",
430 variant
= labels
[row
% 5];
435 variant
= wxString::Format("%d", row
% 100);
439 wxFAIL_MSG( "invalid column" );
443 bool MyListModel::GetAttrByRow( unsigned int row
, unsigned int col
,
444 wxDataViewItemAttr
&attr
) const
448 case Col_EditableText
:
454 attr
.SetColour(*wxLIGHT_GREY
);
457 case Col_TextWithAttr
:
459 // do what the labels defined in GetValueByRow() hint at
463 attr
.SetColour(*wxBLUE
);
467 attr
.SetColour(*wxGREEN
);
471 attr
.SetColour(*wxRED
);
475 attr
.SetColour(*wxCYAN
);
485 wxFAIL_MSG( "invalid column" );
491 bool MyListModel::SetValueByRow( const wxVariant
&variant
,
492 unsigned int row
, unsigned int col
)
496 case Col_EditableText
:
498 if (row
>= m_textColValues
.GetCount())
500 // the item is not in the range of the items
501 // which we store... for simplicity, don't allow editing it
502 wxLogError( "Cannot edit rows with an index greater than %d",
503 m_textColValues
.GetCount() );
507 if ( col
== Col_EditableText
)
509 m_textColValues
[row
] = variant
.GetString();
511 else // col == Col_IconText
513 wxDataViewIconText iconText
;
515 m_iconColValues
[row
] = iconText
.GetText();
519 case Col_TextWithAttr
:
521 wxLogError("Cannot edit the column %d", col
);
525 wxFAIL_MSG( "invalid column" );