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