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