]> git.saurik.com Git - wxWidgets.git/blob - src/common/datavcmn.cpp
Renamed HasChildren() to IsContainer(), added GetParent() to wxDataViewModel
[wxWidgets.git] / src / common / datavcmn.cpp
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 bool operator == (const wxDataViewItem &left, const wxDataViewItem &right)
30 {
31 return (left.GetID() == right.GetID() );
32 }
33
34
35 // ---------------------------------------------------------
36 // wxDataViewModel
37 // ---------------------------------------------------------
38
39 wxDataViewModel::wxDataViewModel()
40 {
41 m_notifiers.DeleteContents( true );
42 m_sortingColumn = 0;
43 m_ascending = true;
44 }
45
46 bool wxDataViewModel::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
47 {
48 bool ret = true;
49
50 wxList::compatibility_iterator node = m_notifiers.GetFirst();
51 while (node)
52 {
53 wxDataViewModelNotifier* notifier = (wxDataViewModelNotifier*) node->GetData();
54 if (!notifier->ItemAdded( parent, item ))
55 ret = false;
56 node = node->GetNext();
57 }
58
59 return ret;
60 }
61
62 bool wxDataViewModel::ItemDeleted( const wxDataViewItem &item )
63 {
64 bool ret = true;
65
66 wxList::compatibility_iterator node = m_notifiers.GetFirst();
67 while (node)
68 {
69 wxDataViewModelNotifier* notifier = (wxDataViewModelNotifier*) node->GetData();
70 if (!notifier->ItemDeleted( item ))
71 ret = false;
72 node = node->GetNext();
73 }
74
75 return ret;
76 }
77
78 bool wxDataViewModel::ItemChanged( const wxDataViewItem &item )
79 {
80 bool ret = true;
81
82 wxList::compatibility_iterator node = m_notifiers.GetFirst();
83 while (node)
84 {
85 wxDataViewModelNotifier* notifier = (wxDataViewModelNotifier*) node->GetData();
86 if (!notifier->ItemChanged( item ))
87 ret = false;
88 node = node->GetNext();
89 }
90
91 return ret;
92 }
93
94 bool wxDataViewModel::ValueChanged( const wxDataViewItem &item, unsigned int col )
95 {
96 bool ret = true;
97
98 wxList::compatibility_iterator node = m_notifiers.GetFirst();
99 while (node)
100 {
101 wxDataViewModelNotifier* notifier = (wxDataViewModelNotifier*) node->GetData();
102 if (!notifier->ValueChanged( item, col ))
103 ret = false;
104 node = node->GetNext();
105 }
106
107 return ret;
108 }
109
110 bool wxDataViewModel::Cleared()
111 {
112 bool ret = true;
113
114 wxList::compatibility_iterator node = m_notifiers.GetFirst();
115 while (node)
116 {
117 wxDataViewModelNotifier* notifier = (wxDataViewModelNotifier*) node->GetData();
118 if (!notifier->Cleared())
119 ret = false;
120 node = node->GetNext();
121 }
122
123 return ret;
124 }
125
126 void wxDataViewModel::Resort()
127 {
128 wxList::compatibility_iterator node = m_notifiers.GetFirst();
129 while (node)
130 {
131 wxDataViewModelNotifier* notifier = (wxDataViewModelNotifier*) node->GetData();
132 notifier->Resort();
133 node = node->GetNext();
134 }
135 }
136
137 void wxDataViewModel::AddNotifier( wxDataViewModelNotifier *notifier )
138 {
139 m_notifiers.Append( notifier );
140 notifier->SetOwner( this );
141 }
142
143 void wxDataViewModel::RemoveNotifier( wxDataViewModelNotifier *notifier )
144 {
145 m_notifiers.DeleteObject( notifier );
146 }
147
148 int wxDataViewModel::Compare( const wxDataViewItem &item1, const wxDataViewItem &item2 )
149 {
150 // sort branches before leaves
151 bool item1_is_container = IsContainer(item1);
152 bool item2_is_container = IsContainer(item2);
153
154 if (item1_is_container && !item2_is_container)
155 return 1;
156 if (item2_is_container && !item1_is_container)
157 return -1;
158
159 wxVariant value1,value2;
160 GetValue( value1, item1, m_sortingColumn );
161 GetValue( value2, item2, m_sortingColumn );
162
163 if (!m_ascending)
164 {
165 wxVariant temp = value1;
166 value1 = value2;
167 value2 = temp;
168 }
169
170 if (value1.GetType() == wxT("string"))
171 {
172 wxString str1 = value1.GetString();
173 wxString str2 = value2.GetString();
174 int res = str1.Cmp( str2 );
175 if (res) return res;
176 } else
177 if (value1.GetType() == wxT("long"))
178 {
179 long l1 = value1.GetLong();
180 long l2 = value2.GetLong();
181 long res = l1-l2;
182 if (res) return res;
183 } else
184 if (value1.GetType() == wxT("double"))
185 {
186 double d1 = value1.GetDouble();
187 double d2 = value2.GetDouble();
188 if (d1 < d2) return 1;
189 if (d1 > d2) return -1;
190 } else
191 if (value1.GetType() == wxT("datetime"))
192 {
193 wxDateTime dt1 = value1.GetDateTime();
194 wxDateTime dt2 = value2.GetDateTime();
195 if (dt1.IsEarlierThan(dt2)) return 1;
196 if (dt2.IsEarlierThan(dt1)) return -11;
197 }
198
199 // items must be different
200 unsigned long litem1 = (unsigned long) item1.GetID();
201 unsigned long litem2 = (unsigned long) item2.GetID();
202
203 if (!m_ascending)
204 return litem2-litem1;
205 return litem1-litem2;
206 }
207
208 // ---------------------------------------------------------
209 // wxDataViewRendererBase
210 // ---------------------------------------------------------
211
212 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRendererBase, wxObject)
213
214 wxDataViewRendererBase::wxDataViewRendererBase( const wxString &varianttype,
215 wxDataViewCellMode WXUNUSED(mode),
216 int WXUNUSED(align) )
217 {
218 m_variantType = varianttype;
219 m_editorCtrl = NULL;
220 }
221
222 const wxDataViewCtrl* wxDataViewRendererBase::GetView() const
223 {
224 return wx_const_cast(wxDataViewRendererBase*, this)->GetOwner()->GetOwner();
225 }
226
227 bool wxDataViewRendererBase::StartEditing( const wxDataViewItem &item, wxRect labelRect )
228 {
229 m_item = item; // remember for later
230
231 unsigned int col = GetOwner()->GetModelColumn();
232 wxVariant value;
233 GetOwner()->GetOwner()->GetModel()->GetValue( value, item, col );
234
235 m_editorCtrl = CreateEditorCtrl( GetOwner()->GetOwner()->GetMainWindow(), labelRect, value );
236
237 wxDataViewEditorCtrlEvtHandler *handler =
238 new wxDataViewEditorCtrlEvtHandler( m_editorCtrl, (wxDataViewRenderer*) this );
239
240 m_editorCtrl->PushEventHandler( handler );
241
242 #if defined(__WXGTK20__) && !defined(wxUSE_GENERICDATAVIEWCTRL)
243 handler->SetFocusOnIdle();
244 #else
245 m_editorCtrl->SetFocus();
246 #endif
247
248 return true;
249 }
250
251 void wxDataViewRendererBase::CancelEditing()
252 {
253 wxPendingDelete.Append( m_editorCtrl );
254
255 GetOwner()->GetOwner()->GetMainWindow()->SetFocus();
256
257 // m_editorCtrl->PopEventHandler( true );
258 }
259
260 bool wxDataViewRendererBase::FinishEditing()
261 {
262 wxVariant value;
263 GetValueFromEditorCtrl( m_editorCtrl, value );
264
265 wxPendingDelete.Append( m_editorCtrl );
266
267 GetOwner()->GetOwner()->GetMainWindow()->SetFocus();
268
269 if (!Validate(value))
270 return false;
271
272 unsigned int col = GetOwner()->GetModelColumn();
273 GetOwner()->GetOwner()->GetModel()->SetValue( value, m_item, col );
274 GetOwner()->GetOwner()->GetModel()->ValueChanged( m_item, col );
275
276 // m_editorCtrl->PopEventHandler( true );
277
278 return true;
279 }
280
281 //-----------------------------------------------------------------------------
282 // wxDataViewEditorCtrlEvtHandler
283 //-----------------------------------------------------------------------------
284
285 BEGIN_EVENT_TABLE(wxDataViewEditorCtrlEvtHandler, wxEvtHandler)
286 EVT_CHAR (wxDataViewEditorCtrlEvtHandler::OnChar)
287 EVT_KILL_FOCUS (wxDataViewEditorCtrlEvtHandler::OnKillFocus)
288 EVT_IDLE (wxDataViewEditorCtrlEvtHandler::OnIdle)
289 END_EVENT_TABLE()
290
291 wxDataViewEditorCtrlEvtHandler::wxDataViewEditorCtrlEvtHandler(
292 wxControl *editorCtrl,
293 wxDataViewRenderer *owner )
294 {
295 m_owner = owner;
296 m_editorCtrl = editorCtrl;
297
298 m_finished = false;
299 }
300
301 void wxDataViewEditorCtrlEvtHandler::OnIdle( wxIdleEvent &event )
302 {
303 if (m_focusOnIdle)
304 {
305 m_focusOnIdle = false;
306 if (wxWindow::FindFocus() != m_editorCtrl)
307 m_editorCtrl->SetFocus();
308 }
309
310 event.Skip();
311 }
312
313 void wxDataViewEditorCtrlEvtHandler::OnChar( wxKeyEvent &event )
314 {
315 switch ( event.m_keyCode )
316 {
317 case WXK_RETURN:
318 m_finished = true;
319 m_owner->FinishEditing();
320 break;
321
322 case WXK_ESCAPE:
323 m_finished = true;
324 m_owner->CancelEditing();
325 break;
326
327 default:
328 event.Skip();
329 }
330 }
331
332 void wxDataViewEditorCtrlEvtHandler::OnKillFocus( wxFocusEvent &event )
333 {
334 if (!m_finished)
335 {
336 m_finished = true;
337 m_owner->FinishEditing();
338 }
339
340 event.Skip();
341 }
342
343 // ---------------------------------------------------------
344 // wxDataViewColumnBase
345 // ---------------------------------------------------------
346
347 IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumnBase, wxObject)
348
349 wxDataViewColumnBase::wxDataViewColumnBase(const wxString& WXUNUSED(title),
350 wxDataViewRenderer *renderer,
351 unsigned int model_column,
352 int WXUNUSED(width),
353 wxAlignment WXUNUSED(align),
354 int WXUNUSED(flags))
355 {
356 m_renderer = renderer;
357 m_model_column = model_column;
358 m_owner = NULL;
359 m_renderer->SetOwner( (wxDataViewColumn*) this );
360
361 // NOTE: the wxDataViewColumn's ctor must store the width, align, flags
362 // parameters inside the native control!
363 }
364
365 wxDataViewColumnBase::wxDataViewColumnBase(const wxBitmap& bitmap,
366 wxDataViewRenderer *renderer,
367 unsigned int model_column,
368 int WXUNUSED(width),
369 wxAlignment WXUNUSED(align),
370 int WXUNUSED(flags) )
371 {
372 m_renderer = renderer;
373 m_model_column = model_column;
374 m_bitmap = bitmap;
375 m_owner = NULL;
376 m_renderer->SetOwner( (wxDataViewColumn*) this );
377 }
378
379 wxDataViewColumnBase::~wxDataViewColumnBase()
380 {
381 if (m_renderer)
382 delete m_renderer;
383 }
384
385 int wxDataViewColumnBase::GetFlags() const
386 {
387 int ret = 0;
388
389 if (IsSortable())
390 ret |= wxDATAVIEW_COL_SORTABLE;
391 if (IsResizeable())
392 ret |= wxDATAVIEW_COL_RESIZABLE;
393 if (IsHidden())
394 ret |= wxDATAVIEW_COL_HIDDEN;
395
396 return ret;
397 }
398
399 void wxDataViewColumnBase::SetFlags(int flags)
400 {
401 SetSortable((flags & wxDATAVIEW_COL_SORTABLE) != 0);
402 SetResizeable((flags & wxDATAVIEW_COL_RESIZABLE) != 0);
403 SetHidden((flags & wxDATAVIEW_COL_HIDDEN) != 0);
404 }
405
406 // ---------------------------------------------------------
407 // wxDataViewEventModelNotifier
408 // ---------------------------------------------------------
409
410 class WXDLLIMPEXP_ADV wxDataViewEventModelNotifier: public wxDataViewModelNotifier
411 {
412 public:
413 wxDataViewEventModelNotifier( wxDataViewCtrl *ctrl ) { m_ctrl = ctrl; }
414
415 bool SendEvent( wxEventType event_type, const wxDataViewItem &item, unsigned int col = 0 )
416 {
417 wxDataViewEvent event( event_type, m_ctrl->GetId() );
418 event.SetEventObject( m_ctrl );
419 event.SetModel( m_ctrl->GetModel() );
420 event.SetItem( item );
421 event.SetColumn( col );
422 m_ctrl->GetEventHandler()->ProcessEvent( event );
423 return true;
424 }
425
426 virtual bool ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
427 { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_ADDED, item ); }
428 virtual bool ItemDeleted( const wxDataViewItem &item )
429 { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_DELETED, item ); }
430 virtual bool ItemChanged( const wxDataViewItem &item )
431 { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_CHANGED, item ); }
432 virtual bool ValueChanged( const wxDataViewItem &item, unsigned int col )
433 { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_VALUE_CHANGED, item, col ); }
434 virtual bool Cleared()
435 { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_CLEARED, wxDataViewItem(0) ); }
436
437 private:
438 wxDataViewCtrl *m_ctrl;
439 };
440
441
442 // ---------------------------------------------------------
443 // wxDataViewCtrlBase
444 // ---------------------------------------------------------
445
446 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCtrlBase, wxControl)
447
448 wxDataViewCtrlBase::wxDataViewCtrlBase()
449 {
450 m_model = NULL;
451 m_cols.DeleteContents( true );
452 m_eventNotifier = NULL;
453 m_expander_column = 0;
454 m_indent = 8;
455 }
456
457 wxDataViewCtrlBase::~wxDataViewCtrlBase()
458 {
459 // IMPORTANT: before calling DecRef() on our model (since it may
460 // result in a free() call), erase all columns (since
461 // they hold a pointer to our model)
462 m_cols.Clear();
463
464 if (m_model)
465 {
466 if (m_eventNotifier)
467 m_model->RemoveNotifier( m_eventNotifier );
468 m_eventNotifier = NULL;
469
470 m_model->DecRef();
471 m_model = NULL;
472 }
473 }
474
475 bool wxDataViewCtrlBase::AssociateModel( wxDataViewModel *model )
476 {
477 if (m_model)
478 {
479 if (m_eventNotifier)
480 m_model->RemoveNotifier( m_eventNotifier );
481 m_eventNotifier = NULL;
482
483 m_model->DecRef(); // discard old model, if any
484 }
485
486 // add our own reference to the new model:
487 m_model = model;
488 if (m_model)
489 {
490 m_model->IncRef();
491 m_eventNotifier = new wxDataViewEventModelNotifier( (wxDataViewCtrl*) this );
492 m_model->AddNotifier( m_eventNotifier );
493 }
494
495 return true;
496 }
497
498 wxDataViewModel* wxDataViewCtrlBase::GetModel()
499 {
500 return m_model;
501 }
502
503 bool wxDataViewCtrlBase::AppendTextColumn( const wxString &label, unsigned int model_column,
504 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
505 {
506 return AppendColumn( new wxDataViewColumn( label,
507 new wxDataViewTextRenderer( wxT("string"), mode, (int)align ),
508 model_column, width, align, flags ) );
509 }
510
511 bool wxDataViewCtrlBase::AppendToggleColumn( const wxString &label, unsigned int model_column,
512 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
513 {
514 return AppendColumn( new wxDataViewColumn( label,
515 new wxDataViewToggleRenderer( wxT("bool"), mode, (int)align ),
516 model_column, width, align, flags ) );
517 }
518
519 bool wxDataViewCtrlBase::AppendProgressColumn( const wxString &label, unsigned int model_column,
520 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
521 {
522 return AppendColumn( new wxDataViewColumn( label,
523 new wxDataViewProgressRenderer( wxEmptyString, wxT("long"), mode, (int)align ),
524 model_column, width, align, flags ) );
525 }
526
527 bool wxDataViewCtrlBase::AppendDateColumn( const wxString &label, unsigned int model_column,
528 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
529 {
530 return AppendColumn( new wxDataViewColumn( label,
531 new wxDataViewDateRenderer( wxT("datetime"), mode, (int)align ),
532 model_column, width, align, flags ) );
533 }
534
535 bool wxDataViewCtrlBase::AppendBitmapColumn( const wxString &label, unsigned int model_column,
536 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
537 {
538 return AppendColumn( new wxDataViewColumn( label,
539 new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode, (int)align ),
540 model_column, width, align, flags ) );
541 }
542
543 bool wxDataViewCtrlBase::AppendTextColumn( const wxBitmap &label, unsigned int model_column,
544 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
545 {
546 return AppendColumn( new wxDataViewColumn( label,
547 new wxDataViewTextRenderer( wxT("string"), mode, (int)align ),
548 model_column, width, align, flags ) );
549 }
550
551 bool wxDataViewCtrlBase::AppendToggleColumn( const wxBitmap &label, unsigned int model_column,
552 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
553 {
554 return AppendColumn( new wxDataViewColumn( label,
555 new wxDataViewToggleRenderer( wxT("bool"), mode, (int)align ),
556 model_column, width, align, flags ) );
557 }
558
559 bool wxDataViewCtrlBase::AppendProgressColumn( const wxBitmap &label, unsigned int model_column,
560 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
561 {
562 return AppendColumn( new wxDataViewColumn( label,
563 new wxDataViewProgressRenderer( wxEmptyString, wxT("long"), mode, (int)align ),
564 model_column, width, align, flags ) );
565 }
566
567 bool wxDataViewCtrlBase::AppendDateColumn( const wxBitmap &label, unsigned int model_column,
568 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
569 {
570 return AppendColumn( new wxDataViewColumn( label,
571 new wxDataViewDateRenderer( wxT("datetime"), mode, (int)align ),
572 model_column, width, align, flags ) );
573 }
574
575 bool wxDataViewCtrlBase::AppendBitmapColumn( const wxBitmap &label, unsigned int model_column,
576 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
577 {
578 return AppendColumn( new wxDataViewColumn( label,
579 new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode, (int)align ),
580 model_column, width, align, flags ) );
581 }
582
583 bool wxDataViewCtrlBase::AppendColumn( wxDataViewColumn *col )
584 {
585 m_cols.Append( (wxObject*) col );
586 col->SetOwner( (wxDataViewCtrl*) this );
587 return true;
588 }
589
590 unsigned int wxDataViewCtrlBase::GetColumnCount() const
591 {
592 return m_cols.GetCount();
593 }
594
595 bool wxDataViewCtrlBase::DeleteColumn( unsigned int WXUNUSED(pos) )
596 {
597 return false;
598 }
599
600 bool wxDataViewCtrlBase::ClearColumns()
601 {
602 return false;
603 }
604
605 wxDataViewColumn* wxDataViewCtrlBase::GetColumn( unsigned int pos )
606 {
607 return (wxDataViewColumn*) m_cols[ pos ];
608 }
609
610 // ---------------------------------------------------------
611 // wxDataViewEvent
612 // ---------------------------------------------------------
613
614 IMPLEMENT_DYNAMIC_CLASS(wxDataViewEvent,wxNotifyEvent)
615
616 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ITEM_SELECTED)
617 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED)
618 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK)
619 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK)
620 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED)
621
622 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_ADDED)
623 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_DELETED)
624 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_CHANGED)
625 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_MODEL_VALUE_CHANGED)
626 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_MODEL_CLEARED)
627
628 #endif