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