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