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