]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // Name: src/common/datavcmn.cpp | |
3 | // Purpose: wxDataViewCtrl base classes and common parts | |
4 | // Author: Robert Roebling | |
5 | // Created: 2006/02/20 | |
6 | // RCS-ID: $Id$ | |
7 | // Copyright: (c) 2006, Robert Roebling | |
8 | // Licence: wxWindows licence | |
9 | ///////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | // For compilers that support precompilation, includes "wx.h". | |
12 | #include "wx/wxprec.h" | |
13 | ||
14 | #ifdef __BORLANDC__ | |
15 | #pragma hdrstop | |
16 | #endif | |
17 | ||
18 | #if wxUSE_DATAVIEWCTRL | |
19 | ||
20 | #include "wx/dataview.h" | |
21 | ||
22 | #ifndef WX_PRECOMP | |
23 | #include "wx/log.h" | |
24 | #endif | |
25 | ||
26 | const wxChar wxDataViewCtrlNameStr[] = wxT("dataviewCtrl"); | |
27 | ||
28 | // --------------------------------------------------------- | |
29 | // wxDataViewModel | |
30 | // --------------------------------------------------------- | |
31 | ||
32 | IMPLEMENT_ABSTRACT_CLASS(wxDataViewModel, wxObject) | |
33 | ||
34 | // --------------------------------------------------------- | |
35 | // wxDataViewListModel | |
36 | // --------------------------------------------------------- | |
37 | ||
38 | IMPLEMENT_ABSTRACT_CLASS(wxDataViewListModel, wxDataViewModel) | |
39 | ||
40 | wxDataViewListModel::wxDataViewListModel() | |
41 | { | |
42 | m_viewingColumns.DeleteContents( true ); | |
43 | m_notifiers.DeleteContents( true ); | |
44 | } | |
45 | ||
46 | wxDataViewListModel::~wxDataViewListModel() | |
47 | { | |
48 | } | |
49 | ||
50 | bool wxDataViewListModel::RowAppended() | |
51 | { | |
52 | bool ret = true; | |
53 | ||
54 | wxList::compatibility_iterator node = m_notifiers.GetFirst(); | |
55 | while (node) | |
56 | { | |
57 | wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); | |
58 | if (!notifier->RowAppended()) | |
59 | ret = false; | |
60 | node = node->GetNext(); | |
61 | } | |
62 | ||
63 | return ret; | |
64 | } | |
65 | ||
66 | bool wxDataViewListModel::RowPrepended() | |
67 | { | |
68 | bool ret = true; | |
69 | ||
70 | wxList::compatibility_iterator node = m_notifiers.GetFirst(); | |
71 | while (node) | |
72 | { | |
73 | wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); | |
74 | if (!notifier->RowPrepended()) | |
75 | ret = false; | |
76 | node = node->GetNext(); | |
77 | } | |
78 | ||
79 | return ret; | |
80 | } | |
81 | ||
82 | bool wxDataViewListModel::RowInserted( size_t before ) | |
83 | { | |
84 | bool ret = true; | |
85 | ||
86 | wxList::compatibility_iterator node = m_notifiers.GetFirst(); | |
87 | while (node) | |
88 | { | |
89 | wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); | |
90 | if (!notifier->RowInserted(before)) | |
91 | ret = false; | |
92 | node = node->GetNext(); | |
93 | } | |
94 | ||
95 | return ret; | |
96 | } | |
97 | ||
98 | bool wxDataViewListModel::RowDeleted( size_t row ) | |
99 | { | |
100 | bool ret = true; | |
101 | ||
102 | wxList::compatibility_iterator node = m_notifiers.GetFirst(); | |
103 | while (node) | |
104 | { | |
105 | wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); | |
106 | if (!notifier->RowDeleted( row )) | |
107 | ret = false; | |
108 | node = node->GetNext(); | |
109 | } | |
110 | ||
111 | return ret; | |
112 | } | |
113 | ||
114 | bool wxDataViewListModel::RowChanged( size_t row ) | |
115 | { | |
116 | bool ret = true; | |
117 | ||
118 | wxList::compatibility_iterator node = m_notifiers.GetFirst(); | |
119 | while (node) | |
120 | { | |
121 | wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); | |
122 | if (!notifier->RowChanged( row )) | |
123 | ret = false; | |
124 | node = node->GetNext(); | |
125 | } | |
126 | ||
127 | return ret; | |
128 | } | |
129 | ||
130 | bool wxDataViewListModel::ValueChanged( size_t col, size_t row ) | |
131 | { | |
132 | bool ret = true; | |
133 | ||
134 | wxList::compatibility_iterator node = m_notifiers.GetFirst(); | |
135 | while (node) | |
136 | { | |
137 | wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); | |
138 | if (!notifier->ValueChanged( col, row )) | |
139 | ret = false; | |
140 | node = node->GetNext(); | |
141 | } | |
142 | ||
143 | return ret; | |
144 | } | |
145 | ||
146 | bool wxDataViewListModel::RowsReordered( size_t *new_order ) | |
147 | { | |
148 | bool ret = true; | |
149 | ||
150 | wxList::compatibility_iterator node = m_notifiers.GetFirst(); | |
151 | while (node) | |
152 | { | |
153 | wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); | |
154 | if (!notifier->RowsReordered( new_order )) | |
155 | ret = false; | |
156 | node = node->GetNext(); | |
157 | } | |
158 | ||
159 | return ret; | |
160 | } | |
161 | ||
162 | bool wxDataViewListModel::Cleared() | |
163 | { | |
164 | bool ret = true; | |
165 | ||
166 | wxList::compatibility_iterator node = m_notifiers.GetFirst(); | |
167 | while (node) | |
168 | { | |
169 | wxDataViewListModelNotifier* notifier = (wxDataViewListModelNotifier*) node->GetData(); | |
170 | if (!notifier->Cleared()) | |
171 | ret = false; | |
172 | node = node->GetNext(); | |
173 | } | |
174 | ||
175 | return ret; | |
176 | } | |
177 | ||
178 | void wxDataViewListModel::AddViewingColumn( wxDataViewColumn *view_column, size_t model_column ) | |
179 | { | |
180 | m_viewingColumns.Append( new wxDataViewViewingColumn( view_column, model_column ) ); | |
181 | } | |
182 | ||
183 | void wxDataViewListModel::RemoveViewingColumn( wxDataViewColumn *column ) | |
184 | { | |
185 | wxList::compatibility_iterator node = m_viewingColumns.GetFirst(); | |
186 | while (node) | |
187 | { | |
188 | wxDataViewViewingColumn* tmp = (wxDataViewViewingColumn*) node->GetData(); | |
189 | ||
190 | if (tmp->m_viewColumn == column) | |
191 | { | |
192 | m_viewingColumns.DeleteObject( tmp ); | |
193 | return; | |
194 | } | |
195 | ||
196 | node = node->GetNext(); | |
197 | } | |
198 | } | |
199 | ||
200 | void wxDataViewListModel::AddNotifier( wxDataViewListModelNotifier *notifier ) | |
201 | { | |
202 | m_notifiers.Append( notifier ); | |
203 | notifier->SetOwner( this ); | |
204 | } | |
205 | ||
206 | void wxDataViewListModel::RemoveNotifier( wxDataViewListModelNotifier *notifier ) | |
207 | { | |
208 | m_notifiers.DeleteObject( notifier ); | |
209 | } | |
210 | ||
211 | // --------------------------------------------------------- | |
212 | // wxDataViewSortedListModelNotifier | |
213 | // --------------------------------------------------------- | |
214 | ||
215 | class wxDataViewSortedListModelNotifier: public wxDataViewListModelNotifier | |
216 | { | |
217 | public: | |
218 | wxDataViewSortedListModelNotifier( wxDataViewSortedListModel *model ) | |
219 | { m_model = model; } | |
220 | ||
221 | virtual bool RowAppended() { return true; } | |
222 | virtual bool RowPrepended() { return true; } | |
223 | virtual bool RowInserted( size_t WXUNUSED(before) ) { return true; } | |
224 | virtual bool RowDeleted( size_t WXUNUSED(row) ) { return true; } | |
225 | virtual bool RowChanged( size_t WXUNUSED(row) ) { return true; } | |
226 | virtual bool ValueChanged( size_t col, size_t row ) | |
227 | { return m_model->ChildValueChanged( col, row); } | |
228 | virtual bool RowsReordered( size_t *WXUNUSED(new_order) ) { return true; } | |
229 | virtual bool Cleared() { return true; } | |
230 | ||
231 | wxDataViewSortedListModel *m_model; | |
232 | }; | |
233 | ||
234 | // --------------------------------------------------------- | |
235 | // wxDataViewSortedListModel compare function | |
236 | // --------------------------------------------------------- | |
237 | ||
238 | int wxCALLBACK wxDataViewListModelSortedDefaultCompare | |
239 | (size_t row1, size_t row2, size_t col, wxDataViewListModel* model ) | |
240 | { | |
241 | wxVariant value1,value2; | |
242 | model->GetValue( value1, col, row1 ); | |
243 | model->GetValue( value2, col, row2 ); | |
244 | if (value1.GetType() == wxT("string")) | |
245 | { | |
246 | wxString str1 = value1.GetString(); | |
247 | wxString str2 = value2.GetString(); | |
248 | return str1.Cmp( str2 ); | |
249 | } | |
250 | if (value1.GetType() == wxT("long")) | |
251 | { | |
252 | long l1 = value1.GetLong(); | |
253 | long l2 = value2.GetLong(); | |
254 | return l1-l2; | |
255 | } | |
256 | if (value1.GetType() == wxT("double")) | |
257 | { | |
258 | double d1 = value1.GetDouble(); | |
259 | double d2 = value2.GetDouble(); | |
260 | if (d1 == d2) return 0; | |
261 | if (d1 < d2) return 1; | |
262 | return -1; | |
263 | } | |
264 | if (value1.GetType() == wxT("datetime")) | |
265 | { | |
266 | wxDateTime dt1 = value1.GetDateTime(); | |
267 | wxDateTime dt2 = value2.GetDateTime(); | |
268 | if (dt1.IsEqualTo(dt2)) return 0; | |
269 | if (dt1.IsEarlierThan(dt2)) return 1; | |
270 | return -1; | |
271 | } | |
272 | ||
273 | return 0; | |
274 | } | |
275 | ||
276 | static wxDataViewListModelCompare s_CmpFunc; | |
277 | static wxDataViewListModel *s_CmpModel; | |
278 | static size_t s_CmpCol; | |
279 | ||
280 | int LINKAGEMODE wxDataViewIntermediateCmp( size_t row1, size_t row2 ) | |
281 | { | |
282 | return s_CmpFunc( row1, row2, s_CmpCol, s_CmpModel ); | |
283 | } | |
284 | ||
285 | // --------------------------------------------------------- | |
286 | // wxDataViewSortedListModel | |
287 | // --------------------------------------------------------- | |
288 | ||
289 | IMPLEMENT_ABSTRACT_CLASS(wxDataViewSortedListModel, wxDataViewListModel) | |
290 | ||
291 | wxDataViewSortedListModel::wxDataViewSortedListModel( wxDataViewListModel *child ) : | |
292 | m_array( wxDataViewIntermediateCmp ) | |
293 | { | |
294 | m_child = child; | |
295 | s_CmpCol = 0; | |
296 | s_CmpModel = child; | |
297 | s_CmpFunc = wxDataViewListModelSortedDefaultCompare; | |
298 | ||
299 | m_notifierOnChild = new wxDataViewSortedListModelNotifier( this ); | |
300 | m_child->AddNotifier( m_notifierOnChild ); | |
301 | ||
302 | Resort(); | |
303 | } | |
304 | ||
305 | wxDataViewSortedListModel::~wxDataViewSortedListModel() | |
306 | { | |
307 | m_child->RemoveNotifier( m_notifierOnChild ); | |
308 | } | |
309 | ||
310 | void wxDataViewSortedListModel::Resort() | |
311 | { | |
312 | m_array.Clear(); | |
313 | size_t n = m_child->GetNumberOfRows(); | |
314 | size_t i; | |
315 | for (i = 0; i < n; i++) | |
316 | m_array.Add( i ); | |
317 | } | |
318 | ||
319 | #if 0 | |
320 | static void Dump( wxDataViewListModel *model, size_t col ) | |
321 | { | |
322 | size_t n = model->GetNumberOfRows(); | |
323 | size_t i; | |
324 | for (i = 0; i < n; i++) | |
325 | { | |
326 | wxVariant variant; | |
327 | model->GetValue( variant, col, i ); | |
328 | wxString tmp; | |
329 | tmp = variant.GetString(); | |
330 | wxPrintf( wxT("%d: %s\n"), (int) i, tmp.c_str() ); | |
331 | } | |
332 | } | |
333 | #endif | |
334 | ||
335 | bool wxDataViewSortedListModel::ChildValueChanged( size_t col, size_t row ) | |
336 | { | |
337 | size_t i; | |
338 | size_t len = m_array.GetCount(); | |
339 | ||
340 | // Remove and readd sorted. Find out at which | |
341 | // position it was and where it ended. | |
342 | size_t start_pos = 0,end_pos = 0; | |
343 | for (i = 0; i < len; i++) | |
344 | if (m_array[i] == row) | |
345 | { | |
346 | start_pos = i; | |
347 | break; | |
348 | } | |
349 | m_array.RemoveAt( start_pos ); | |
350 | m_array.Add( row ); | |
351 | ||
352 | for (i = 0; i < len; i++) | |
353 | if (m_array[i] == row) | |
354 | { | |
355 | end_pos = i; | |
356 | break; | |
357 | } | |
358 | ||
359 | if (end_pos == start_pos) | |
360 | return wxDataViewListModel::ValueChanged( col, start_pos ); | |
361 | ||
362 | // Create an array where order[old] -> new_pos, so that | |
363 | // if nothing changed order[0] -> 0 etc. | |
364 | size_t *order = new size_t[ len ]; | |
365 | // Fill up initial values. | |
366 | for (i = 0; i < len; i++) | |
367 | order[i] = i; | |
368 | ||
369 | if (start_pos < end_pos) | |
370 | { | |
371 | for (i = start_pos; i < end_pos; i++) | |
372 | order[i] = order[i+1]; | |
373 | order[end_pos] = start_pos; | |
374 | } | |
375 | else | |
376 | { | |
377 | for (i = end_pos; i > start_pos; i--) | |
378 | order[i] = order[i-1]; | |
379 | order[start_pos] = end_pos; | |
380 | } | |
381 | ||
382 | wxDataViewListModel::RowsReordered( order ); | |
383 | ||
384 | delete [] order; | |
385 | ||
386 | return true; | |
387 | } | |
388 | ||
389 | size_t wxDataViewSortedListModel::GetNumberOfRows() | |
390 | { | |
391 | return m_array.GetCount(); | |
392 | } | |
393 | ||
394 | size_t wxDataViewSortedListModel::GetNumberOfCols() | |
395 | { | |
396 | return m_child->GetNumberOfCols(); | |
397 | } | |
398 | ||
399 | wxString wxDataViewSortedListModel::GetColType( size_t col ) | |
400 | { | |
401 | return m_child->GetColType( col ); | |
402 | } | |
403 | ||
404 | void wxDataViewSortedListModel::GetValue( wxVariant &variant, size_t col, size_t row ) | |
405 | { | |
406 | size_t child_row = m_array[row]; | |
407 | m_child->GetValue( variant, col, child_row ); | |
408 | } | |
409 | ||
410 | bool wxDataViewSortedListModel::SetValue( wxVariant &variant, size_t col, size_t row ) | |
411 | { | |
412 | size_t child_row = m_array[row]; | |
413 | bool ret = m_child->SetValue( variant, col, child_row ); | |
414 | ||
415 | // Resort in ::ChildValueChanged() which gets reported back. | |
416 | ||
417 | return ret; | |
418 | } | |
419 | ||
420 | bool wxDataViewSortedListModel::RowAppended() | |
421 | { | |
422 | // you can only append | |
423 | bool ret = m_child->RowAppended(); | |
424 | ||
425 | // report RowInsrted | |
426 | ||
427 | return ret; | |
428 | } | |
429 | ||
430 | bool wxDataViewSortedListModel::RowPrepended() | |
431 | { | |
432 | // you can only append | |
433 | bool ret = m_child->RowAppended(); | |
434 | ||
435 | // report RowInsrted | |
436 | ||
437 | return ret; | |
438 | } | |
439 | ||
440 | bool wxDataViewSortedListModel::RowInserted( size_t WXUNUSED(before) ) | |
441 | { | |
442 | // you can only append | |
443 | bool ret = m_child->RowAppended(); | |
444 | ||
445 | // report different RowInsrted | |
446 | ||
447 | return ret; | |
448 | } | |
449 | ||
450 | bool wxDataViewSortedListModel::RowDeleted( size_t row ) | |
451 | { | |
452 | size_t child_row = m_array[row]; | |
453 | ||
454 | bool ret = m_child->RowDeleted( child_row ); | |
455 | ||
456 | // Do nothing here as the change in the | |
457 | // child model will be reported back. | |
458 | ||
459 | return ret; | |
460 | } | |
461 | ||
462 | bool wxDataViewSortedListModel::RowChanged( size_t row ) | |
463 | { | |
464 | size_t child_row = m_array[row]; | |
465 | bool ret = m_child->RowChanged( child_row ); | |
466 | ||
467 | // Do nothing here as the change in the | |
468 | // child model will be reported back. | |
469 | ||
470 | return ret; | |
471 | } | |
472 | ||
473 | bool wxDataViewSortedListModel::ValueChanged( size_t col, size_t row ) | |
474 | { | |
475 | size_t child_row = m_array[row]; | |
476 | bool ret = m_child->ValueChanged( col, child_row ); | |
477 | ||
478 | // Do nothing here as the change in the | |
479 | // child model will be reported back. | |
480 | ||
481 | return ret; | |
482 | } | |
483 | ||
484 | bool wxDataViewSortedListModel::RowsReordered( size_t *WXUNUSED(new_order) ) | |
485 | { | |
486 | // We sort them ourselves. | |
487 | ||
488 | return false; | |
489 | } | |
490 | ||
491 | bool wxDataViewSortedListModel::Cleared() | |
492 | { | |
493 | bool ret = m_child->Cleared(); | |
494 | ||
495 | wxDataViewListModel::Cleared(); | |
496 | ||
497 | return ret; | |
498 | } | |
499 | ||
500 | // --------------------------------------------------------- | |
501 | // wxDataViewCellBase | |
502 | // --------------------------------------------------------- | |
503 | ||
504 | IMPLEMENT_ABSTRACT_CLASS(wxDataViewCellBase, wxObject) | |
505 | ||
506 | wxDataViewCellBase::wxDataViewCellBase( const wxString &varianttype, wxDataViewCellMode mode ) | |
507 | { | |
508 | m_variantType = varianttype; | |
509 | m_mode = mode; | |
510 | } | |
511 | ||
512 | // --------------------------------------------------------- | |
513 | // wxDataViewColumnBase | |
514 | // --------------------------------------------------------- | |
515 | ||
516 | IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumnBase, wxObject) | |
517 | ||
518 | wxDataViewColumnBase::wxDataViewColumnBase(const wxString& title, | |
519 | wxDataViewCell *cell, | |
520 | size_t model_column, | |
521 | int WXUNUSED(fixed_width), | |
522 | wxDataViewColumnSizing WXUNUSED(sizing), | |
523 | int flags ) | |
524 | { | |
525 | m_cell = cell; | |
526 | m_model_column = model_column; | |
527 | m_flags = flags; | |
528 | m_title = title; | |
529 | m_owner = NULL; | |
530 | m_cell->SetOwner( (wxDataViewColumn*) this ); | |
531 | } | |
532 | ||
533 | wxDataViewColumnBase::~wxDataViewColumnBase() | |
534 | { | |
535 | if (m_cell) | |
536 | delete m_cell; | |
537 | ||
538 | if (GetOwner()) | |
539 | { | |
540 | GetOwner()->GetModel()->RemoveViewingColumn( (wxDataViewColumn*) this ); | |
541 | } | |
542 | } | |
543 | ||
544 | void wxDataViewColumnBase::SetTitle( const wxString &title ) | |
545 | { | |
546 | m_title = title; | |
547 | } | |
548 | ||
549 | wxString wxDataViewColumnBase::GetTitle() | |
550 | { | |
551 | return m_title; | |
552 | } | |
553 | ||
554 | // --------------------------------------------------------- | |
555 | // wxDataViewCtrlBase | |
556 | // --------------------------------------------------------- | |
557 | ||
558 | IMPLEMENT_ABSTRACT_CLASS(wxDataViewCtrlBase, wxControl) | |
559 | ||
560 | wxDataViewCtrlBase::wxDataViewCtrlBase() | |
561 | { | |
562 | m_model = NULL; | |
563 | m_cols.DeleteContents( true ); | |
564 | } | |
565 | ||
566 | wxDataViewCtrlBase::~wxDataViewCtrlBase() | |
567 | { | |
568 | } | |
569 | ||
570 | bool wxDataViewCtrlBase::AssociateModel( wxDataViewListModel *model ) | |
571 | { | |
572 | m_model = model; | |
573 | ||
574 | return true; | |
575 | } | |
576 | ||
577 | wxDataViewListModel* wxDataViewCtrlBase::GetModel() | |
578 | { | |
579 | return m_model; | |
580 | } | |
581 | ||
582 | bool wxDataViewCtrlBase::AppendTextColumn( const wxString &label, size_t model_column ) | |
583 | { | |
584 | return AppendColumn( new wxDataViewColumn( label, new wxDataViewTextCell(), model_column ) ); | |
585 | } | |
586 | ||
587 | bool wxDataViewCtrlBase::AppendToggleColumn( const wxString &label, size_t model_column ) | |
588 | { | |
589 | return AppendColumn( new wxDataViewColumn( label, new wxDataViewToggleCell(), model_column, 30 ) ); | |
590 | } | |
591 | ||
592 | bool wxDataViewCtrlBase::AppendProgressColumn( const wxString &label, size_t model_column ) | |
593 | { | |
594 | return AppendColumn( new wxDataViewColumn( label, new wxDataViewProgressCell(), model_column, 70 ) ); | |
595 | } | |
596 | ||
597 | bool wxDataViewCtrlBase::AppendDateColumn( const wxString &label, size_t model_column ) | |
598 | { | |
599 | return AppendColumn( new wxDataViewColumn( label, new wxDataViewDateCell(), model_column ) ); | |
600 | } | |
601 | ||
602 | bool wxDataViewCtrlBase::AppendColumn( wxDataViewColumn *col ) | |
603 | { | |
604 | m_cols.Append( (wxObject*) col ); | |
605 | col->SetOwner( (wxDataViewCtrl*) this ); | |
606 | m_model->AddViewingColumn( col, col->GetModelColumn() ); | |
607 | return true; | |
608 | } | |
609 | ||
610 | size_t wxDataViewCtrlBase::GetNumberOfColumns() | |
611 | { | |
612 | return m_cols.GetCount(); | |
613 | } | |
614 | ||
615 | bool wxDataViewCtrlBase::DeleteColumn( size_t WXUNUSED(pos) ) | |
616 | { | |
617 | return false; | |
618 | } | |
619 | ||
620 | bool wxDataViewCtrlBase::ClearColumns() | |
621 | { | |
622 | return false; | |
623 | } | |
624 | ||
625 | wxDataViewColumn* wxDataViewCtrlBase::GetColumn( size_t pos ) | |
626 | { | |
627 | return (wxDataViewColumn*) m_cols[ pos ]; | |
628 | } | |
629 | ||
630 | #endif |