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