]> git.saurik.com Git - wxWidgets.git/blame - samples/dataview/mymodels.cpp
Fix wxHtmlHelpData::SetTempDir() to behave correctly without trailing slash.
[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
03dfc8f5 7// Copyright: (c) Robert Roebling
526954c5 8// Licence: wxWindows licence
03dfc8f5
VZ
9/////////////////////////////////////////////////////////////////////////////
10
11
12// For compilers that support precompilation, includes "wx/wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16#pragma hdrstop
17#endif
18
19#ifndef WX_PRECOMP
20 #include "wx/wx.h"
21#endif
22
23#include "wx/dataview.h"
24#include "mymodels.h"
25
26// ----------------------------------------------------------------------------
27// resources
28// ----------------------------------------------------------------------------
29
30#include "null.xpm"
31#include "wx_small.xpm"
32
33
34// ----------------------------------------------------------------------------
35// MyMusicTreeModel
36// ----------------------------------------------------------------------------
37
38MyMusicTreeModel::MyMusicTreeModel()
39{
ecad59d8 40 m_root = new MyMusicTreeModelNode( NULL, "My Music" );
03dfc8f5
VZ
41
42 // setup pop music
ecad59d8 43 m_pop = new MyMusicTreeModelNode( m_root, "Pop music" );
03dfc8f5 44 m_pop->Append(
caa4f8ff 45 new MyMusicTreeModelNode( m_pop, "You are not alone", "Michael Jackson", 1995 ) );
03dfc8f5 46 m_pop->Append(
ecad59d8 47 new MyMusicTreeModelNode( m_pop, "Take a bow", "Madonna", 1994 ) );
03dfc8f5
VZ
48 m_root->Append( m_pop );
49
50 // setup classical music
ecad59d8
FM
51 m_classical = new MyMusicTreeModelNode( m_root, "Classical music" );
52 m_ninth = new MyMusicTreeModelNode( m_classical, "Ninth symphony",
53 "Ludwig van Beethoven", 1824 );
03dfc8f5 54 m_classical->Append( m_ninth );
ecad59d8
FM
55 m_classical->Append( new MyMusicTreeModelNode( m_classical, "German Requiem",
56 "Johannes Brahms", 1868 ) );
03dfc8f5
VZ
57 m_root->Append( m_classical );
58
59 m_classicalMusicIsKnownToControl = false;
60}
61
62wxString MyMusicTreeModel::GetTitle( const wxDataViewItem &item ) const
63{
64 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
65 if (!node) // happens if item.IsOk()==false
66 return wxEmptyString;
67
68 return node->m_title;
69}
70
ecc32226
RR
71wxString MyMusicTreeModel::GetArtist( const wxDataViewItem &item ) const
72{
73 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
74 if (!node) // happens if item.IsOk()==false
75 return wxEmptyString;
76
77 return node->m_artist;
78}
79
03dfc8f5
VZ
80int MyMusicTreeModel::GetYear( const wxDataViewItem &item ) const
81{
82 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
83 if (!node) // happens if item.IsOk()==false
84 return 2000;
85
86 return node->m_year;
87}
88
89void MyMusicTreeModel::AddToClassical( const wxString &title, const wxString &artist,
90 unsigned int year )
91{
92 if (!m_classical)
93 {
94 wxASSERT(m_root);
95
96 // it was removed: restore it
ecad59d8 97 m_classical = new MyMusicTreeModelNode( m_root, "Classical music" );
03dfc8f5 98 m_root->Append( m_classical );
ecad59d8
FM
99
100 // notify control
101 wxDataViewItem child( (void*) m_classical );
102 wxDataViewItem parent( (void*) m_root );
103 ItemAdded( parent, child );
03dfc8f5
VZ
104 }
105
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 );
110
ecad59d8 111 // FIXME: what's m_classicalMusicIsKnownToControl for?
03dfc8f5
VZ
112 if (m_classicalMusicIsKnownToControl)
113 {
114 // notify control
115 wxDataViewItem child( (void*) child_node );
116 wxDataViewItem parent( (void*) m_classical );
117 ItemAdded( parent, child );
118 }
119}
120
121void MyMusicTreeModel::Delete( const wxDataViewItem &item )
122{
123 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
124 if (!node) // happens if item.IsOk()==false
125 return;
126
127 wxDataViewItem parent( node->GetParent() );
128 if (!parent.IsOk())
129 {
130 wxASSERT(node == m_root);
131
132 // don't make the control completely empty:
ecad59d8 133 wxLogError( "Cannot remove the root item!" );
03dfc8f5
VZ
134 return;
135 }
136
137 // is the node one of those we keep stored in special pointers?
138 if (node == m_pop)
139 m_pop = NULL;
140 else if (node == m_classical)
141 m_classical = NULL;
142 else if (node == m_ninth)
143 m_ninth = NULL;
144
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 );
149
150 // free the node
151 delete node;
152
153 // notify control
154 ItemDeleted( parent, item );
155}
156
157int MyMusicTreeModel::Compare( const wxDataViewItem &item1, const wxDataViewItem &item2,
a82e28dd 158 unsigned int column, bool ascending ) const
03dfc8f5
VZ
159{
160 wxASSERT(item1.IsOk() && item2.IsOk());
161 // should never happen
162
163 if (IsContainer(item1) && IsContainer(item2))
164 {
165 wxVariant value1, value2;
166 GetValue( value1, item1, 0 );
167 GetValue( value2, item2, 0 );
168
169 wxString str1 = value1.GetString();
170 wxString str2 = value2.GetString();
171 int res = str1.Cmp( str2 );
172 if (res) return res;
173
174 // items must be different
175 wxUIntPtr litem1 = (wxUIntPtr) item1.GetID();
176 wxUIntPtr litem2 = (wxUIntPtr) item2.GetID();
177
178 return litem1-litem2;
179 }
180
181 return wxDataViewModel::Compare( item1, item2, column, ascending );
182}
183
184void MyMusicTreeModel::GetValue( wxVariant &variant,
185 const wxDataViewItem &item, unsigned int col ) const
186{
187 wxASSERT(item.IsOk());
188
189 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
190 switch (col)
191 {
192 case 0:
193 variant = node->m_title;
194 break;
195 case 1:
196 variant = node->m_artist;
197 break;
198 case 2:
199 variant = (long) node->m_year;
200 break;
201 case 3:
202 variant = node->m_quality;
203 break;
204 case 4:
ef6833f9 205 variant = 80L; // all music is very 80% popular
03dfc8f5
VZ
206 break;
207 case 5:
03dfc8f5 208 if (GetYear(item) < 1900)
ef6833f9 209 variant = "old";
03dfc8f5 210 else
ef6833f9 211 variant = "new";
03dfc8f5
VZ
212 break;
213
214 default:
ecad59d8 215 wxLogError( "MyMusicTreeModel::GetValue: wrong column %d", col );
03dfc8f5
VZ
216 }
217}
218
219bool MyMusicTreeModel::SetValue( const wxVariant &variant,
220 const wxDataViewItem &item, unsigned int col )
221{
222 wxASSERT(item.IsOk());
223
224 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
225 switch (col)
226 {
227 case 0:
228 node->m_title = variant.GetString();
229 return true;
230 case 1:
231 node->m_artist = variant.GetString();
232 return true;
233 case 2:
234 node->m_year = variant.GetLong();
235 return true;
236 case 3:
237 node->m_quality = variant.GetString();
238 return true;
239
240 default:
ecad59d8 241 wxLogError( "MyMusicTreeModel::SetValue: wrong column" );
03dfc8f5
VZ
242 }
243 return false;
244}
245
98f8e666
VZ
246bool MyMusicTreeModel::IsEnabled( const wxDataViewItem &item,
247 unsigned int col ) const
248{
249 wxASSERT(item.IsOk());
250
251 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
252
253 // disable Beethoven's ratings, his pieces can only be good
254 return !(col == 3 && node->m_artist.EndsWith("Beethoven"));
255}
256
03dfc8f5
VZ
257wxDataViewItem MyMusicTreeModel::GetParent( const wxDataViewItem &item ) const
258{
259 // the invisible root node has no parent
260 if (!item.IsOk())
261 return wxDataViewItem(0);
262
263 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
264
265 // "MyMusic" also has no parent
266 if (node == m_root)
267 return wxDataViewItem(0);
268
269 return wxDataViewItem( (void*) node->GetParent() );
270}
271
272bool MyMusicTreeModel::IsContainer( const wxDataViewItem &item ) const
273{
274 // the invisble root node can have children
275 // (in our model always "MyMusic")
276 if (!item.IsOk())
277 return true;
278
279 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) item.GetID();
280 return node->IsContainer();
281}
282
283unsigned int MyMusicTreeModel::GetChildren( const wxDataViewItem &parent,
284 wxDataViewItemArray &array ) const
285{
286 MyMusicTreeModelNode *node = (MyMusicTreeModelNode*) parent.GetID();
287 if (!node)
288 {
289 array.Add( wxDataViewItem( (void*) m_root ) );
290 return 1;
291 }
292
293 if (node == m_classical)
294 {
295 MyMusicTreeModel *model = (MyMusicTreeModel*)(const MyMusicTreeModel*) this;
296 model->m_classicalMusicIsKnownToControl = true;
297 }
298
299 if (node->GetChildCount() == 0)
300 {
301 return 0;
302 }
303
304 unsigned int count = node->GetChildren().GetCount();
305 for (unsigned int pos = 0; pos < count; pos++)
306 {
307 MyMusicTreeModelNode *child = node->GetChildren().Item( pos );
308 array.Add( wxDataViewItem( (void*) child ) );
309 }
310
311 return count;
312}
313
314
315
316// ----------------------------------------------------------------------------
317// MyListModel
318// ----------------------------------------------------------------------------
319
320static int my_sort_reverse( int *v1, int *v2 )
321{
322 return *v2-*v1;
323}
324
325static int my_sort( int *v1, int *v2 )
326{
327 return *v1-*v2;
328}
329
d8090b5e 330#define INITIAL_NUMBER_OF_ITEMS 10000
03dfc8f5
VZ
331
332MyListModel::MyListModel() :
333 wxDataViewVirtualListModel( INITIAL_NUMBER_OF_ITEMS )
334{
03dfc8f5 335 // the first 100 items are really stored in this model;
205bdf20
VZ
336 // all the others are synthesized on request
337 static const unsigned NUMBER_REAL_ITEMS = 100;
338
339 m_textColValues.reserve(NUMBER_REAL_ITEMS);
c937bcac
VZ
340 m_textColValues.push_back("first row with long label to test ellipsization");
341 for (unsigned int i = 1; i < NUMBER_REAL_ITEMS; i++)
03dfc8f5 342 {
205bdf20 343 m_textColValues.push_back(wxString::Format("real row %d", i));
03dfc8f5
VZ
344 }
345
205bdf20
VZ
346 m_iconColValues.assign(NUMBER_REAL_ITEMS, "test");
347
03dfc8f5
VZ
348 m_icon[0] = wxIcon( null_xpm );
349 m_icon[1] = wxIcon( wx_small_xpm );
350}
351
352void MyListModel::Prepend( const wxString &text )
353{
205bdf20 354 m_textColValues.Insert( text, 0 );
03dfc8f5
VZ
355 RowPrepended();
356}
357
358void MyListModel::DeleteItem( const wxDataViewItem &item )
359{
360 unsigned int row = GetRow( item );
ce00f59b 361
205bdf20 362 if (row >= m_textColValues.GetCount())
03dfc8f5
VZ
363 return;
364
205bdf20 365 m_textColValues.RemoveAt( row );
03dfc8f5
VZ
366 RowDeleted( row );
367}
368
369void MyListModel::DeleteItems( const wxDataViewItemArray &items )
370{
371 unsigned i;
372 wxArrayInt rows;
bfb9ad8b 373 for (i = 0; i < items.GetCount(); i++)
03dfc8f5
VZ
374 {
375 unsigned int row = GetRow( items[i] );
205bdf20 376 if (row < m_textColValues.GetCount())
03dfc8f5
VZ
377 rows.Add( row );
378 }
379
380 if (rows.GetCount() == 0)
381 {
382 // none of the selected items were in the range of the items
383 // which we store... for simplicity, don't allow removing them
205bdf20 384 wxLogError( "Cannot remove rows with an index greater than %d", m_textColValues.GetCount() );
03dfc8f5
VZ
385 return;
386 }
387
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++)
205bdf20 393 m_textColValues.RemoveAt( rows[i] );
03dfc8f5
VZ
394
395 // This is just to test if wxDataViewCtrl can
396 // cope with removing rows not sorted in
397 // descending order
398 rows.Sort( my_sort );
399 RowsDeleted( rows );
400}
401
402void MyListModel::AddMany()
403{
d8090b5e 404 Reset( GetCount()+1000 );
03dfc8f5
VZ
405}
406
407void MyListModel::GetValueByRow( wxVariant &variant,
408 unsigned int row, unsigned int col ) const
409{
2746bccf 410 switch ( col )
03dfc8f5 411 {
2746bccf
VZ
412 case Col_EditableText:
413 if (row >= m_textColValues.GetCount())
414 variant = wxString::Format( "virtual row %d", row );
415 else
416 variant = m_textColValues[ row ];
417 break;
205bdf20 418
2746bccf
VZ
419 case Col_IconText:
420 {
421 wxString text;
422 if ( row >= m_iconColValues.GetCount() )
423 text = "virtual icon";
424 else
425 text = m_iconColValues[row];
426
427 variant << wxDataViewIconText(text, m_icon[row % 2]);
428 }
429 break;
430
431 case Col_TextWithAttr:
432 {
433 static const char *labels[5] =
434 {
435 "blue", "green", "red", "bold cyan", "default",
436 };
437
438 variant = labels[row % 5];
439 }
440 break;
09a0ece0 441
ef6833f9
VZ
442 case Col_Custom:
443 variant = wxString::Format("%d", row % 100);
444 break;
445
2746bccf
VZ
446 case Col_Max:
447 wxFAIL_MSG( "invalid column" );
03dfc8f5
VZ
448 }
449}
450
451bool MyListModel::GetAttrByRow( unsigned int row, unsigned int col,
7fadac88 452 wxDataViewItemAttr &attr ) const
03dfc8f5 453{
38c34918 454 switch ( col )
03dfc8f5 455 {
2746bccf 456 case Col_EditableText:
38c34918 457 return false;
09a0ece0 458
2746bccf 459 case Col_IconText:
38c34918
VZ
460 if ( !(row % 2) )
461 return false;
462 attr.SetColour(*wxLIGHT_GREY);
09a0ece0
VZ
463 break;
464
2746bccf 465 case Col_TextWithAttr:
ef6833f9
VZ
466 case Col_Custom:
467 // do what the labels defined in GetValueByRow() hint at
38c34918
VZ
468 switch ( row % 5 )
469 {
470 case 0:
471 attr.SetColour(*wxBLUE);
472 break;
473
474 case 1:
475 attr.SetColour(*wxGREEN);
476 break;
477
478 case 2:
479 attr.SetColour(*wxRED);
480 break;
481
482 case 3:
483 attr.SetColour(*wxCYAN);
484 attr.SetBold(true);
485 break;
486
487 case 4:
488 return false;
489 }
09a0ece0 490 break;
2746bccf
VZ
491
492 case Col_Max:
493 wxFAIL_MSG( "invalid column" );
03dfc8f5
VZ
494 }
495
496 return true;
497}
498
499bool MyListModel::SetValueByRow( const wxVariant &variant,
500 unsigned int row, unsigned int col )
501{
205bdf20 502 switch ( col )
03dfc8f5 503 {
2746bccf
VZ
504 case Col_EditableText:
505 case Col_IconText:
205bdf20
VZ
506 if (row >= m_textColValues.GetCount())
507 {
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() );
512 return false;
513 }
03dfc8f5 514
2746bccf 515 if ( col == Col_EditableText )
205bdf20
VZ
516 {
517 m_textColValues[row] = variant.GetString();
518 }
2746bccf 519 else // col == Col_IconText
205bdf20
VZ
520 {
521 wxDataViewIconText iconText;
522 iconText << variant;
523 m_iconColValues[row] = iconText.GetText();
524 }
2746bccf 525 return true;
205bdf20 526
2746bccf 527 case Col_TextWithAttr:
ef6833f9 528 case Col_Custom:
205bdf20 529 wxLogError("Cannot edit the column %d", col);
2746bccf
VZ
530 break;
531
532 case Col_Max:
533 wxFAIL_MSG( "invalid column" );
03dfc8f5
VZ
534 }
535
2746bccf 536 return false;
03dfc8f5 537}
98f8e666
VZ
538
539
540// ----------------------------------------------------------------------------
541// MyListStoreDerivedModel
542// ----------------------------------------------------------------------------
543
544bool MyListStoreDerivedModel::IsEnabledByRow(unsigned int row, unsigned int col) const
545{
546 // disabled the last two checkboxes
547 return !(col == 0 && 8 <= row && row <= 9);
548}