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