1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/datavcmn.cpp
3 // Purpose: wxDataViewCtrl base classes and common parts
4 // Author: Robert Roebling
7 // Copyright: (c) 2006, Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
18 #if wxUSE_DATAVIEWCTRL
20 #include "wx/dataview.h"
26 const wxChar wxDataViewCtrlNameStr
[] = wxT("dataviewCtrl");
29 bool operator == (const wxDataViewItem
&left
, const wxDataViewItem
&right
)
31 return (left
.GetID() == right
.GetID() );
35 // ---------------------------------------------------------
37 // ---------------------------------------------------------
39 wxDataViewModel::wxDataViewModel()
41 m_notifiers
.DeleteContents( true );
46 bool wxDataViewModel::ItemAdded( const wxDataViewItem
&parent
, const wxDataViewItem
&item
)
50 wxList::compatibility_iterator node
= m_notifiers
.GetFirst();
53 wxDataViewModelNotifier
* notifier
= (wxDataViewModelNotifier
*) node
->GetData();
54 if (!notifier
->ItemAdded( parent
, item
))
56 node
= node
->GetNext();
62 bool wxDataViewModel::ItemDeleted( const wxDataViewItem
&item
)
66 wxList::compatibility_iterator node
= m_notifiers
.GetFirst();
69 wxDataViewModelNotifier
* notifier
= (wxDataViewModelNotifier
*) node
->GetData();
70 if (!notifier
->ItemDeleted( item
))
72 node
= node
->GetNext();
78 bool wxDataViewModel::ItemChanged( const wxDataViewItem
&item
)
82 wxList::compatibility_iterator node
= m_notifiers
.GetFirst();
85 wxDataViewModelNotifier
* notifier
= (wxDataViewModelNotifier
*) node
->GetData();
86 if (!notifier
->ItemChanged( item
))
88 node
= node
->GetNext();
94 bool wxDataViewModel::ValueChanged( const wxDataViewItem
&item
, unsigned int col
)
98 wxList::compatibility_iterator node
= m_notifiers
.GetFirst();
101 wxDataViewModelNotifier
* notifier
= (wxDataViewModelNotifier
*) node
->GetData();
102 if (!notifier
->ValueChanged( item
, col
))
104 node
= node
->GetNext();
110 bool wxDataViewModel::Cleared()
114 wxList::compatibility_iterator node
= m_notifiers
.GetFirst();
117 wxDataViewModelNotifier
* notifier
= (wxDataViewModelNotifier
*) node
->GetData();
118 if (!notifier
->Cleared())
120 node
= node
->GetNext();
126 void wxDataViewModel::Resort()
128 wxList::compatibility_iterator node
= m_notifiers
.GetFirst();
131 wxDataViewModelNotifier
* notifier
= (wxDataViewModelNotifier
*) node
->GetData();
133 node
= node
->GetNext();
137 void wxDataViewModel::AddNotifier( wxDataViewModelNotifier
*notifier
)
139 m_notifiers
.Append( notifier
);
140 notifier
->SetOwner( this );
143 void wxDataViewModel::RemoveNotifier( wxDataViewModelNotifier
*notifier
)
145 m_notifiers
.DeleteObject( notifier
);
148 int wxDataViewModel::Compare( const wxDataViewItem
&item1
, const wxDataViewItem
&item2
)
150 // sort branches before leaves
151 bool item1_is_container
= IsContainer(item1
);
152 bool item2_is_container
= IsContainer(item2
);
154 if (item1_is_container
&& !item2_is_container
)
156 if (item2_is_container
&& !item1_is_container
)
159 wxVariant value1
,value2
;
160 GetValue( value1
, item1
, m_sortingColumn
);
161 GetValue( value2
, item2
, m_sortingColumn
);
165 wxVariant temp
= value1
;
170 if (value1
.GetType() == wxT("string"))
172 wxString str1
= value1
.GetString();
173 wxString str2
= value2
.GetString();
174 int res
= str1
.Cmp( str2
);
177 if (value1
.GetType() == wxT("long"))
179 long l1
= value1
.GetLong();
180 long l2
= value2
.GetLong();
184 if (value1
.GetType() == wxT("double"))
186 double d1
= value1
.GetDouble();
187 double d2
= value2
.GetDouble();
188 if (d1
< d2
) return 1;
189 if (d1
> d2
) return -1;
191 if (value1
.GetType() == wxT("datetime"))
193 wxDateTime dt1
= value1
.GetDateTime();
194 wxDateTime dt2
= value2
.GetDateTime();
195 if (dt1
.IsEarlierThan(dt2
)) return 1;
196 if (dt2
.IsEarlierThan(dt1
)) return -11;
199 // items must be different
200 unsigned long litem1
= (unsigned long) item1
.GetID();
201 unsigned long litem2
= (unsigned long) item2
.GetID();
204 return litem2
-litem1
;
205 return litem1
-litem2
;
208 // ---------------------------------------------------------
209 // wxDataViewIndexListModel
210 // ---------------------------------------------------------
212 wxDataViewIndexListModel::wxDataViewIndexListModel( unsigned int initial_size
)
214 // build initial index
216 for (i
= 1; i
< initial_size
+1; i
++)
217 m_hash
.Add( (void*) i
);
218 m_lastIndex
= initial_size
+ 1;
221 wxDataViewIndexListModel::~wxDataViewIndexListModel()
225 void wxDataViewIndexListModel::RowPrepended()
227 unsigned int id
= m_lastIndex
++;
228 m_hash
.Insert( (void*) id
, 0 );
229 wxDataViewItem
item( (void*) id
);
230 ItemAdded( wxDataViewItem(0), item
);
233 void wxDataViewIndexListModel::RowInserted( unsigned int before
)
235 unsigned int id
= m_lastIndex
++;
236 m_hash
.Insert( (void*) id
, before
);
237 wxDataViewItem
item( (void*) id
);
238 ItemAdded( wxDataViewItem(0), item
);
241 void wxDataViewIndexListModel::RowAppended()
243 unsigned int id
= m_lastIndex
++;
244 m_hash
.Add( (void*) id
);
245 wxDataViewItem
item( (void*) id
);
246 ItemAdded( wxDataViewItem(0), item
);
249 void wxDataViewIndexListModel::RowDeleted( unsigned int row
)
251 wxDataViewItem
item( m_hash
[row
] );
252 m_hash
.RemoveAt( row
);
253 wxDataViewModel::ItemDeleted( item
);
256 void wxDataViewIndexListModel::RowChanged( unsigned int row
)
258 wxDataViewModel::ItemChanged( GetItem(row
) );
261 void wxDataViewIndexListModel::RowValueChanged( unsigned int row
, unsigned int col
)
263 wxDataViewModel::ValueChanged( GetItem(row
), col
);
266 unsigned int wxDataViewIndexListModel::GetRow( const wxDataViewItem
&item
) const
268 // assert for not found
269 return (unsigned int) m_hash
.Index( item
.GetID() );
272 wxDataViewItem
wxDataViewIndexListModel::GetItem( unsigned int row
) const
274 return wxDataViewItem( m_hash
[row
] );
277 int wxDataViewIndexListModel::Compare( const wxDataViewItem
&item1
, const wxDataViewItem
&item2
)
279 return GetRow(item1
) - GetRow(item2
);
282 void wxDataViewIndexListModel::GetValue( wxVariant
&variant
,
283 const wxDataViewItem
&item
, unsigned int col
) const
285 return GetValue( variant
, GetRow(item
), col
);
288 bool wxDataViewIndexListModel::SetValue( const wxVariant
&variant
,
289 const wxDataViewItem
&item
, unsigned int col
)
291 return SetValue( variant
, GetRow(item
), col
);
294 wxDataViewItem
wxDataViewIndexListModel::GetParent( const wxDataViewItem
&item
) const
296 return wxDataViewItem(0);
299 bool wxDataViewIndexListModel::IsContainer( const wxDataViewItem
&item
) const
301 // only the invisible root item has children
308 wxDataViewItem
wxDataViewIndexListModel::GetFirstChild( const wxDataViewItem
&parent
) const
312 if (m_hash
.GetCount() == 0)
313 return wxDataViewItem(0);
315 return wxDataViewItem( m_hash
[0]);
318 return wxDataViewItem(0);
321 wxDataViewItem
wxDataViewIndexListModel::GetNextSibling( const wxDataViewItem
&item
) const
324 return wxDataViewItem(0);
326 int pos
= m_hash
.Index( item
.GetID() );
327 if ((pos
== wxNOT_FOUND
) || (pos
== m_hash
.GetCount()-1))
328 return wxDataViewItem(0);
330 return wxDataViewItem( m_hash
[pos
+1] );
333 // ---------------------------------------------------------
334 // wxDataViewRendererBase
335 // ---------------------------------------------------------
337 IMPLEMENT_ABSTRACT_CLASS(wxDataViewRendererBase
, wxObject
)
339 wxDataViewRendererBase::wxDataViewRendererBase( const wxString
&varianttype
,
340 wxDataViewCellMode
WXUNUSED(mode
),
341 int WXUNUSED(align
) )
343 m_variantType
= varianttype
;
347 const wxDataViewCtrl
* wxDataViewRendererBase::GetView() const
349 return wx_const_cast(wxDataViewRendererBase
*, this)->GetOwner()->GetOwner();
352 bool wxDataViewRendererBase::StartEditing( const wxDataViewItem
&item
, wxRect labelRect
)
354 m_item
= item
; // remember for later
356 unsigned int col
= GetOwner()->GetModelColumn();
358 GetOwner()->GetOwner()->GetModel()->GetValue( value
, item
, col
);
360 m_editorCtrl
= CreateEditorCtrl( GetOwner()->GetOwner()->GetMainWindow(), labelRect
, value
);
362 wxDataViewEditorCtrlEvtHandler
*handler
=
363 new wxDataViewEditorCtrlEvtHandler( m_editorCtrl
, (wxDataViewRenderer
*) this );
365 m_editorCtrl
->PushEventHandler( handler
);
367 #if defined(__WXGTK20__) && !defined(wxUSE_GENERICDATAVIEWCTRL)
368 handler
->SetFocusOnIdle();
370 m_editorCtrl
->SetFocus();
376 void wxDataViewRendererBase::CancelEditing()
378 wxPendingDelete
.Append( m_editorCtrl
);
380 GetOwner()->GetOwner()->GetMainWindow()->SetFocus();
382 // m_editorCtrl->PopEventHandler( true );
385 bool wxDataViewRendererBase::FinishEditing()
388 GetValueFromEditorCtrl( m_editorCtrl
, value
);
390 wxPendingDelete
.Append( m_editorCtrl
);
392 GetOwner()->GetOwner()->GetMainWindow()->SetFocus();
394 if (!Validate(value
))
397 unsigned int col
= GetOwner()->GetModelColumn();
398 GetOwner()->GetOwner()->GetModel()->SetValue( value
, m_item
, col
);
399 GetOwner()->GetOwner()->GetModel()->ValueChanged( m_item
, col
);
401 // m_editorCtrl->PopEventHandler( true );
406 //-----------------------------------------------------------------------------
407 // wxDataViewEditorCtrlEvtHandler
408 //-----------------------------------------------------------------------------
410 BEGIN_EVENT_TABLE(wxDataViewEditorCtrlEvtHandler
, wxEvtHandler
)
411 EVT_CHAR (wxDataViewEditorCtrlEvtHandler::OnChar
)
412 EVT_KILL_FOCUS (wxDataViewEditorCtrlEvtHandler::OnKillFocus
)
413 EVT_IDLE (wxDataViewEditorCtrlEvtHandler::OnIdle
)
416 wxDataViewEditorCtrlEvtHandler::wxDataViewEditorCtrlEvtHandler(
417 wxControl
*editorCtrl
,
418 wxDataViewRenderer
*owner
)
421 m_editorCtrl
= editorCtrl
;
426 void wxDataViewEditorCtrlEvtHandler::OnIdle( wxIdleEvent
&event
)
430 m_focusOnIdle
= false;
431 if (wxWindow::FindFocus() != m_editorCtrl
)
432 m_editorCtrl
->SetFocus();
438 void wxDataViewEditorCtrlEvtHandler::OnChar( wxKeyEvent
&event
)
440 switch ( event
.m_keyCode
)
444 m_owner
->FinishEditing();
449 m_owner
->CancelEditing();
457 void wxDataViewEditorCtrlEvtHandler::OnKillFocus( wxFocusEvent
&event
)
462 m_owner
->FinishEditing();
468 // ---------------------------------------------------------
469 // wxDataViewColumnBase
470 // ---------------------------------------------------------
472 IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumnBase
, wxObject
)
474 wxDataViewColumnBase::wxDataViewColumnBase(const wxString
& WXUNUSED(title
),
475 wxDataViewRenderer
*renderer
,
476 unsigned int model_column
,
478 wxAlignment
WXUNUSED(align
),
481 m_renderer
= renderer
;
482 m_model_column
= model_column
;
484 m_renderer
->SetOwner( (wxDataViewColumn
*) this );
486 // NOTE: the wxDataViewColumn's ctor must store the width, align, flags
487 // parameters inside the native control!
490 wxDataViewColumnBase::wxDataViewColumnBase(const wxBitmap
& bitmap
,
491 wxDataViewRenderer
*renderer
,
492 unsigned int model_column
,
494 wxAlignment
WXUNUSED(align
),
495 int WXUNUSED(flags
) )
497 m_renderer
= renderer
;
498 m_model_column
= model_column
;
501 m_renderer
->SetOwner( (wxDataViewColumn
*) this );
504 wxDataViewColumnBase::~wxDataViewColumnBase()
510 int wxDataViewColumnBase::GetFlags() const
515 ret
|= wxDATAVIEW_COL_SORTABLE
;
517 ret
|= wxDATAVIEW_COL_RESIZABLE
;
519 ret
|= wxDATAVIEW_COL_HIDDEN
;
524 void wxDataViewColumnBase::SetFlags(int flags
)
526 SetSortable((flags
& wxDATAVIEW_COL_SORTABLE
) != 0);
527 SetResizeable((flags
& wxDATAVIEW_COL_RESIZABLE
) != 0);
528 SetHidden((flags
& wxDATAVIEW_COL_HIDDEN
) != 0);
531 // ---------------------------------------------------------
532 // wxDataViewEventModelNotifier
533 // ---------------------------------------------------------
535 class WXDLLIMPEXP_ADV wxDataViewEventModelNotifier
: public wxDataViewModelNotifier
538 wxDataViewEventModelNotifier( wxDataViewCtrl
*ctrl
) { m_ctrl
= ctrl
; }
540 bool SendEvent( wxEventType event_type
, const wxDataViewItem
&item
, unsigned int col
= 0 )
542 wxDataViewEvent
event( event_type
, m_ctrl
->GetId() );
543 event
.SetEventObject( m_ctrl
);
544 event
.SetModel( m_ctrl
->GetModel() );
545 event
.SetItem( item
);
546 event
.SetColumn( col
);
547 m_ctrl
->GetEventHandler()->ProcessEvent( event
);
551 virtual bool ItemAdded( const wxDataViewItem
&parent
, const wxDataViewItem
&item
)
552 { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_ADDED
, item
); }
553 virtual bool ItemDeleted( const wxDataViewItem
&item
)
554 { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_DELETED
, item
); }
555 virtual bool ItemChanged( const wxDataViewItem
&item
)
556 { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_CHANGED
, item
); }
557 virtual bool ValueChanged( const wxDataViewItem
&item
, unsigned int col
)
558 { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_VALUE_CHANGED
, item
, col
); }
559 virtual bool Cleared()
560 { return SendEvent( wxEVT_COMMAND_DATAVIEW_MODEL_CLEARED
, wxDataViewItem(0) ); }
563 wxDataViewCtrl
*m_ctrl
;
567 // ---------------------------------------------------------
568 // wxDataViewCtrlBase
569 // ---------------------------------------------------------
571 IMPLEMENT_ABSTRACT_CLASS(wxDataViewCtrlBase
, wxControl
)
573 wxDataViewCtrlBase::wxDataViewCtrlBase()
576 m_cols
.DeleteContents( true );
577 m_eventNotifier
= NULL
;
578 m_expander_column
= 0;
582 wxDataViewCtrlBase::~wxDataViewCtrlBase()
584 // IMPORTANT: before calling DecRef() on our model (since it may
585 // result in a free() call), erase all columns (since
586 // they hold a pointer to our model)
592 m_model
->RemoveNotifier( m_eventNotifier
);
593 m_eventNotifier
= NULL
;
600 bool wxDataViewCtrlBase::AssociateModel( wxDataViewModel
*model
)
605 m_model
->RemoveNotifier( m_eventNotifier
);
606 m_eventNotifier
= NULL
;
608 m_model
->DecRef(); // discard old model, if any
611 // add our own reference to the new model:
616 m_eventNotifier
= new wxDataViewEventModelNotifier( (wxDataViewCtrl
*) this );
617 m_model
->AddNotifier( m_eventNotifier
);
623 wxDataViewModel
* wxDataViewCtrlBase::GetModel()
628 bool wxDataViewCtrlBase::AppendTextColumn( const wxString
&label
, unsigned int model_column
,
629 wxDataViewCellMode mode
, int width
, wxAlignment align
, int flags
)
631 return AppendColumn( new wxDataViewColumn( label
,
632 new wxDataViewTextRenderer( wxT("string"), mode
, (int)align
),
633 model_column
, width
, align
, flags
) );
636 bool wxDataViewCtrlBase::AppendToggleColumn( const wxString
&label
, unsigned int model_column
,
637 wxDataViewCellMode mode
, int width
, wxAlignment align
, int flags
)
639 return AppendColumn( new wxDataViewColumn( label
,
640 new wxDataViewToggleRenderer( wxT("bool"), mode
, (int)align
),
641 model_column
, width
, align
, flags
) );
644 bool wxDataViewCtrlBase::AppendProgressColumn( const wxString
&label
, unsigned int model_column
,
645 wxDataViewCellMode mode
, int width
, wxAlignment align
, int flags
)
647 return AppendColumn( new wxDataViewColumn( label
,
648 new wxDataViewProgressRenderer( wxEmptyString
, wxT("long"), mode
, (int)align
),
649 model_column
, width
, align
, flags
) );
652 bool wxDataViewCtrlBase::AppendDateColumn( const wxString
&label
, unsigned int model_column
,
653 wxDataViewCellMode mode
, int width
, wxAlignment align
, int flags
)
655 return AppendColumn( new wxDataViewColumn( label
,
656 new wxDataViewDateRenderer( wxT("datetime"), mode
, (int)align
),
657 model_column
, width
, align
, flags
) );
660 bool wxDataViewCtrlBase::AppendBitmapColumn( const wxString
&label
, unsigned int model_column
,
661 wxDataViewCellMode mode
, int width
, wxAlignment align
, int flags
)
663 return AppendColumn( new wxDataViewColumn( label
,
664 new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode
, (int)align
),
665 model_column
, width
, align
, flags
) );
668 bool wxDataViewCtrlBase::AppendTextColumn( const wxBitmap
&label
, unsigned int model_column
,
669 wxDataViewCellMode mode
, int width
, wxAlignment align
, int flags
)
671 return AppendColumn( new wxDataViewColumn( label
,
672 new wxDataViewTextRenderer( wxT("string"), mode
, (int)align
),
673 model_column
, width
, align
, flags
) );
676 bool wxDataViewCtrlBase::AppendToggleColumn( const wxBitmap
&label
, unsigned int model_column
,
677 wxDataViewCellMode mode
, int width
, wxAlignment align
, int flags
)
679 return AppendColumn( new wxDataViewColumn( label
,
680 new wxDataViewToggleRenderer( wxT("bool"), mode
, (int)align
),
681 model_column
, width
, align
, flags
) );
684 bool wxDataViewCtrlBase::AppendProgressColumn( const wxBitmap
&label
, unsigned int model_column
,
685 wxDataViewCellMode mode
, int width
, wxAlignment align
, int flags
)
687 return AppendColumn( new wxDataViewColumn( label
,
688 new wxDataViewProgressRenderer( wxEmptyString
, wxT("long"), mode
, (int)align
),
689 model_column
, width
, align
, flags
) );
692 bool wxDataViewCtrlBase::AppendDateColumn( const wxBitmap
&label
, unsigned int model_column
,
693 wxDataViewCellMode mode
, int width
, wxAlignment align
, int flags
)
695 return AppendColumn( new wxDataViewColumn( label
,
696 new wxDataViewDateRenderer( wxT("datetime"), mode
, (int)align
),
697 model_column
, width
, align
, flags
) );
700 bool wxDataViewCtrlBase::AppendBitmapColumn( const wxBitmap
&label
, unsigned int model_column
,
701 wxDataViewCellMode mode
, int width
, wxAlignment align
, int flags
)
703 return AppendColumn( new wxDataViewColumn( label
,
704 new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode
, (int)align
),
705 model_column
, width
, align
, flags
) );
708 bool wxDataViewCtrlBase::AppendColumn( wxDataViewColumn
*col
)
710 m_cols
.Append( (wxObject
*) col
);
711 col
->SetOwner( (wxDataViewCtrl
*) this );
715 unsigned int wxDataViewCtrlBase::GetColumnCount() const
717 return m_cols
.GetCount();
720 bool wxDataViewCtrlBase::DeleteColumn( unsigned int WXUNUSED(pos
) )
725 bool wxDataViewCtrlBase::ClearColumns()
730 wxDataViewColumn
* wxDataViewCtrlBase::GetColumn( unsigned int pos
)
732 return (wxDataViewColumn
*) m_cols
[ pos
];
735 // ---------------------------------------------------------
737 // ---------------------------------------------------------
739 IMPLEMENT_DYNAMIC_CLASS(wxDataViewEvent
,wxNotifyEvent
)
741 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ITEM_SELECTED
)
742 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED
)
743 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK
)
744 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK
)
745 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED
)
747 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_ADDED
)
748 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_DELETED
)
749 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_MODEL_ITEM_CHANGED
)
750 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_MODEL_VALUE_CHANGED
)
751 DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_MODEL_CLEARED
)