remove wxT() and _() macros to make the sample more readable; add File->Clear log...
[wxWidgets.git] / samples / dataview / mymodels.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: mymodels.cpp
3 // Purpose: wxDataViewCtrl wxWidgets sample
4 // Author: Robert Roebling
5 // Modified by: Francesco Montorsi, Bo Yang
6 // Created: 06/01/06
7 // RCS-ID: $Id$
8 // Copyright: (c) Robert Roebling
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12
13 // For compilers that support precompilation, includes "wx/wx.h".
14 #include "wx/wxprec.h"
15
16 #ifdef __BORLANDC__
17 #pragma hdrstop
18 #endif
19
20 #ifndef WX_PRECOMP
21 #include "wx/wx.h"
22 #endif
23
24 #include "wx/dataview.h"
25 #include "mymodels.h"
26
27 // ----------------------------------------------------------------------------
28 // resources
29 // ----------------------------------------------------------------------------
30
31 #include "null.xpm"
32 #include "wx_small.xpm"
33
34
35 // ----------------------------------------------------------------------------
36 // MyMusicTreeModel
37 // ----------------------------------------------------------------------------
38
39 MyMusicTreeModel::MyMusicTreeModel()
40 {
41 m_root = new MyMusicTreeModelNode( NULL, "My Music" );
42
43 // setup pop music
44 m_pop = new MyMusicTreeModelNode( m_root, "Pop music" );
45 m_pop->Append(
46 new MyMusicTreeModelNode( m_pop, "You are not alone"), "Michael Jackson", 1995 ) );
47 m_pop->Append(
48 new MyMusicTreeModelNode( m_pop, "Take a bow", "Madonna", 1994 ) );
49 m_root->Append( m_pop );
50
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 );
59
60 m_classicalMusicIsKnownToControl = false;
61 }
62
63 wxString MyMusicTreeModel::GetTitle( const wxDataViewItem &item ) const
64 {
65 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
66 if (!node) // happens if item.IsOk()==false
67 return wxEmptyString;
68
69 return node->m_title;
70 }
71
72 int MyMusicTreeModel::GetYear( const wxDataViewItem &item ) const
73 {
74 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
75 if (!node) // happens if item.IsOk()==false
76 return 2000;
77
78 return node->m_year;
79 }
80
81 void MyMusicTreeModel::AddToClassical( const wxString &title, const wxString &artist,
82 unsigned int year )
83 {
84 if (!m_classical)
85 {
86 wxASSERT(m_root);
87
88 // it was removed: restore it
89 m_classical = new MyMusicTreeModelNode( m_root, "Classical music" );
90 m_root->Append( m_classical );
91
92 // notify control
93 wxDataViewItem child( (void*) m_classical );
94 wxDataViewItem parent( (void*) m_root );
95 ItemAdded( parent, child );
96 }
97
98 // add to the classical music node a new node:
99 MyMusicTreeModelNode *child_node =
100 new MyMusicTreeModelNode( m_classical, title, artist, year );
101 m_classical->Append( child_node );
102
103 // FIXME: what's m_classicalMusicIsKnownToControl for?
104 if (m_classicalMusicIsKnownToControl)
105 {
106 // notify control
107 wxDataViewItem child( (void*) child_node );
108 wxDataViewItem parent( (void*) m_classical );
109 ItemAdded( parent, child );
110 }
111 }
112
113 void MyMusicTreeModel::Delete( const wxDataViewItem &item )
114 {
115 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
116 if (!node) // happens if item.IsOk()==false
117 return;
118
119 wxDataViewItem parent( node->GetParent() );
120 if (!parent.IsOk())
121 {
122 wxASSERT(node == m_root);
123
124 // don't make the control completely empty:
125 wxLogError( "Cannot remove the root item!" );
126 return;
127 }
128
129 // is the node one of those we keep stored in special pointers?
130 if (node == m_pop)
131 m_pop = NULL;
132 else if (node == m_classical)
133 m_classical = NULL;
134 else if (node == m_ninth)
135 m_ninth = NULL;
136
137 // first remove the node from the parent's array of children;
138 // NOTE: MyMusicTreeModelNodePtrArray is only an array of _pointers_
139 // thus removing the node from it doesn't result in freeing it
140 node->GetParent()->GetChildren().Remove( node );
141
142 // free the node
143 delete node;
144
145 // notify control
146 ItemDeleted( parent, item );
147 }
148
149 int MyMusicTreeModel::Compare( const wxDataViewItem &item1, const wxDataViewItem &item2,
150 unsigned int column, bool ascending )
151 {
152 wxASSERT(item1.IsOk() && item2.IsOk());
153 // should never happen
154
155 if (IsContainer(item1) && IsContainer(item2))
156 {
157 wxVariant value1, value2;
158 GetValue( value1, item1, 0 );
159 GetValue( value2, item2, 0 );
160
161 wxString str1 = value1.GetString();
162 wxString str2 = value2.GetString();
163 int res = str1.Cmp( str2 );
164 if (res) return res;
165
166 // items must be different
167 wxUIntPtr litem1 = (wxUIntPtr) item1.GetID();
168 wxUIntPtr litem2 = (wxUIntPtr) item2.GetID();
169
170 return litem1-litem2;
171 }
172
173 return wxDataViewModel::Compare( item1, item2, column, ascending );
174 }
175
176 void MyMusicTreeModel::GetValue( wxVariant &variant,
177 const wxDataViewItem &item, unsigned int col ) const
178 {
179 wxASSERT(item.IsOk());
180
181 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
182 switch (col)
183 {
184 case 0:
185 variant = node->m_title;
186 break;
187 case 1:
188 variant = node->m_artist;
189 break;
190 case 2:
191 variant = (long) node->m_year;
192 break;
193 case 3:
194 variant = node->m_quality;
195 break;
196 case 4:
197 // wxMac doesn't conceal the popularity progress renderer, return 0 for containers
198 if (IsContainer(item))
199 variant = (long) 0;
200 else
201 variant = (long) 80; // all music is very 80% popular
202 break;
203 case 5:
204 // Make size of red square depend on year
205 if (GetYear(item) < 1900)
206 variant = (long) 35;
207 else
208 variant = (long) 25;
209 break;
210
211 default:
212 wxLogError( "MyMusicTreeModel::GetValue: wrong column %d", col );
213 }
214 }
215
216 bool MyMusicTreeModel::SetValue( const wxVariant &variant,
217 const wxDataViewItem &item, unsigned int col )
218 {
219 wxASSERT(item.IsOk());
220
221 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
222 switch (col)
223 {
224 case 0:
225 node->m_title = variant.GetString();
226 return true;
227 case 1:
228 node->m_artist = variant.GetString();
229 return true;
230 case 2:
231 node->m_year = variant.GetLong();
232 return true;
233 case 3:
234 node->m_quality = variant.GetString();
235 return true;
236
237 default:
238 wxLogError( "MyMusicTreeModel::SetValue: wrong column" );
239 }
240 return false;
241 }
242
243 wxDataViewItem MyMusicTreeModel::GetParent( const wxDataViewItem &item ) const
244 {
245 // the invisible root node has no parent
246 if (!item.IsOk())
247 return wxDataViewItem(0);
248
249 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
250
251 // "MyMusic" also has no parent
252 if (node == m_root)
253 return wxDataViewItem(0);
254
255 return wxDataViewItem( (void*) node->GetParent() );
256 }
257
258 bool MyMusicTreeModel::IsContainer( const wxDataViewItem &item ) const
259 {
260 // the invisble root node can have children
261 // (in our model always "MyMusic")
262 if (!item.IsOk())
263 return true;
264
265 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
266 return node->IsContainer();
267 }
268
269 unsigned int MyMusicTreeModel::GetChildren( const wxDataViewItem &parent,
270 wxDataViewItemArray &array ) const
271 {
272 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) parent.GetID();
273 if (!node)
274 {
275 array.Add( wxDataViewItem( (void*) m_root ) );
276 return 1;
277 }
278
279 if (node == m_classical)
280 {
281 MyMusicTreeModel *model = (MyMusicTreeModel*)(const MyMusicTreeModel*) this;
282 model->m_classicalMusicIsKnownToControl = true;
283 }
284
285 if (node->GetChildCount() == 0)
286 {
287 return 0;
288 }
289
290 unsigned int count = node->GetChildren().GetCount();
291 for (unsigned int pos = 0; pos < count; pos++)
292 {
293 MyMusicTreeModelNode *child = node->GetChildren().Item( pos );
294 array.Add( wxDataViewItem( (void*) child ) );
295 }
296
297 return count;
298 }
299
300
301
302 // ----------------------------------------------------------------------------
303 // MyListModel
304 // ----------------------------------------------------------------------------
305
306 static int my_sort_reverse( int *v1, int *v2 )
307 {
308 return *v2-*v1;
309 }
310
311 static int my_sort( int *v1, int *v2 )
312 {
313 return *v1-*v2;
314 }
315
316 #ifdef __WXMAC__
317 #define INITIAL_NUMBER_OF_ITEMS 100
318 #else
319 #define INITIAL_NUMBER_OF_ITEMS 100000
320 #endif
321
322 MyListModel::MyListModel() :
323 wxDataViewVirtualListModel( INITIAL_NUMBER_OF_ITEMS )
324 {
325 m_virtualItems = INITIAL_NUMBER_OF_ITEMS;
326
327 // the first 100 items are really stored in this model;
328 // all the others are synthetized on request
329 for (unsigned int i = 0; i < 100; i++)
330 {
331 wxString str;
332 str.Printf( "real row %d"), i );
333 m_array.Add( str );
334 }
335
336 m_icon[0] = wxIcon( null_xpm );
337 m_icon[1] = wxIcon( wx_small_xpm );
338 }
339
340 void MyListModel::Prepend( const wxString &text )
341 {
342 m_array.Insert( text, 0 );
343 RowPrepended();
344 }
345
346 void MyListModel::DeleteItem( const wxDataViewItem &item )
347 {
348 unsigned int row = GetRow( item );
349 if (row >= m_array.GetCount())
350 return;
351
352 m_array.RemoveAt( row );
353 RowDeleted( row );
354 }
355
356 void MyListModel::DeleteItems( const wxDataViewItemArray &items )
357 {
358 unsigned i;
359 wxArrayInt rows;
360 for (i = 0; i < items.GetCount(); i++)
361 {
362 unsigned int row = GetRow( items[i] );
363 if (row < m_array.GetCount())
364 rows.Add( row );
365 }
366
367 if (rows.GetCount() == 0)
368 {
369 // none of the selected items were in the range of the items
370 // which we store... for simplicity, don't allow removing them
371 wxLogError( "Cannot remove rows with an index greater than %d", m_array.GetCount() );
372 return;
373 }
374
375 // Sort in descending order so that the last
376 // row will be deleted first. Otherwise the
377 // remaining indeces would all be wrong.
378 rows.Sort( my_sort_reverse );
379 for (i = 0; i < rows.GetCount(); i++)
380 m_array.RemoveAt( rows[i] );
381
382 // This is just to test if wxDataViewCtrl can
383 // cope with removing rows not sorted in
384 // descending order
385 rows.Sort( my_sort );
386 RowsDeleted( rows );
387 }
388
389 void MyListModel::AddMany()
390 {
391 m_virtualItems += 1000;
392 Reset( m_array.GetCount() + m_virtualItems );
393 }
394
395 void MyListModel::GetValueByRow( wxVariant &variant,
396 unsigned int row, unsigned int col ) const
397 {
398 if (col==0)
399 {
400 if (row >= m_array.GetCount())
401 variant = wxString::Format( "virtual row %d", row );
402 else
403 variant = m_array[ row ];
404 }
405 else if (col==1)
406 {
407 wxDataViewIconText data( "test", m_icon[ row%2 ] );
408 variant << data;
409 }
410 else if (col==2)
411 {
412 if (row >= m_array.GetCount())
413 variant = "plain";
414 else
415 variant = "blue/green/red";
416 }
417 }
418
419 bool MyListModel::GetAttrByRow( unsigned int row, unsigned int col,
420 wxDataViewItemAttr &attr )
421 {
422 if (col != 2)
423 return false;
424
425 if (row < m_array.GetCount())
426 {
427 attr.SetColour( (row%2) == 0 ? *wxBLUE :
428 ((row%3) == 0 ? *wxGREEN : *wxRED) );
429 attr.SetItalic( (row%2) == 5 );
430 }
431
432 return true;
433 }
434
435 bool MyListModel::SetValueByRow( const wxVariant &variant,
436 unsigned int row, unsigned int col )
437 {
438 if (col == 0)
439 {
440 if (row >= m_array.GetCount())
441 {
442 // the item is not in the range of the items
443 // which we store... for simplicity, don't allow editing it
444 wxLogError( "Cannot edit rows with an index greater than %d", m_array.GetCount() );
445 return false;
446 }
447
448 m_array[row] = variant.GetString();
449 return true;
450 }
451
452 return false;
453 }