]> git.saurik.com Git - wxWidgets.git/blame - src/common/datavcmn.cpp
Halfway reasonable implementation of wxFont for wxCocoa.
[wxWidgets.git] / src / common / datavcmn.cpp
CommitLineData
239eaa41
RR
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
8045736e
RR
18#if wxUSE_DATAVIEWCTRL
19
e7445ff8
PC
20#include "wx/dataview.h"
21
f554a14b 22#ifndef WX_PRECOMP
f554a14b 23 #include "wx/log.h"
e94d0c1e 24 #include "wx/icon.h"
f554a14b
WS
25#endif
26
4a2e5ee8 27const wxChar wxDataViewCtrlNameStr[] = wxT("dataviewCtrl");
239eaa41 28
239eaa41 29
d5025dc0
RR
30bool operator == (const wxDataViewItem &left, const wxDataViewItem &right)
31{
32 return (left.GetID() == right.GetID() );
33}
34
35
f554a14b 36// ---------------------------------------------------------
854cdb09 37// wxDataViewModelNotifier
f554a14b 38// ---------------------------------------------------------
239eaa41 39
8ab03001 40#include "wx/listimpl.cpp"
9d8fe14a
RR
41WX_DEFINE_LIST(wxDataViewModelNotifiers);
42
854cdb09
RR
43bool wxDataViewModelNotifier::ItemsAdded( const wxDataViewItem &parent, const wxDataViewItemArray &items )
44{
45 size_t count = items.GetCount();
46 size_t i;
47 for (i = 0; i < count; i++)
48 if (!ItemAdded( parent, items[i] )) return false;
49
50 return true;
51}
52
53bool wxDataViewModelNotifier::ItemsDeleted( const wxDataViewItem &parent, const wxDataViewItemArray &items )
54{
55 size_t count = items.GetCount();
56 size_t i;
57 for (i = 0; i < count; i++)
58 if (!ItemDeleted( parent, items[i] )) return false;
59
60 return true;
61}
62
63bool wxDataViewModelNotifier::ItemsChanged( const wxDataViewItemArray &items )
64{
65 size_t count = items.GetCount();
66 size_t i;
67 for (i = 0; i < count; i++)
68 if (!ItemChanged( items[i] )) return false;
69
70 return true;
71}
72
73// ---------------------------------------------------------
74// wxDataViewModel
75// ---------------------------------------------------------
76
e0062c04 77wxDataViewModel::wxDataViewModel()
239eaa41 78{
8f850e28 79 m_notifiers.DeleteContents( true );
239eaa41
RR
80}
81
e0062c04 82bool wxDataViewModel::ItemAdded( const wxDataViewItem &parent, const wxDataViewItem &item )
239eaa41 83{
8f850e28
RR
84 bool ret = true;
85
9d8fe14a
RR
86 wxDataViewModelNotifiers::iterator iter;
87 for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
8f850e28 88 {
9d8fe14a 89 wxDataViewModelNotifier* notifier = *iter;
e0062c04 90 if (!notifier->ItemAdded( parent, item ))
8f850e28 91 ret = false;
8f850e28 92 }
f554a14b 93
8f850e28 94 return ret;
239eaa41
RR
95}
96
469d3e9b 97bool wxDataViewModel::ItemDeleted( const wxDataViewItem &parent, const wxDataViewItem &item )
239eaa41 98{
8f850e28
RR
99 bool ret = true;
100
9d8fe14a
RR
101 wxDataViewModelNotifiers::iterator iter;
102 for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
8f850e28 103 {
9d8fe14a 104 wxDataViewModelNotifier* notifier = *iter;
469d3e9b 105 if (!notifier->ItemDeleted( parent, item ))
8f850e28 106 ret = false;
8f850e28 107 }
f554a14b 108
8f850e28 109 return ret;
239eaa41
RR
110}
111
e0062c04 112bool wxDataViewModel::ItemChanged( const wxDataViewItem &item )
239eaa41 113{
8f850e28
RR
114 bool ret = true;
115
9d8fe14a
RR
116 wxDataViewModelNotifiers::iterator iter;
117 for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
8f850e28 118 {
9d8fe14a 119 wxDataViewModelNotifier* notifier = *iter;
e0062c04 120 if (!notifier->ItemChanged( item ))
8f850e28 121 ret = false;
8f850e28 122 }
f554a14b 123
8f850e28 124 return ret;
239eaa41
RR
125}
126
854cdb09
RR
127bool wxDataViewModel::ItemsAdded( const wxDataViewItem &parent, const wxDataViewItemArray &items )
128{
129 bool ret = true;
130
131 wxDataViewModelNotifiers::iterator iter;
132 for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
133 {
134 wxDataViewModelNotifier* notifier = *iter;
135 if (!notifier->ItemsAdded( parent, items ))
136 ret = false;
137 }
138
139 return ret;
140}
141
142bool wxDataViewModel::ItemsDeleted( const wxDataViewItem &parent, const wxDataViewItemArray &items )
143{
144 bool ret = true;
145
146 wxDataViewModelNotifiers::iterator iter;
147 for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
148 {
149 wxDataViewModelNotifier* notifier = *iter;
150 if (!notifier->ItemsDeleted( parent, items ))
151 ret = false;
152 }
153
154 return ret;
155}
156
157bool wxDataViewModel::ItemsChanged( const wxDataViewItemArray &items )
158{
159 bool ret = true;
160
161 wxDataViewModelNotifiers::iterator iter;
162 for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
163 {
164 wxDataViewModelNotifier* notifier = *iter;
165 if (!notifier->ItemsChanged( items ))
166 ret = false;
167 }
168
169 return ret;
170}
171
e0062c04 172bool wxDataViewModel::ValueChanged( const wxDataViewItem &item, unsigned int col )
239eaa41 173{
8f850e28 174 bool ret = true;
b5d777c7 175
9d8fe14a
RR
176 wxDataViewModelNotifiers::iterator iter;
177 for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
b5d777c7 178 {
9d8fe14a 179 wxDataViewModelNotifier* notifier = *iter;
e0062c04 180 if (!notifier->ValueChanged( item, col ))
8f850e28 181 ret = false;
b5d777c7 182 }
f554a14b 183
b5d777c7 184 return ret;
239eaa41
RR
185}
186
e0062c04 187bool wxDataViewModel::Cleared()
4eccd3a1
RR
188{
189 bool ret = true;
190
9d8fe14a
RR
191 wxDataViewModelNotifiers::iterator iter;
192 for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
4eccd3a1 193 {
9d8fe14a 194 wxDataViewModelNotifier* notifier = *iter;
8f850e28
RR
195 if (!notifier->Cleared())
196 ret = false;
8f850e28 197 }
f554a14b 198
8f850e28 199 return ret;
239eaa41
RR
200}
201
ef427989
RR
202void wxDataViewModel::Resort()
203{
9d8fe14a
RR
204 wxDataViewModelNotifiers::iterator iter;
205 for (iter = m_notifiers.begin(); iter != m_notifiers.end(); ++iter)
ef427989 206 {
9d8fe14a 207 wxDataViewModelNotifier* notifier = *iter;
ef427989 208 notifier->Resort();
ef427989
RR
209 }
210}
211
e0062c04 212void wxDataViewModel::AddNotifier( wxDataViewModelNotifier *notifier )
239eaa41 213{
9d8fe14a 214 m_notifiers.push_back( notifier );
8f850e28 215 notifier->SetOwner( this );
239eaa41
RR
216}
217
e0062c04 218void wxDataViewModel::RemoveNotifier( wxDataViewModelNotifier *notifier )
239eaa41 219{
8f850e28 220 m_notifiers.DeleteObject( notifier );
239eaa41
RR
221}
222
7ee7191c
RR
223int wxDataViewModel::Compare( const wxDataViewItem &item1, const wxDataViewItem &item2,
224 unsigned int column, bool ascending )
ef427989 225{
cf283a47 226 // sort branches before leaves
ed903e42
RR
227 bool item1_is_container = IsContainer(item1);
228 bool item2_is_container = IsContainer(item2);
900af470 229
ed903e42 230 if (item1_is_container && !item2_is_container)
cf283a47 231 return 1;
ed903e42 232 if (item2_is_container && !item1_is_container)
cf283a47 233 return -1;
900af470 234
ef427989 235 wxVariant value1,value2;
7ee7191c
RR
236 GetValue( value1, item1, column );
237 GetValue( value2, item2, column );
238
239 if (!ascending)
240 {
241 wxVariant temp = value1;
242 value1 = value2;
243 value2 = temp;
244 }
cf283a47 245
ef427989
RR
246 if (value1.GetType() == wxT("string"))
247 {
248 wxString str1 = value1.GetString();
249 wxString str2 = value2.GetString();
0be79c8a 250 int res = str1.Cmp( str2 );
cf283a47
RR
251 if (res) return res;
252 } else
ef427989
RR
253 if (value1.GetType() == wxT("long"))
254 {
255 long l1 = value1.GetLong();
256 long l2 = value2.GetLong();
cf283a47
RR
257 long res = l1-l2;
258 if (res) return res;
259 } else
ef427989
RR
260 if (value1.GetType() == wxT("double"))
261 {
262 double d1 = value1.GetDouble();
263 double d2 = value2.GetDouble();
ef427989 264 if (d1 < d2) return 1;
cf283a47
RR
265 if (d1 > d2) return -1;
266 } else
ef427989
RR
267 if (value1.GetType() == wxT("datetime"))
268 {
269 wxDateTime dt1 = value1.GetDateTime();
270 wxDateTime dt2 = value2.GetDateTime();
ef427989 271 if (dt1.IsEarlierThan(dt2)) return 1;
cf283a47 272 if (dt2.IsEarlierThan(dt1)) return -11;
ef427989
RR
273 }
274
cf283a47 275 // items must be different
900af470
JS
276 unsigned long litem1 = (unsigned long) item1.GetID();
277 unsigned long litem2 = (unsigned long) item2.GetID();
b7fe2261 278
7ee7191c
RR
279 if (!ascending)
280 return litem2-litem2;
cf283a47 281
cf283a47 282 return litem1-litem2;
ef427989
RR
283}
284
c534e696
RR
285// ---------------------------------------------------------
286// wxDataViewIndexListModel
287// ---------------------------------------------------------
288
289wxDataViewIndexListModel::wxDataViewIndexListModel( unsigned int initial_size )
290{
291 // build initial index
292 unsigned int i;
293 for (i = 1; i < initial_size+1; i++)
294 m_hash.Add( (void*) i );
295 m_lastIndex = initial_size + 1;
296}
297
298wxDataViewIndexListModel::~wxDataViewIndexListModel()
299{
300}
301
302void wxDataViewIndexListModel::RowPrepended()
303{
304 unsigned int id = m_lastIndex++;
305 m_hash.Insert( (void*) id, 0 );
306 wxDataViewItem item( (void*) id );
307 ItemAdded( wxDataViewItem(0), item );
308}
309
310void wxDataViewIndexListModel::RowInserted( unsigned int before )
311{
312 unsigned int id = m_lastIndex++;
313 m_hash.Insert( (void*) id, before );
314 wxDataViewItem item( (void*) id );
315 ItemAdded( wxDataViewItem(0), item );
316}
317
318void wxDataViewIndexListModel::RowAppended()
319{
320 unsigned int id = m_lastIndex++;
321 m_hash.Add( (void*) id );
322 wxDataViewItem item( (void*) id );
323 ItemAdded( wxDataViewItem(0), item );
324}
325
326void wxDataViewIndexListModel::RowDeleted( unsigned int row )
327{
328 wxDataViewItem item( m_hash[row] );
469d3e9b 329 wxDataViewModel::ItemDeleted( wxDataViewItem(0), item );
d3f00f59 330 m_hash.RemoveAt( row );
c534e696
RR
331}
332
333void wxDataViewIndexListModel::RowChanged( unsigned int row )
334{
335 wxDataViewModel::ItemChanged( GetItem(row) );
336}
337
338void wxDataViewIndexListModel::RowValueChanged( unsigned int row, unsigned int col )
339{
340 wxDataViewModel::ValueChanged( GetItem(row), col );
341}
342
343unsigned int wxDataViewIndexListModel::GetRow( const wxDataViewItem &item ) const
344{
345 // assert for not found
346 return (unsigned int) m_hash.Index( item.GetID() );
347}
348
349wxDataViewItem wxDataViewIndexListModel::GetItem( unsigned int row ) const
350{
fbda518c 351 wxASSERT( row < m_hash.GetCount() );
c534e696
RR
352 return wxDataViewItem( m_hash[row] );
353}
354
b7fe2261
VZ
355int wxDataViewIndexListModel::Compare(const wxDataViewItem& item1,
356 const wxDataViewItem& item2,
357 unsigned int WXUNUSED(column),
358 bool ascending)
c534e696 359{
7ee7191c
RR
360 if (ascending)
361 return GetRow(item1) - GetRow(item2);
b7fe2261 362
7ee7191c 363 return GetRow(item2) - GetRow(item1);
c534e696
RR
364}
365
900af470 366void wxDataViewIndexListModel::GetValue( wxVariant &variant,
c534e696
RR
367 const wxDataViewItem &item, unsigned int col ) const
368{
900af470 369 GetValue( variant, GetRow(item), col );
c534e696
RR
370}
371
900af470 372bool wxDataViewIndexListModel::SetValue( const wxVariant &variant,
c534e696
RR
373 const wxDataViewItem &item, unsigned int col )
374{
375 return SetValue( variant, GetRow(item), col );
376}
377
900af470 378wxDataViewItem wxDataViewIndexListModel::GetParent( const wxDataViewItem & WXUNUSED(item) ) const
c534e696
RR
379{
380 return wxDataViewItem(0);
381}
382
383bool wxDataViewIndexListModel::IsContainer( const wxDataViewItem &item ) const
384{
385 // only the invisible root item has children
386 if (!item.IsOk())
387 return true;
900af470 388
c534e696
RR
389 return false;
390}
391
74fe973b 392unsigned int wxDataViewIndexListModel::GetChildren( const wxDataViewItem &item, wxDataViewItemArray &children ) const
c534e696 393{
74fe973b
RR
394 if (item.IsOk())
395 return 0;
c534e696 396
74fe973b 397 children = m_hash;
b7fe2261 398
74fe973b 399 return m_hash.GetCount();
c534e696
RR
400}
401
89352653
RR
402//-----------------------------------------------------------------------------
403// wxDataViewIconText
404//-----------------------------------------------------------------------------
405
406IMPLEMENT_DYNAMIC_CLASS(wxDataViewIconText,wxObject)
407
d350fbec 408IMPLEMENT_VARIANT_OBJECT_EXPORTED(wxDataViewIconText, WXDLLIMPEXP_ADV)
89352653
RR
409
410bool operator == (const wxDataViewIconText &one, const wxDataViewIconText &two)
411{
412 if (one.GetText() != two.GetText()) return false;
413 if (one.IsSameAs(two)) return false;
414 return true;
415}
416
f554a14b 417// ---------------------------------------------------------
baa9ebc4 418// wxDataViewRendererBase
f554a14b 419// ---------------------------------------------------------
6842a71a 420
baa9ebc4 421IMPLEMENT_ABSTRACT_CLASS(wxDataViewRendererBase, wxObject)
6842a71a 422
900af470 423wxDataViewRendererBase::wxDataViewRendererBase( const wxString &varianttype,
9861f022
RR
424 wxDataViewCellMode WXUNUSED(mode),
425 int WXUNUSED(align) )
6842a71a
RR
426{
427 m_variantType = varianttype;
1e510b1e 428 m_editorCtrl = NULL;
9861f022
RR
429}
430
431const wxDataViewCtrl* wxDataViewRendererBase::GetView() const
432{
433 return wx_const_cast(wxDataViewRendererBase*, this)->GetOwner()->GetOwner();
6842a71a 434}
f554a14b 435
e0062c04 436bool wxDataViewRendererBase::StartEditing( const wxDataViewItem &item, wxRect labelRect )
1e510b1e 437{
e0062c04 438 m_item = item; // remember for later
900af470 439
1e510b1e
RR
440 unsigned int col = GetOwner()->GetModelColumn();
441 wxVariant value;
e0062c04 442 GetOwner()->GetOwner()->GetModel()->GetValue( value, item, col );
900af470 443
1e510b1e 444 m_editorCtrl = CreateEditorCtrl( GetOwner()->GetOwner()->GetMainWindow(), labelRect, value );
900af470
JS
445
446 wxDataViewEditorCtrlEvtHandler *handler =
30715fa1 447 new wxDataViewEditorCtrlEvtHandler( m_editorCtrl, (wxDataViewRenderer*) this );
900af470 448
30715fa1 449 m_editorCtrl->PushEventHandler( handler );
900af470 450
30715fa1
RR
451#if defined(__WXGTK20__) && !defined(wxUSE_GENERICDATAVIEWCTRL)
452 handler->SetFocusOnIdle();
453#else
1e510b1e 454 m_editorCtrl->SetFocus();
30715fa1
RR
455#endif
456
afebb87b
RR
457 // Now we should send Editing Started event
458 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_STARTED, GetOwner()->GetOwner()->GetId() );
459 event.SetDataViewColumn( GetOwner() );
460 event.SetModel( GetOwner()->GetOwner()->GetModel() );
461 event.SetItem( item );
afebb87b
RR
462 GetOwner()->GetOwner()->GetEventHandler()->ProcessEvent( event );
463
1e510b1e
RR
464 return true;
465}
466
467void wxDataViewRendererBase::CancelEditing()
468{
2fa73716 469 wxPendingDelete.Append( m_editorCtrl );
900af470 470
1e510b1e 471 GetOwner()->GetOwner()->GetMainWindow()->SetFocus();
900af470 472
2fa73716 473 // m_editorCtrl->PopEventHandler( true );
1e510b1e
RR
474}
475
476bool wxDataViewRendererBase::FinishEditing()
477{
1e510b1e
RR
478 wxVariant value;
479 GetValueFromEditorCtrl( m_editorCtrl, value );
480
2fa73716 481 wxPendingDelete.Append( m_editorCtrl );
900af470 482
1e510b1e 483 GetOwner()->GetOwner()->GetMainWindow()->SetFocus();
900af470 484
1e510b1e
RR
485 if (!Validate(value))
486 return false;
900af470 487
1e510b1e 488 unsigned int col = GetOwner()->GetModelColumn();
e0062c04
RR
489 GetOwner()->GetOwner()->GetModel()->SetValue( value, m_item, col );
490 GetOwner()->GetOwner()->GetModel()->ValueChanged( m_item, col );
900af470 491
2fa73716 492 // m_editorCtrl->PopEventHandler( true );
b7fe2261 493
afebb87b
RR
494 // Now we should send Editing Done event
495 wxDataViewEvent event( wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE, GetOwner()->GetOwner()->GetId() );
496 event.SetDataViewColumn( GetOwner() );
497 event.SetModel( GetOwner()->GetOwner()->GetModel() );
8fdaf7de 498 event.SetItem( m_item );
afebb87b 499 GetOwner()->GetOwner()->GetEventHandler()->ProcessEvent( event );
900af470 500
1e510b1e
RR
501 return true;
502}
503
504//-----------------------------------------------------------------------------
505// wxDataViewEditorCtrlEvtHandler
506//-----------------------------------------------------------------------------
507
508BEGIN_EVENT_TABLE(wxDataViewEditorCtrlEvtHandler, wxEvtHandler)
509 EVT_CHAR (wxDataViewEditorCtrlEvtHandler::OnChar)
510 EVT_KILL_FOCUS (wxDataViewEditorCtrlEvtHandler::OnKillFocus)
30715fa1 511 EVT_IDLE (wxDataViewEditorCtrlEvtHandler::OnIdle)
1e510b1e
RR
512END_EVENT_TABLE()
513
514wxDataViewEditorCtrlEvtHandler::wxDataViewEditorCtrlEvtHandler(
515 wxControl *editorCtrl,
516 wxDataViewRenderer *owner )
517{
518 m_owner = owner;
519 m_editorCtrl = editorCtrl;
520
521 m_finished = false;
522}
523
30715fa1
RR
524void wxDataViewEditorCtrlEvtHandler::OnIdle( wxIdleEvent &event )
525{
526 if (m_focusOnIdle)
527 {
528 m_focusOnIdle = false;
529 if (wxWindow::FindFocus() != m_editorCtrl)
530 m_editorCtrl->SetFocus();
531 }
900af470 532
30715fa1
RR
533 event.Skip();
534}
535
1e510b1e
RR
536void wxDataViewEditorCtrlEvtHandler::OnChar( wxKeyEvent &event )
537{
538 switch ( event.m_keyCode )
539 {
540 case WXK_RETURN:
541 m_finished = true;
542 m_owner->FinishEditing();
543 break;
544
545 case WXK_ESCAPE:
546 m_finished = true;
547 m_owner->CancelEditing();
548 break;
549
550 default:
551 event.Skip();
552 }
553}
554
555void wxDataViewEditorCtrlEvtHandler::OnKillFocus( wxFocusEvent &event )
556{
557 if (!m_finished)
558 {
559 m_finished = true;
560 m_owner->FinishEditing();
561 }
562
1e510b1e
RR
563 event.Skip();
564}
565
f554a14b 566// ---------------------------------------------------------
fa28826d 567// wxDataViewColumnBase
f554a14b 568// ---------------------------------------------------------
fa28826d
RR
569
570IMPLEMENT_ABSTRACT_CLASS(wxDataViewColumnBase, wxObject)
571
9861f022 572wxDataViewColumnBase::wxDataViewColumnBase(const wxString& WXUNUSED(title),
baa9ebc4 573 wxDataViewRenderer *renderer,
0a71f9e9 574 unsigned int model_column,
008b5a66 575 int WXUNUSED(width),
87f0efe2 576 wxAlignment WXUNUSED(align),
900af470 577 int WXUNUSED(flags))
fa28826d 578{
baa9ebc4 579 m_renderer = renderer;
6842a71a 580 m_model_column = model_column;
6842a71a 581 m_owner = NULL;
baa9ebc4 582 m_renderer->SetOwner( (wxDataViewColumn*) this );
9861f022
RR
583
584 // NOTE: the wxDataViewColumn's ctor must store the width, align, flags
585 // parameters inside the native control!
6842a71a
RR
586}
587
07a84e7b
RR
588wxDataViewColumnBase::wxDataViewColumnBase(const wxBitmap& bitmap,
589 wxDataViewRenderer *renderer,
590 unsigned int model_column,
591 int WXUNUSED(width),
87f0efe2 592 wxAlignment WXUNUSED(align),
900af470 593 int WXUNUSED(flags) )
07a84e7b
RR
594{
595 m_renderer = renderer;
596 m_model_column = model_column;
07a84e7b
RR
597 m_bitmap = bitmap;
598 m_owner = NULL;
599 m_renderer->SetOwner( (wxDataViewColumn*) this );
600}
601
6842a71a
RR
602wxDataViewColumnBase::~wxDataViewColumnBase()
603{
baa9ebc4
RR
604 if (m_renderer)
605 delete m_renderer;
fa28826d
RR
606}
607
9861f022 608int wxDataViewColumnBase::GetFlags() const
fa28826d 609{
9861f022 610 int ret = 0;
fa28826d 611
9861f022
RR
612 if (IsSortable())
613 ret |= wxDATAVIEW_COL_SORTABLE;
614 if (IsResizeable())
615 ret |= wxDATAVIEW_COL_RESIZABLE;
616 if (IsHidden())
617 ret |= wxDATAVIEW_COL_HIDDEN;
fa28826d 618
9861f022 619 return ret;
07a84e7b
RR
620}
621
9861f022 622void wxDataViewColumnBase::SetFlags(int flags)
07a84e7b 623{
9861f022
RR
624 SetSortable((flags & wxDATAVIEW_COL_SORTABLE) != 0);
625 SetResizeable((flags & wxDATAVIEW_COL_RESIZABLE) != 0);
626 SetHidden((flags & wxDATAVIEW_COL_HIDDEN) != 0);
07a84e7b
RR
627}
628
f554a14b 629// ---------------------------------------------------------
239eaa41 630// wxDataViewCtrlBase
f554a14b 631// ---------------------------------------------------------
239eaa41
RR
632
633IMPLEMENT_ABSTRACT_CLASS(wxDataViewCtrlBase, wxControl)
634
635wxDataViewCtrlBase::wxDataViewCtrlBase()
636{
637 m_model = NULL;
3b6280be
RR
638 m_expander_column = 0;
639 m_indent = 8;
239eaa41
RR
640}
641
642wxDataViewCtrlBase::~wxDataViewCtrlBase()
643{
87f0efe2
RR
644 if (m_model)
645 {
646 m_model->DecRef();
647 m_model = NULL;
648 }
239eaa41
RR
649}
650
e0062c04 651bool wxDataViewCtrlBase::AssociateModel( wxDataViewModel *model )
239eaa41 652{
1821abd1
RR
653 if (m_model)
654 {
87f0efe2 655 m_model->DecRef(); // discard old model, if any
1821abd1 656 }
87f0efe2
RR
657
658 // add our own reference to the new model:
239eaa41 659 m_model = model;
1821abd1
RR
660 if (m_model)
661 {
900af470 662 m_model->IncRef();
1821abd1 663 }
f554a14b 664
239eaa41
RR
665 return true;
666}
667
e0062c04 668wxDataViewModel* wxDataViewCtrlBase::GetModel()
239eaa41
RR
669{
670 return m_model;
671}
672
c7074d44
RR
673wxDataViewColumn *
674wxDataViewCtrlBase::AppendTextColumn( const wxString &label, unsigned int model_column,
87f0efe2 675 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
fa28826d 676{
c7074d44 677 wxDataViewColumn *ret = new wxDataViewColumn( label,
900af470 678 new wxDataViewTextRenderer( wxT("string"), mode, (int)align ),
c7074d44
RR
679 model_column, width, align, flags );
680 AppendColumn( ret );
681 return ret;
fa28826d
RR
682}
683
b04fcede
RR
684wxDataViewColumn *
685wxDataViewCtrlBase::AppendIconTextColumn( const wxString &label, unsigned int model_column,
686 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
687{
688 wxDataViewColumn *ret = new wxDataViewColumn( label,
689 new wxDataViewIconTextRenderer( wxT("wxDataViewIconText"), mode, (int)align ),
690 model_column, width, align, flags );
691 AppendColumn( ret );
692 return ret;
693}
694
c7074d44
RR
695wxDataViewColumn *
696wxDataViewCtrlBase::AppendToggleColumn( const wxString &label, unsigned int model_column,
87f0efe2 697 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
605c2c4a 698{
b7fe2261 699
c7074d44 700 wxDataViewColumn *ret = new wxDataViewColumn( label,
900af470 701 new wxDataViewToggleRenderer( wxT("bool"), mode, (int)align ),
c7074d44
RR
702 model_column, width, align, flags );
703 AppendColumn( ret );
704 return ret;
605c2c4a
RR
705}
706
c7074d44
RR
707wxDataViewColumn *
708wxDataViewCtrlBase::AppendProgressColumn( const wxString &label, unsigned int model_column,
87f0efe2 709 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
ad63bf41 710{
c7074d44 711 wxDataViewColumn *ret = new wxDataViewColumn( label,
900af470 712 new wxDataViewProgressRenderer( wxEmptyString, wxT("long"), mode, (int)align ),
c7074d44
RR
713 model_column, width, align, flags );
714 AppendColumn( ret );
715 return ret;
ad63bf41
RR
716}
717
c7074d44
RR
718wxDataViewColumn *
719wxDataViewCtrlBase::AppendDateColumn( const wxString &label, unsigned int model_column,
87f0efe2 720 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
4d496ecb 721{
c7074d44 722 wxDataViewColumn *ret = new wxDataViewColumn( label,
900af470 723 new wxDataViewDateRenderer( wxT("datetime"), mode, (int)align ),
c7074d44
RR
724 model_column, width, align, flags );
725 AppendColumn( ret );
726 return ret;
4d496ecb
RR
727}
728
c7074d44
RR
729wxDataViewColumn *
730wxDataViewCtrlBase::AppendBitmapColumn( const wxString &label, unsigned int model_column,
87f0efe2 731 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
07a84e7b 732{
c7074d44 733 wxDataViewColumn *ret = new wxDataViewColumn( label,
900af470 734 new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode, (int)align ),
c7074d44
RR
735 model_column, width, align, flags );
736 AppendColumn( ret );
737 return ret;
07a84e7b
RR
738}
739
c7074d44
RR
740wxDataViewColumn *
741wxDataViewCtrlBase::AppendTextColumn( const wxBitmap &label, unsigned int model_column,
87f0efe2 742 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
07a84e7b 743{
c7074d44 744 wxDataViewColumn *ret = new wxDataViewColumn( label,
900af470 745 new wxDataViewTextRenderer( wxT("string"), mode, (int)align ),
c7074d44
RR
746 model_column, width, align, flags );
747 AppendColumn( ret );
748 return ret;
b04fcede
RR
749}
750
751wxDataViewColumn *
752wxDataViewCtrlBase::AppendIconTextColumn( const wxBitmap &label, unsigned int model_column,
753 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
754{
755 wxDataViewColumn *ret = new wxDataViewColumn( label,
756 new wxDataViewIconTextRenderer( wxT("wxDataViewIconText"), mode, (int)align ),
757 model_column, width, align, flags );
758 AppendColumn( ret );
759 return ret;
07a84e7b
RR
760}
761
c7074d44
RR
762wxDataViewColumn *
763wxDataViewCtrlBase::AppendToggleColumn( const wxBitmap &label, unsigned int model_column,
87f0efe2 764 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
07a84e7b 765{
c7074d44 766 wxDataViewColumn *ret = new wxDataViewColumn( label,
900af470 767 new wxDataViewToggleRenderer( wxT("bool"), mode, (int)align ),
c7074d44
RR
768 model_column, width, align, flags );
769 AppendColumn( ret );
770 return ret;
07a84e7b
RR
771}
772
c7074d44
RR
773wxDataViewColumn *
774wxDataViewCtrlBase::AppendProgressColumn( const wxBitmap &label, unsigned int model_column,
87f0efe2 775 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
07a84e7b 776{
c7074d44 777 wxDataViewColumn *ret = new wxDataViewColumn( label,
900af470 778 new wxDataViewProgressRenderer( wxEmptyString, wxT("long"), mode, (int)align ),
c7074d44
RR
779 model_column, width, align, flags );
780 AppendColumn( ret );
781 return ret;
07a84e7b
RR
782}
783
c7074d44
RR
784wxDataViewColumn *
785wxDataViewCtrlBase::AppendDateColumn( const wxBitmap &label, unsigned int model_column,
87f0efe2 786 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
07a84e7b 787{
c7074d44 788 wxDataViewColumn *ret = new wxDataViewColumn( label,
900af470 789 new wxDataViewDateRenderer( wxT("datetime"), mode, (int)align ),
c7074d44
RR
790 model_column, width, align, flags );
791 AppendColumn( ret );
792 return ret;
07a84e7b
RR
793}
794
c7074d44
RR
795wxDataViewColumn *
796wxDataViewCtrlBase::AppendBitmapColumn( const wxBitmap &label, unsigned int model_column,
87f0efe2 797 wxDataViewCellMode mode, int width, wxAlignment align, int flags )
07a84e7b 798{
c7074d44 799 wxDataViewColumn *ret = new wxDataViewColumn( label,
900af470 800 new wxDataViewBitmapRenderer( wxT("wxBitmap"), mode, (int)align ),
c7074d44
RR
801 model_column, width, align, flags );
802 AppendColumn( ret );
803 return ret;
07a84e7b
RR
804}
805
c7074d44
RR
806bool
807wxDataViewCtrlBase::AppendColumn( wxDataViewColumn *col )
fa28826d 808{
6842a71a 809 col->SetOwner( (wxDataViewCtrl*) this );
fa28826d
RR
810 return true;
811}
812
eb7f97f8
RR
813// ---------------------------------------------------------
814// wxDataViewEvent
815// ---------------------------------------------------------
816
817IMPLEMENT_DYNAMIC_CLASS(wxDataViewEvent,wxNotifyEvent)
818
d86c1870
RR
819DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_SELECTION_CHANGED)
820
e0062c04 821DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ITEM_ACTIVATED)
6977c3bf 822DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSING)
3ecb8a53 823DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ITEM_COLLAPSED)
6977c3bf 824DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDING)
3ecb8a53 825DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ITEM_EXPANDED)
e0000f94
RR
826DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_STARTED)
827DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ITEM_EDITING_DONE)
6608fdab 828DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_ITEM_VALUE_CHANGED)
e0000f94 829
31fb32e1
RR
830DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_CLICK)
831DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_HEADER_RIGHT_CLICK)
c0a66d92 832DEFINE_EVENT_TYPE(wxEVT_COMMAND_DATAVIEW_COLUMN_SORTED)
eb7f97f8 833
e94d0c1e
RR
834//-----------------------------------------------------------------------------
835// wxDataViewTreeStore
836//-----------------------------------------------------------------------------
837
838wxDataViewTreeStoreNode::wxDataViewTreeStoreNode(
839 wxDataViewTreeStoreNode *parent,
840 const wxString &text, const wxIcon &icon, wxClientData *data )
841{
842 m_parent = parent;
843 m_text = text;
844 m_icon = icon;
845 m_data = data;
846}
847
848wxDataViewTreeStoreNode::~wxDataViewTreeStoreNode()
849{
850 if (m_data)
851 delete m_data;
852}
853
854#include "wx/listimpl.cpp"
855WX_DEFINE_LIST(wxDataViewTreeStoreNodeList);
856
857wxDataViewTreeStoreContainerNode::wxDataViewTreeStoreContainerNode(
858 wxDataViewTreeStoreNode *parent, const wxString &text,
859 const wxIcon &icon, const wxIcon &expanded, wxClientData *data ) :
860 wxDataViewTreeStoreNode( parent, text, icon, data )
861{
862 m_iconExpanded = expanded;
863 m_children.DeleteContents(true);
864}
865
866wxDataViewTreeStoreContainerNode::~wxDataViewTreeStoreContainerNode()
867{
868}
869
870//-----------------------------------------------------------------------------
871
872wxDataViewTreeStore::wxDataViewTreeStore()
873{
874 m_root = new wxDataViewTreeStoreContainerNode( NULL, wxEmptyString );
875}
876
877wxDataViewTreeStore::~wxDataViewTreeStore()
878{
879 delete m_root;
880}
881
882wxDataViewItem wxDataViewTreeStore::AppendItem( const wxDataViewItem& parent,
883 const wxString &text, const wxIcon &icon, wxClientData *data )
884{
885 wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent );
886 if (!parent_node) return wxDataViewItem(0);
887
888 wxDataViewTreeStoreNode *node =
889 new wxDataViewTreeStoreNode( parent_node, text, icon, data );
890 parent_node->GetChildren().Append( node );
891
892 // notify control
893 ItemAdded( parent, node->GetItem() );
894
895 return node->GetItem();
896}
897
898wxDataViewItem wxDataViewTreeStore::PrependItem( const wxDataViewItem& parent,
899 const wxString &text, const wxIcon &icon, wxClientData *data )
900{
901 wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent );
902 if (!parent_node) return wxDataViewItem(0);
903
904 wxDataViewTreeStoreNode *node =
905 new wxDataViewTreeStoreNode( parent_node, text, icon, data );
906 parent_node->GetChildren().Insert( node );
907
908 // notify control
909 ItemAdded( parent, node->GetItem() );
910
911 return node->GetItem();
912}
913
914wxDataViewItem wxDataViewTreeStore::InsertItem( const wxDataViewItem& parent, const wxDataViewItem& previous,
915 const wxString &text, const wxIcon &icon, wxClientData *data )
916{
917 return wxDataViewItem(0);
918}
919
920wxDataViewItem wxDataViewTreeStore::PrependContainer( const wxDataViewItem& parent,
921 const wxString &text, const wxIcon &icon, const wxIcon &expanded,
922 wxClientData *data )
923{
924 wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent );
925 if (!parent_node) return wxDataViewItem(0);
926
927 wxDataViewTreeStoreContainerNode *node =
928 new wxDataViewTreeStoreContainerNode( parent_node, text, icon, expanded, data );
929 parent_node->GetChildren().Insert( node );
930
931 // notify control
932 ItemAdded( parent, node->GetItem() );
933
934 return node->GetItem();
935}
936
937wxDataViewItem wxDataViewTreeStore::AppendContainer( const wxDataViewItem& parent,
938 const wxString &text, const wxIcon &icon, const wxIcon &expanded,
939 wxClientData *data )
940{
941 wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent );
942 if (!parent_node) return wxDataViewItem(0);
943
944 wxDataViewTreeStoreContainerNode *node =
945 new wxDataViewTreeStoreContainerNode( parent_node, text, icon, expanded, data );
946 parent_node->GetChildren().Append( node );
947
948 // notify control
949 ItemAdded( parent, node->GetItem() );
950
951 return node->GetItem();
952}
953
954wxDataViewItem wxDataViewTreeStore::InsertContainer( const wxDataViewItem& parent, const wxDataViewItem& previous,
955 const wxString &text, const wxIcon &icon, const wxIcon &expanded,
956 wxClientData *data )
957{
958 return wxDataViewItem(0);
959}
960
961wxDataViewItem wxDataViewTreeStore::GetNthChild( const wxDataViewItem& parent, unsigned int pos ) const
962{
963 wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent );
964 if (!parent_node) return wxDataViewItem(0);
965
966 wxDataViewTreeStoreNodeList::compatibility_iterator node = parent_node->GetChildren().Item( pos );
967 if (node)
968 return node->GetData();
969
970 return wxDataViewItem(0);
971}
972
973int wxDataViewTreeStore::GetChildCount( const wxDataViewItem& parent ) const
974{
975 wxDataViewTreeStoreNode *node = FindNode( parent );
976 if (!node) return -1;
977
978 if (!node->IsContainer())
979 return 0;
980
981 wxDataViewTreeStoreContainerNode *container_node = (wxDataViewTreeStoreContainerNode*) node;
982 return (int) container_node->GetChildren().GetCount();
983}
984
985void wxDataViewTreeStore::SetItemText( const wxDataViewItem& item, const wxString &text )
986{
987 wxDataViewTreeStoreNode *node = FindNode( item );
988 if (!node) return;
989
990 node->SetText( text );
991
992 // notify control
993 ValueChanged( item, 0 );
994}
995
996wxString wxDataViewTreeStore::GetItemText( const wxDataViewItem& item ) const
997{
998 wxDataViewTreeStoreNode *node = FindNode( item );
999 if (!node) return wxEmptyString;
1000
1001 return node->GetText();
1002}
1003
1004void wxDataViewTreeStore::SetItemIcon( const wxDataViewItem& item, const wxIcon &icon )
1005{
1006 wxDataViewTreeStoreNode *node = FindNode( item );
1007 if (!node) return;
1008
1009 node->SetIcon( icon );
1010
1011 // notify control
1012 ValueChanged( item, 0 );
1013}
1014
1015const wxIcon &wxDataViewTreeStore::GetItemIcon( const wxDataViewItem& item ) const
1016{
1017 wxDataViewTreeStoreNode *node = FindNode( item );
1018 if (!node) return wxNullIcon;
1019
1020 return node->GetIcon();
1021}
1022
1023void wxDataViewTreeStore::SetItemExpandedIcon( const wxDataViewItem& item, const wxIcon &icon )
1024{
1025 wxDataViewTreeStoreContainerNode *node = FindContainerNode( item );
1026 if (!node) return;
1027
1028 node->SetExpandedIcon( icon );
1029
1030 // notify control
1031 ValueChanged( item, 0 );
1032}
1033
1034const wxIcon &wxDataViewTreeStore::GetItemExpandedIcon( const wxDataViewItem& item ) const
1035{
1036 wxDataViewTreeStoreContainerNode *node = FindContainerNode( item );
1037 if (!node) return wxNullIcon;
1038
1039 return node->GetExpandedIcon();
1040}
1041
1042void wxDataViewTreeStore::SetItemData( const wxDataViewItem& item, wxClientData *data )
1043{
1044 wxDataViewTreeStoreNode *node = FindNode( item );
1045 if (!node) return;
1046
1047 node->SetData( data );
1048
1049 // notify control? only sensible when sorting on client data
1050 // ValueChanged( item, 0 );
1051}
1052
1053wxClientData *wxDataViewTreeStore::GetItemData( const wxDataViewItem& item ) const
1054{
1055 wxDataViewTreeStoreNode *node = FindNode( item );
1056 if (!node) return NULL;
1057
1058 return node->GetData();
1059}
1060
1061void wxDataViewTreeStore::DeleteItem( const wxDataViewItem& item )
1062{
1063 if (!item.IsOk()) return;
1064
1065 wxDataViewItem parent_item = GetParent( item );
1066
1067 wxDataViewTreeStoreContainerNode *parent_node = FindContainerNode( parent_item );
1068 if (!parent_node) return;
1069
1070 wxDataViewTreeStoreContainerNode *node = FindContainerNode( item );
1071 if (!node) return;
1072
1073 parent_node->GetChildren().DeleteObject( node );
1074
1075 // notify control
1076 ItemDeleted( parent_item, item );
1077}
1078
1079void wxDataViewTreeStore::DeleteChildren( const wxDataViewItem& item )
1080{
1081 wxDataViewTreeStoreContainerNode *node = FindContainerNode( item );
1082 if (!node) return;
1083
1084 wxDataViewItemArray array;
1085 wxDataViewTreeStoreNodeList::iterator iter;
1086 for (iter = node->GetChildren().begin(); iter != node->GetChildren().end(); iter++)
1087 {
1088 wxDataViewTreeStoreNode* child = *iter;
1089 array.Add( child->GetItem() );
1090 }
1091
1092 node->GetChildren().clear();
1093
1094 // notify control
1095 ItemsDeleted( item, array );
1096}
1097
1098void wxDataViewTreeStore::DeleteAllItems()
1099{
1100 // TODO
1101}
1102
1103void wxDataViewTreeStore::GetValue( wxVariant &variant,
1104 const wxDataViewItem &item, unsigned int col ) const
1105{
1106 // if (col != 0) return;
1107
1108 wxDataViewTreeStoreNode *node = FindNode( item );
1109 if (!node) return;
1110
1111 wxDataViewIconText data( node->GetText(), node->GetIcon() );
1112
1113 variant << data;
1114}
1115
1116bool wxDataViewTreeStore::SetValue( const wxVariant &variant,
1117 const wxDataViewItem &item, unsigned int col )
1118{
1119 // if (col != 0) return false;
1120
1121 wxDataViewTreeStoreNode *node = FindNode( item );
1122 if (!node) return false;
1123
1124 wxDataViewIconText data;
1125
1126 data << variant;
1127
1128 node->SetText( data.GetText() );
1129 node->SetIcon( data.GetIcon() );
1130
1131 return true;
1132}
1133
1134wxDataViewItem wxDataViewTreeStore::GetParent( const wxDataViewItem &item ) const
1135{
1136 wxDataViewTreeStoreNode *node = FindNode( item );
1137 if (!node) return wxDataViewItem(0);
1138
1139 wxDataViewTreeStoreNode *parent = node->GetParent();
1140 if (!parent) return wxDataViewItem(0);
1141
1142 if (parent == m_root)
1143 return wxDataViewItem(0);
1144
1145 return parent->GetItem();
1146}
1147
1148bool wxDataViewTreeStore::IsContainer( const wxDataViewItem &item ) const
1149{
1150 wxDataViewTreeStoreNode *node = FindNode( item );
1151 if (!node) return false;
1152
1153 return node->IsContainer();
1154}
1155
1156unsigned int wxDataViewTreeStore::GetChildren( const wxDataViewItem &item, wxDataViewItemArray &children ) const
1157{
1158 wxDataViewTreeStoreContainerNode *node = FindContainerNode( item );
1159 if (!node) return 0;
1160
1161 wxDataViewTreeStoreNodeList::iterator iter;
1162 for (iter = node->GetChildren().begin(); iter != node->GetChildren().end(); iter++)
1163 {
1164 wxDataViewTreeStoreNode* child = *iter;
1165 children.Add( child->GetItem() );
1166 }
1167
1168 return node->GetChildren().GetCount();
1169}
1170
1171int wxDataViewTreeStore::Compare( const wxDataViewItem &item1, const wxDataViewItem &item2,
1172 unsigned int WXUNUSED(column), bool WXUNUSED(ascending) )
1173{
1174 wxDataViewTreeStoreNode *node1 = FindNode( item1 );
1175 wxDataViewTreeStoreNode *node2 = FindNode( item2 );
1176
1177 if (!node1 || !node2)
1178 return 0;
1179
1180 wxDataViewTreeStoreContainerNode* parent1 =
1181 (wxDataViewTreeStoreContainerNode*) node1->GetParent();
1182 wxDataViewTreeStoreContainerNode* parent2 =
1183 (wxDataViewTreeStoreContainerNode*) node2->GetParent();
1184
1185 if (parent1 != parent2)
1186 {
1187 wxLogError( wxT("Comparing items with different parent.") );
1188 return 0;
1189 }
1190
1191 if (node1->IsContainer() && !!node2->IsContainer())
1192 return 1;
1193
1194 if (node2->IsContainer() && !!node1->IsContainer())
1195 return -1;
1196
1197 return parent1->GetChildren().IndexOf( node1 ) - parent1->GetChildren().IndexOf( node2 );
1198}
1199
1200wxDataViewTreeStoreNode *wxDataViewTreeStore::FindNode( const wxDataViewItem &item ) const
1201{
1202 if (!item.IsOk())
1203 return m_root;
1204
1205 return (wxDataViewTreeStoreNode*) item.GetID();
1206}
1207
1208wxDataViewTreeStoreContainerNode *wxDataViewTreeStore::FindContainerNode( const wxDataViewItem &item ) const
1209{
1210 if (!item.IsOk())
1211 return (wxDataViewTreeStoreContainerNode*) m_root;
1212
1213 wxDataViewTreeStoreNode* node = (wxDataViewTreeStoreNode*) item.GetID();
1214
1215 if (!node->IsContainer())
1216 return NULL;
1217
1218 return (wxDataViewTreeStoreContainerNode*) node;
1219}
1220
8045736e 1221#endif
e0000f94 1222