Have support for both char* and wchar_t* in wxPGPropArg. Moved wxPGPropArgCls member...
[wxWidgets.git] / src / propgrid / propgridiface.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/propgridiface.cpp
3 // Purpose: wxPropertyGridInterface class
4 // Author: Jaakko Salli
5 // Modified by:
6 // Created: 2008-08-24
7 // RCS-ID: $Id:
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include "wx/defs.h"
21 #include "wx/object.h"
22 #include "wx/hash.h"
23 #include "wx/string.h"
24 #include "wx/log.h"
25 #include "wx/event.h"
26 #include "wx/window.h"
27 #include "wx/panel.h"
28 #include "wx/dc.h"
29 #include "wx/dcmemory.h"
30 #include "wx/button.h"
31 #include "wx/pen.h"
32 #include "wx/brush.h"
33 #include "wx/cursor.h"
34 #include "wx/dialog.h"
35 #include "wx/settings.h"
36 #include "wx/msgdlg.h"
37 #include "wx/choice.h"
38 #include "wx/stattext.h"
39 #include "wx/scrolwin.h"
40 #include "wx/dirdlg.h"
41 #include "wx/layout.h"
42 #include "wx/sizer.h"
43 #include "wx/textdlg.h"
44 #include "wx/filedlg.h"
45 #include "wx/statusbr.h"
46 #include "wx/intl.h"
47 #include "wx/frame.h"
48 #endif
49
50 #include <wx/propgrid/property.h>
51 #include <wx/propgrid/propgrid.h>
52
53 #include <typeinfo>
54
55
56 const wxChar *wxPGTypeName_long = wxT("long");
57 const wxChar *wxPGTypeName_bool = wxT("bool");
58 const wxChar *wxPGTypeName_double = wxT("double");
59 const wxChar *wxPGTypeName_wxString = wxT("string");
60 const wxChar *wxPGTypeName_void = wxT("void*");
61 const wxChar *wxPGTypeName_wxArrayString = wxT("arrstring");
62
63
64 // ----------------------------------------------------------------------------
65 // VariantDatas
66 // ----------------------------------------------------------------------------
67
68 WX_PG_IMPLEMENT_VARIANT_DATA(wxPGVariantDataPoint, wxPoint)
69 WX_PG_IMPLEMENT_VARIANT_DATA(wxPGVariantDataSize, wxSize)
70 WX_PG_IMPLEMENT_VARIANT_DATA(wxPGVariantDataArrayInt, wxArrayInt)
71 WX_PG_IMPLEMENT_VARIANT_DATA(wxPGVariantDataLongLong, wxLongLong)
72 WX_PG_IMPLEMENT_VARIANT_DATA(wxPGVariantDataULongLong, wxULongLong)
73
74 WX_PG_IMPLEMENT_WXOBJECT_VARIANT_DATA(wxPGVariantDataFont, wxFont)
75
76 wxObject* wxPG_VariantToWxObject( const wxVariant& variant, wxClassInfo* classInfo )
77 {
78 if ( !variant.IsValueKindOf(classInfo) )
79 return (wxObject*) NULL;
80
81 wxVariantData* vdata = variant.GetData();
82
83 wxPGVariantData* pgvdata = wxDynamicCastVariantData(vdata, wxPGVariantData);
84 if ( pgvdata )
85 return (wxObject*) pgvdata->GetValuePtr();
86
87 if ( wxPGIsVariantClassInfo(wxPGVariantDataGetClassInfo(vdata), wxobject) )
88 return variant.GetWxObjectPtr();
89
90 return (wxObject*) NULL;
91 }
92
93 // -----------------------------------------------------------------------
94 // wxVariant helpers
95 // -----------------------------------------------------------------------
96
97 long wxPGVariantToInt( const wxVariant& variant, long defVal )
98 {
99 if ( variant.IsNull() )
100 return defVal;
101
102 if ( wxPGIsVariantType(variant, long) )
103 return variant.GetLong();
104
105 if ( wxPGIsVariantType(variant, bool) )
106 return variant.GetBool() ? 1 : 0;
107
108 if ( typeid(*variant.GetData()) == typeid(wxPGVariantDataLongLong) )
109 {
110 wxLongLong ll = ((const wxPGVariantDataLongLong&)variant).GetValue();
111 if ( ll >= LONG_MAX )
112 return LONG_MAX;
113 else if ( ll <= LONG_MIN )
114 return LONG_MIN;
115 return ll.ToLong();
116 }
117
118 long l = defVal;
119
120 if ( wxPGIsVariantType(variant, string) )
121 variant.GetString().ToLong(&l, 0);
122
123 return l;
124 }
125
126 // -----------------------------------------------------------------------
127
128 bool wxPGVariantToLongLong( const wxVariant& variant, wxLongLong_t* pResult )
129 {
130 if ( variant.IsNull() )
131 return false;
132
133 if ( wxPGIsVariantType(variant, long) )
134 {
135 *pResult = variant.GetLong();
136 return true;
137 }
138
139 if ( typeid(*variant.GetData()) == typeid(wxPGVariantDataLongLong) )
140 {
141 *pResult = ((const wxPGVariantDataLongLong&)variant).GetValue().GetValue();
142 return true;
143 }
144
145 return false;
146 }
147
148 // -----------------------------------------------------------------------
149
150 bool wxPGVariantToULongLong( const wxVariant& variant, wxULongLong_t* pResult )
151 {
152 if ( variant.IsNull() )
153 return false;
154
155 if ( wxPGIsVariantType(variant, long) )
156 {
157 *pResult = (unsigned long)variant.GetLong();
158 return true;
159 }
160
161 if ( typeid(*variant.GetData()) == typeid(wxPGVariantDataULongLong) )
162 {
163 *pResult = ((const wxPGVariantDataULongLong&)variant).GetValue().GetValue();
164 return true;
165 }
166
167 return false;
168 }
169
170 // -----------------------------------------------------------------------
171
172 bool wxPGVariantToDouble( const wxVariant& variant, double* pResult )
173 {
174 if ( variant.IsNull() )
175 return false;
176
177 if ( wxPGIsVariantType(variant, double) )
178 {
179 *pResult = variant.GetDouble();
180 return true;
181 }
182
183 if ( wxPGIsVariantType(variant, long) )
184 {
185 *pResult = (double)variant.GetLong();
186 return true;
187 }
188
189 if ( typeid(*variant.GetData()) == typeid(wxPGVariantDataLongLong) )
190 {
191 wxLongLong ll = ((const wxPGVariantDataLongLong&)variant).GetValue();
192 *pResult = ll.ToDouble();
193 return true;
194 }
195
196 if ( wxPGIsVariantType(variant, string) )
197 if ( variant.GetString().ToDouble(pResult) )
198 return true;
199
200 return false;
201 }
202
203 // -----------------------------------------------------------------------
204 // wxPGPropArgCls
205 // -----------------------------------------------------------------------
206
207 wxPGProperty* wxPGPropArgCls::GetPtr( wxPropertyGridInterface* iface ) const
208 {
209 if ( m_flags == IsProperty )
210 {
211 wxASSERT_MSG( m_ptr.property, wxT("invalid property ptr") );
212 return m_ptr.property;
213 }
214 else if ( m_flags & IsWxString )
215 return iface->GetPropertyByNameA(*m_ptr.stringName);
216 else if ( m_flags & IsCharPtr )
217 return iface->GetPropertyByNameA(m_ptr.charName);
218 #if wxUSE_WCHAR_T
219 else if ( m_flags & IsWCharPtr )
220 return iface->GetPropertyByNameA(m_ptr.wcharName);
221 #endif
222
223 return NULL;
224 }
225
226 // -----------------------------------------------------------------------
227 // Choice related methods
228 // -----------------------------------------------------------------------
229
230 void wxPropertyGridInterface::AddPropertyChoice( wxPGPropArg id,
231 const wxString& label,
232 int value )
233 {
234 wxPG_PROP_ARG_CALL_PROLOG()
235
236 p->InsertChoice(label,-1,value);
237 }
238
239
240 void wxPropertyGridInterface::InsertPropertyChoice( wxPGPropArg id,
241 const wxString& label,
242 int index,
243 int value )
244 {
245 wxPG_PROP_ARG_CALL_PROLOG()
246
247 p->InsertChoice(label,index,value);
248 }
249
250
251 void wxPropertyGridInterface::DeletePropertyChoice( wxPGPropArg id,
252 int index )
253 {
254 wxPG_PROP_ARG_CALL_PROLOG()
255
256 p->DeleteChoice(index);
257 }
258
259 // -----------------------------------------------------------------------
260
261 void wxPropertyGridInterface::RefreshGrid( wxPropertyGridPageState* state )
262 {
263 if ( !state )
264 state = m_pState;
265
266 wxPropertyGrid* grid = state->GetGrid();
267 if ( grid->GetState() == state && !grid->IsFrozen() )
268 {
269 grid->Refresh();
270 }
271 }
272
273 // -----------------------------------------------------------------------
274
275 wxPGProperty* wxPropertyGridInterface::Append( wxPGProperty* property )
276 {
277 wxPGProperty* retp = m_pState->DoAppend(property);
278
279 wxPropertyGrid* grid = m_pState->GetGrid();
280 if ( grid )
281 grid->RefreshGrid();
282
283 return retp;
284 }
285
286 // -----------------------------------------------------------------------
287
288 wxPGProperty* wxPropertyGridInterface::AppendIn( wxPGPropArg id, wxPGProperty* newproperty )
289 {
290 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
291 wxPGProperty* pwc = (wxPGProperty*) p;
292 wxPGProperty* retp = m_pState->DoInsert(pwc, pwc->GetChildCount(), newproperty);
293 return retp;
294 }
295
296 // -----------------------------------------------------------------------
297
298 wxPGProperty* wxPropertyGridInterface::Insert( wxPGPropArg id, wxPGProperty* property )
299 {
300 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
301 wxPGProperty* retp = m_pState->DoInsert(p->GetParent(), p->GetArrIndex(), property);
302 RefreshGrid();
303 return retp;
304 }
305
306 // -----------------------------------------------------------------------
307
308 wxPGProperty* wxPropertyGridInterface::Insert( wxPGPropArg id, int index, wxPGProperty* newproperty )
309 {
310 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
311 wxPGProperty* retp = m_pState->DoInsert((wxPGProperty*)p,index,newproperty);
312 RefreshGrid();
313 return retp;
314 }
315
316 // -----------------------------------------------------------------------
317
318 void wxPropertyGridInterface::DeleteProperty( wxPGPropArg id )
319 {
320 wxPG_PROP_ARG_CALL_PROLOG()
321
322 wxPropertyGridPageState* state = p->GetParentState();
323 wxPropertyGrid* grid = state->GetGrid();
324
325 if ( grid->GetState() == state )
326 {
327 bool selRes = grid->DoSelectProperty(NULL, wxPG_SEL_DELETING);
328 wxPG_CHECK_RET_DBG( selRes,
329 wxT("failed to deselect a property (editor probably had invalid value)") );
330 }
331
332 state->DoDelete( p );
333
334 RefreshGrid(state);
335 }
336
337 // -----------------------------------------------------------------------
338
339 wxPGProperty* wxPropertyGridInterface::ReplaceProperty( wxPGPropArg id, wxPGProperty* property )
340 {
341 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
342
343 wxPGProperty* replaced = p;
344 wxCHECK_MSG( replaced && property,
345 wxNullProperty,
346 wxT("NULL property") );
347 wxCHECK_MSG( !replaced->IsCategory(),
348 wxNullProperty,
349 wxT("cannot replace this type of property") );
350 wxCHECK_MSG( !m_pState->IsInNonCatMode(),
351 wxNullProperty,
352 wxT("cannot replace properties in alphabetic mode") );
353
354 // Get address to the slot
355 wxPGProperty* parent = replaced->GetParent();
356 int ind = replaced->GetIndexInParent();
357
358 wxPropertyGridPageState* state = replaced->GetParentState();
359 DeleteProperty(replaced); // Must use generic Delete
360 state->DoInsert(parent,ind,property);
361
362 return property;
363 }
364
365 // -----------------------------------------------------------------------
366 // wxPropertyGridInterface property operations
367 // -----------------------------------------------------------------------
368
369 bool wxPropertyGridInterface::ClearSelection()
370 {
371 wxPropertyGridPageState* state = m_pState;
372 wxPropertyGrid* pg = state->GetGrid();
373 if ( pg->GetState() == state )
374 return pg->DoClearSelection();
375 else
376 state->SetSelection(NULL);
377 return true;
378 }
379
380 // -----------------------------------------------------------------------
381
382 void wxPropertyGridInterface::LimitPropertyEditing( wxPGPropArg id, bool limit )
383 {
384 wxPG_PROP_ARG_CALL_PROLOG()
385
386 m_pState->DoLimitPropertyEditing(p, limit);
387 RefreshProperty(p);
388 }
389
390 // -----------------------------------------------------------------------
391
392 bool wxPropertyGridInterface::EnableProperty( wxPGPropArg id, bool enable )
393 {
394 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
395
396 wxPropertyGridPageState* state = p->GetParentState();
397 wxPropertyGrid* grid = state->GetGrid();
398
399 if ( enable )
400 {
401 if ( !(p->m_flags & wxPG_PROP_DISABLED) )
402 return false;
403
404 // If active, Set active Editor.
405 if ( grid->GetState() == state && p == grid->GetSelection() )
406 grid->DoSelectProperty( p, wxPG_SEL_FORCE );
407 }
408 else
409 {
410 if ( p->m_flags & wxPG_PROP_DISABLED )
411 return false;
412
413 // If active, Disable as active Editor.
414 if ( grid->GetState() == state && p == grid->GetSelection() )
415 grid->DoSelectProperty( p, wxPG_SEL_FORCE );
416 }
417
418 state->DoEnableProperty(p, enable);
419
420 RefreshProperty( p );
421
422 return true;
423 }
424
425 // -----------------------------------------------------------------------
426
427 bool wxPropertyGridInterface::ExpandAll( bool doExpand )
428 {
429 wxPropertyGridPageState* state = m_pState;
430
431 if ( !state->DoGetRoot()->GetChildCount() )
432 return true;
433
434 wxPropertyGrid* pg = state->GetGrid();
435
436 if ( GetSelection() && GetSelection() != state->DoGetRoot() &&
437 !doExpand )
438 {
439 if ( !pg->ClearSelection() )
440 return false;
441 }
442
443 wxPGVIterator it;
444
445 for ( it = GetVIterator( wxPG_ITERATE_ALL ); !it.AtEnd(); it.Next() )
446 {
447 wxPGProperty* p = (wxPGProperty*) it.GetProperty();
448 if ( p->GetChildCount() )
449 {
450 if ( doExpand )
451 {
452 if ( !p->IsExpanded() )
453 {
454 state->DoExpand(p);
455 }
456 }
457 else
458 {
459 if ( p->IsExpanded() )
460 {
461 state->DoCollapse(p);
462 }
463 }
464 }
465 }
466
467 pg->RecalculateVirtualSize();
468
469 RefreshGrid();
470
471 return true;
472 }
473
474 // -----------------------------------------------------------------------
475
476 void wxPropertyGridInterface::SetPropertyValueUnspecified( wxPGPropArg id )
477 {
478 wxPG_PROP_ARG_CALL_PROLOG()
479 wxPropertyGrid* propGrid = p->GetGridIfDisplayed();
480 if ( propGrid )
481 propGrid->DoSetPropertyValueUnspecified(p);
482 else
483 p->GetParentState()->DoSetPropertyValueUnspecified(p);
484 }
485
486 // -----------------------------------------------------------------------
487 // wxPropertyGridInterface property value setting and getting
488 // -----------------------------------------------------------------------
489
490 void wxPGGetFailed( const wxPGProperty* p, const wxChar* typestr )
491 {
492 wxPGTypeOperationFailed(p,typestr,wxT("Get"));
493 }
494
495 // -----------------------------------------------------------------------
496
497 void wxPGTypeOperationFailed( const wxPGProperty* p, const wxChar* typestr,
498 const wxChar* op )
499 {
500 wxASSERT( p != NULL );
501 wxLogError( _("Type operation \"%s\" failed: Property labeled \"%s\" is of type \"%s\", NOT \"%s\"."),
502 op,p->GetLabel().c_str(),p->GetValue().GetType().c_str(),typestr );
503 }
504
505 // -----------------------------------------------------------------------
506
507 void wxPropertyGridInterface::SetPropVal( wxPGPropArg id, wxVariant& value )
508 {
509 wxPG_PROP_ARG_CALL_PROLOG()
510
511 if ( p )
512 {
513 p->SetValue(value);
514 wxPropertyGrid* propGrid = p->GetGridIfDisplayed();
515 if ( propGrid )
516 propGrid->DrawItemAndValueRelated( p );
517
518 }
519 }
520
521 // -----------------------------------------------------------------------
522
523 void wxPropertyGridInterface::SetPropertyValueString( wxPGPropArg id, const wxString& value )
524 {
525 wxPG_PROP_ARG_CALL_PROLOG()
526
527 if ( m_pState->DoSetPropertyValueString(p,value) )
528 {
529 wxPropertyGrid* propGrid = p->GetGridIfDisplayed();
530 if ( propGrid )
531 propGrid->DrawItemAndValueRelated( p );
532 }
533 }
534
535 // -----------------------------------------------------------------------
536
537 void wxPropertyGridInterface::SetValidationFailureBehavior( int vfbFlags )
538 {
539 GetPropertyGrid()->m_permanentValidationFailureBehavior = vfbFlags;
540 }
541
542 // -----------------------------------------------------------------------
543
544 wxPGProperty* wxPropertyGridInterface::GetPropertyByNameA( const wxString& name ) const
545 {
546 wxPGProperty* p = GetPropertyByName(name);
547 wxASSERT_MSG(p,wxString::Format(wxT("no property with name '%s'"),name.c_str()));
548 return p;
549 }
550
551 // ----------------------------------------------------------------------------
552
553 wxPGProperty* wxPropertyGridInterface::GetPropertyByLabel( const wxString& label ) const
554 {
555 wxPGVIterator it;
556
557 for ( it = GetVIterator( wxPG_ITERATE_PROPERTIES ); !it.AtEnd(); it.Next() )
558 {
559 if ( it.GetProperty()->GetLabel() == label )
560 return it.GetProperty();
561 }
562
563 return wxNullProperty;
564 }
565
566 // ----------------------------------------------------------------------------
567
568 void wxPropertyGridInterface::DoSetPropertyAttribute( wxPGPropArg id, const wxString& name,
569 wxVariant& value, long argFlags )
570 {
571 wxPG_PROP_ARG_CALL_PROLOG()
572
573 p->SetAttribute( name, value );
574
575 if ( argFlags & wxPG_RECURSE )
576 {
577 unsigned int i;
578 for ( i = 0; i < p->GetChildCount(); i++ )
579 DoSetPropertyAttribute(p->Item(i), name, value, argFlags);
580 }
581 }
582
583 // -----------------------------------------------------------------------
584
585 void wxPropertyGridInterface::GetPropertiesWithFlag( wxArrayPGProperty* targetArr,
586 wxPGProperty::FlagType flags,
587 bool inverse,
588 int iterFlags ) const
589 {
590 wxASSERT( targetArr );
591 wxPGVIterator it = GetVIterator( iterFlags );
592
593 for ( ;
594 !it.AtEnd();
595 it.Next() )
596 {
597 const wxPGProperty* property = it.GetProperty();
598
599 if ( !inverse )
600 {
601 if ( (property->GetFlags() & flags) == flags )
602 targetArr->push_back((wxPGProperty*)property);
603 }
604 else
605 {
606 if ( (property->GetFlags() & flags) != flags )
607 targetArr->push_back((wxPGProperty*)property);
608 }
609 }
610 }
611
612 // -----------------------------------------------------------------------
613
614 void wxPropertyGridInterface::SetPropertiesFlag( const wxArrayPGProperty& srcArr,
615 wxPGProperty::FlagType flags,
616 bool inverse )
617 {
618 unsigned int i;
619
620 for ( i=0; i<srcArr.size(); i++ )
621 {
622 wxPGProperty* property = srcArr[i];
623
624 if ( !inverse )
625 property->SetFlag(flags);
626 else
627 property->ClearFlag(flags);
628 }
629
630 // If collapsed flag or hidden was manipulated, we need to update virtual
631 // size.
632 wxPropertyGrid* pg = GetPropertyGrid();
633 if ( flags & (wxPG_PROP_COLLAPSED|wxPG_PROP_HIDDEN) )
634 {
635 GetState()->VirtualHeightChanged();
636 pg->RecalculateVirtualSize();
637 }
638 }
639
640 // -----------------------------------------------------------------------
641
642 void wxPropertyGridInterface::SetBoolChoices( const wxString& trueChoice,
643 const wxString& falseChoice )
644 {
645 wxPGGlobalVars->m_boolChoices[0] = falseChoice;
646 wxPGGlobalVars->m_boolChoices[1] = trueChoice;
647 }
648
649 // -----------------------------------------------------------------------
650
651 wxPGChoices gs_emptyChoices;
652
653 wxPGChoices& wxPropertyGridInterface::GetPropertyChoices( wxPGPropArg id )
654 {
655 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(gs_emptyChoices)
656
657 wxPGChoiceInfo ci;
658 ci.m_choices = (wxPGChoices*) NULL;
659
660 p->GetChoiceInfo(&ci);
661
662 if ( !ci.m_choices )
663 return gs_emptyChoices;
664
665 return *ci.m_choices;
666 }
667
668 // -----------------------------------------------------------------------
669
670 wxPGProperty* wxPropertyGridInterface::DoGetPropertyByName( const wxString& name ) const
671 {
672 return m_pState->BaseGetPropertyByName(name);
673 }
674
675 // -----------------------------------------------------------------------
676
677 wxPGProperty* wxPropertyGridInterface::GetPropertyByName( const wxString& name,
678 const wxString& subname ) const
679 {
680 wxPGProperty* p = DoGetPropertyByName(name);
681 if ( !p || !p->GetChildCount() )
682 return wxNullProperty;
683
684 return p->GetPropertyByName(subname);
685 }
686
687 // -----------------------------------------------------------------------
688
689 // Since GetPropertyByName is used *a lot*, this makes sense
690 // since non-virtual method can be called with less code.
691 wxPGProperty* wxPropertyGridInterface::GetPropertyByName( const wxString& name ) const
692 {
693 wxPGProperty* p = DoGetPropertyByName(name);
694 if ( p )
695 return p;
696
697 // Check if its "Property.SubProperty" format
698 int pos = name.Find(wxT('.'));
699 if ( pos <= 0 )
700 return NULL;
701
702 return GetPropertyByName(name.substr(0,pos),
703 name.substr(pos+1,name.length()-pos-1));
704 }
705
706 // -----------------------------------------------------------------------
707
708 bool wxPropertyGridInterface::HideProperty( wxPGPropArg id, bool hide, int flags )
709 {
710 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
711
712 wxPropertyGrid* pg = m_pState->GetGrid();
713
714 if ( pg == p->GetGrid() )
715 return pg->DoHideProperty(p, hide, flags);
716 else
717 m_pState->DoHideProperty(p, hide, flags);
718
719 return true;
720 }
721
722 // -----------------------------------------------------------------------
723
724 bool wxPropertyGridInterface::Collapse( wxPGPropArg id )
725 {
726 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
727 wxPropertyGrid* pg = p->GetGridIfDisplayed();
728 if ( pg )
729 return pg->DoCollapse(p);
730
731 return p->GetParentState()->DoCollapse(p);
732 }
733
734 // -----------------------------------------------------------------------
735
736 bool wxPropertyGridInterface::Expand( wxPGPropArg id )
737 {
738 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
739 wxPropertyGrid* pg = p->GetGridIfDisplayed();
740 if ( pg )
741 return pg->DoExpand(p);
742
743 return p->GetParentState()->DoExpand(p);
744 }
745
746 // -----------------------------------------------------------------------
747
748 void wxPropertyGridInterface::SetPropertyLabel( wxPGPropArg id, const wxString& newproplabel )
749 {
750 wxPG_PROP_ARG_CALL_PROLOG()
751
752 p->SetLabel( newproplabel );
753
754 wxPropertyGridPageState* state = p->GetParentState();
755 wxPropertyGrid* pg = state->GetGrid();
756
757 if ( pg->HasFlag(wxPG_AUTO_SORT) )
758 pg->SortChildren(p->GetParent());
759
760 if ( pg->GetState() == state )
761 {
762 if ( pg->HasFlag(wxPG_AUTO_SORT) )
763 pg->Refresh();
764 else
765 pg->DrawItem( p );
766 }
767 }
768
769 // -----------------------------------------------------------------------
770
771 bool wxPropertyGridInterface::SetPropertyMaxLength( wxPGPropArg id, int maxLen )
772 {
773 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
774
775 wxPropertyGrid* pg = m_pState->GetGrid();
776
777 p->m_maxLen = (short) maxLen;
778
779 // Adjust control if selected currently
780 if ( pg == p->GetGrid() && p == m_pState->GetSelection() )
781 {
782 wxWindow* wnd = pg->GetEditorControl();
783 wxTextCtrl* tc = wxDynamicCast(wnd,wxTextCtrl);
784 if ( tc )
785 tc->SetMaxLength( maxLen );
786 else
787 // Not a text ctrl
788 return false;
789 }
790
791 return true;
792 }
793
794 // -----------------------------------------------------------------------
795 // GetPropertyValueAsXXX methods
796
797 #define IMPLEMENT_GET_VALUE(T,TRET,BIGNAME,DEFRETVAL) \
798 TRET wxPropertyGridInterface::GetPropertyValueAs##BIGNAME( wxPGPropArg id ) const \
799 { \
800 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(DEFRETVAL) \
801 wxVariant value = p->GetValue(); \
802 if ( wxStrcmp(value.GetType(), wxPGTypeName_##T) != 0 ) \
803 { \
804 wxPGGetFailed(p,wxPGTypeName_##T); \
805 return (TRET)DEFRETVAL; \
806 } \
807 return (TRET)value.Get##BIGNAME(); \
808 }
809
810 // String is different than others.
811 wxString wxPropertyGridInterface::GetPropertyValueAsString( wxPGPropArg id ) const
812 {
813 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxEmptyString)
814 return p->GetValueAsString(wxPG_FULL_VALUE);
815 }
816
817 bool wxPropertyGridInterface::GetPropertyValueAsBool( wxPGPropArg id ) const
818 {
819 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
820 wxVariant value = p->GetValue();
821 if ( wxStrcmp(value.GetType(), wxPGTypeName_bool) == 0 )
822 {
823 return value.GetBool();
824 }
825 if ( wxStrcmp(value.GetType(), wxPGTypeName_long) == 0 )
826 {
827 return value.GetLong()?true:false;
828 }
829 wxPGGetFailed(p,wxPGTypeName_bool);
830 return false;
831 }
832
833 IMPLEMENT_GET_VALUE(long,long,Long,0)
834 IMPLEMENT_GET_VALUE(double,double,Double,0.0)
835 IMPLEMENT_GET_VALUE(void,void*,VoidPtr,NULL)
836
837 // wxObject is different than others.
838 wxObject* wxPropertyGridInterface::GetPropertyValueAsWxObjectPtr( wxPGPropArg id ) const
839 {
840 wxPG_PROP_ARG_CALL_PROLOG_RETVAL((wxObject*)NULL)
841
842 wxVariant value = p->GetValue();
843 wxVariantData* vdata = value.GetData();
844
845 if ( !vdata->GetValueClassInfo() )
846 return (wxObject*) NULL;
847
848 wxPGVariantData* pgvdata = wxDynamicCastVariantData(vdata, wxPGVariantData);
849 if ( pgvdata )
850 return (wxObject*) pgvdata->GetValuePtr();
851
852 if ( wxPGIsVariantClassInfo(wxPGVariantDataGetClassInfo(vdata), wxobject) )
853 return (wxObject*) value.GetWxObjectPtr();
854
855 return (wxObject*) NULL;
856 }
857
858 // -----------------------------------------------------------------------
859
860 bool wxPropertyGridInterface::IsPropertyExpanded( wxPGPropArg id ) const
861 {
862 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
863 return p->IsExpanded();
864 }
865
866 // -----------------------------------------------------------------------
867 // wxPropertyGridInterface wrappers
868 // -----------------------------------------------------------------------
869
870 bool wxPropertyGridInterface::ChangePropertyValue( wxPGPropArg id, wxVariant newValue )
871 {
872 return GetPropertyGrid()->ChangePropertyValue(id, newValue);
873 }
874
875 // -----------------------------------------------------------------------
876
877 void wxPropertyGridInterface::BeginAddChildren( wxPGPropArg id )
878 {
879 wxPG_PROP_ARG_CALL_PROLOG()
880 wxCHECK_RET( p->HasFlag(wxPG_PROP_AGGREGATE), wxT("only call on properties with fixed children") );
881 p->ClearFlag(wxPG_PROP_AGGREGATE);
882 p->SetFlag(wxPG_PROP_MISC_PARENT);
883 }
884
885 // -----------------------------------------------------------------------
886
887 bool wxPropertyGridInterface::EditorValidate()
888 {
889 return GetPropertyGrid()->DoEditorValidate();
890 }
891
892 // -----------------------------------------------------------------------
893
894 void wxPropertyGridInterface::EndAddChildren( wxPGPropArg id )
895 {
896 wxPG_PROP_ARG_CALL_PROLOG()
897 wxCHECK_RET( p->HasFlag(wxPG_PROP_MISC_PARENT), wxT("only call on properties for which BeginAddChildren was called prior") );
898 p->ClearFlag(wxPG_PROP_MISC_PARENT);
899 p->SetFlag(wxPG_PROP_AGGREGATE);
900 }
901
902 // -----------------------------------------------------------------------
903 // wxPGVIterator_State
904 // -----------------------------------------------------------------------
905
906 // Default returned by wxPropertyGridInterface::GetVIterator().
907 class wxPGVIteratorBase_State : public wxPGVIteratorBase
908 {
909 public:
910 wxPGVIteratorBase_State( wxPropertyGridPageState* state, int flags )
911 {
912 m_it.Init( state, flags );
913 }
914 virtual ~wxPGVIteratorBase_State() { }
915 virtual void Next() { m_it.Next(); }
916 };
917
918 wxPGVIterator wxPropertyGridInterface::GetVIterator( int flags ) const
919 {
920 return wxPGVIterator( new wxPGVIteratorBase_State( m_pState, flags ) );
921 }
922
923 // -----------------------------------------------------------------------
924 // wxPGEditableState related functions
925 // -----------------------------------------------------------------------
926
927 // EscapeDelimiters() changes ";" into "\;" and "|" into "\|"
928 // in the input string. This is an internal functions which is
929 // used for saving states
930 // NB: Similar function exists in aui/framemanager.cpp
931 static wxString EscapeDelimiters(const wxString& s)
932 {
933 wxString result;
934 result.Alloc(s.length());
935 const wxChar* ch = s.c_str();
936 while (*ch)
937 {
938 if (*ch == wxT(';') || *ch == wxT('|') || *ch == wxT(','))
939 result += wxT('\\');
940 result += *ch;
941 ++ch;
942 }
943 return result;
944 }
945
946 wxString wxPropertyGridInterface::SaveEditableState( int includedStates ) const
947 {
948 wxString result;
949
950 //
951 // Save state on page basis
952 size_t pageIndex = 0;
953 wxPropertyGridPageState* pageState = GetPageState(pageIndex);
954 wxArrayPtrVoid pageStates;
955 while ( pageState )
956 {
957 pageStates.Add(pageState);
958 pageIndex += 1;
959 pageState = GetPageState(pageIndex);
960 }
961
962 for ( pageIndex=0; pageIndex < pageStates.size(); pageIndex++ )
963 {
964 wxPropertyGridPageState* pageState = (wxPropertyGridPageState*) pageStates[pageIndex];
965
966 if ( includedStates & SelectionState )
967 {
968 wxString sel;
969 if ( pageState->GetSelection() )
970 sel = pageState->GetSelection()->GetName();
971 result += wxS("selection=");
972 result += EscapeDelimiters(sel);
973 result += wxS(";");
974 }
975 if ( includedStates & ExpandedState )
976 {
977 wxArrayPGProperty ptrs;
978 wxPropertyGridConstIterator it =
979 wxPropertyGridConstIterator( pageState,
980 wxPG_ITERATE_ALL_PARENTS_RECURSIVELY|wxPG_ITERATE_HIDDEN,
981 wxNullProperty );
982
983 result += wxS("expanded=");
984
985 for ( ;
986 !it.AtEnd();
987 it.Next() )
988 {
989 const wxPGProperty* p = it.GetProperty();
990
991 if ( !p->HasFlag(wxPG_PROP_COLLAPSED) )
992 result += EscapeDelimiters(p->GetName());
993 result += wxS(",");
994
995 }
996
997 if ( result.Last() == wxS(',') )
998 result.RemoveLast();
999
1000 result += wxS(";");
1001 }
1002 if ( includedStates & ScrollPosState )
1003 {
1004 int x, y;
1005 GetPropertyGrid()->GetViewStart(&x,&y);
1006 result += wxString::Format(wxS("scrollpos=%i,%i;"), x, y);
1007 }
1008 if ( includedStates & SplitterPosState )
1009 {
1010 result += wxS("splitterpos=");
1011
1012 for ( size_t i=0; i<pageState->GetColumnCount(); i++ )
1013 result += wxString::Format(wxS("%i,"), pageState->DoGetSplitterPosition(i));
1014
1015 result.RemoveLast(); // Remove last comma
1016 result += wxS(";");
1017 }
1018 if ( includedStates & PageState )
1019 {
1020 result += wxS("ispageselected=");
1021
1022 if ( GetPageState(-1) == pageState )
1023 result += wxS("1;");
1024 else
1025 result += wxS("0;");
1026 }
1027 result.RemoveLast(); // Remove last semicolon
1028 result += wxS("|");
1029 }
1030
1031 // Remove last '|'
1032 if ( result.length() )
1033 result.RemoveLast();
1034
1035 return result;
1036 }
1037
1038 bool wxPropertyGridInterface::RestoreEditableState( const wxString& src, int restoreStates )
1039 {
1040 wxPropertyGrid* pg = GetPropertyGrid();
1041 wxPGProperty* newSelection = NULL;
1042 size_t pageIndex;
1043 long vx = -1;
1044 long vy = -1;
1045 long selectedPage = -1;
1046 bool pgSelectionSet = false;
1047 bool res = true;
1048
1049 pg->Freeze();
1050 wxArrayString pageStrings = ::wxSplit(src, wxS('|'), wxS('\\'));
1051
1052 for ( pageIndex=0; pageIndex<pageStrings.size(); pageIndex++ )
1053 {
1054 wxPropertyGridPageState* pageState = GetPageState(pageIndex);
1055 if ( !pageState )
1056 break;
1057
1058 wxArrayString kvpairStrings = ::wxSplit(pageStrings[pageIndex], wxS(';'), wxS('\\'));
1059
1060 for ( size_t i=0; i<kvpairStrings.size(); i++ )
1061 {
1062 const wxString& kvs = kvpairStrings[i];
1063 int eq_pos = kvs.Find(wxS('='));
1064 if ( eq_pos != wxNOT_FOUND )
1065 {
1066 wxString key = kvs.substr(0, eq_pos);
1067 wxString value = kvs.substr(eq_pos+1);
1068
1069 // Further split value by commas
1070 wxArrayString values = ::wxSplit(value, wxS(','), wxS('\\'));
1071
1072 if ( key == wxS("expanded") )
1073 {
1074 if ( restoreStates & ExpandedState )
1075 {
1076 wxPropertyGridIterator it =
1077 wxPropertyGridIterator( pageState,
1078 wxPG_ITERATE_ALL,
1079 wxNullProperty );
1080
1081 // First collapse all
1082 for ( ; !it.AtEnd(); it.Next() )
1083 {
1084 wxPGProperty* p = it.GetProperty();
1085 pageState->DoCollapse(p);
1086 }
1087
1088 // Then expand those which names are in values
1089 for ( size_t n=0; n<values.size(); n++ )
1090 {
1091 const wxString& name = values[n];
1092 wxPGProperty* prop = GetPropertyByName(name);
1093 if ( prop )
1094 pageState->DoExpand(prop);
1095 }
1096 }
1097 }
1098 else if ( key == wxS("scrollpos") )
1099 {
1100 if ( restoreStates & ScrollPosState )
1101 {
1102 if ( values.size() == 2 )
1103 {
1104 values[0].ToLong(&vx);
1105 values[1].ToLong(&vy);
1106 }
1107 else
1108 {
1109 res = false;
1110 }
1111 }
1112 }
1113 else if ( key == wxS("splitterpos") )
1114 {
1115 if ( restoreStates & SplitterPosState )
1116 {
1117 for ( size_t n=1; n<values.size(); n++ )
1118 {
1119 long pos = 0;
1120 values[n].ToLong(&pos);
1121 if ( pos > 0 )
1122 pageState->DoSetSplitterPosition(pos, n);
1123 }
1124 }
1125 }
1126 else if ( key == wxS("selection") )
1127 {
1128 if ( restoreStates & SelectionState )
1129 {
1130 if ( values.size() > 0 )
1131 {
1132 if ( pageState->IsDisplayed() )
1133 {
1134 if ( values[0].length() )
1135 newSelection = GetPropertyByName(value);
1136 pgSelectionSet = true;
1137 }
1138 else
1139 {
1140 if ( values[0].length() )
1141 pageState->SetSelection(GetPropertyByName(value));
1142 else
1143 pageState->DoClearSelection();
1144 }
1145 }
1146 }
1147 }
1148 else if ( key == wxS("ispageselected") )
1149 {
1150 if ( restoreStates & PageState )
1151 {
1152 long pageSelStatus;
1153 if ( values.size() == 1 && values[0].ToLong(&pageSelStatus) )
1154 {
1155 if ( pageSelStatus )
1156 selectedPage = pageIndex;
1157 }
1158 else
1159 {
1160 res = false;
1161 }
1162 }
1163 }
1164 else
1165 {
1166 res = false;
1167 }
1168 }
1169 }
1170 }
1171
1172 //
1173 // Force recalculation of virtual heights of all pages
1174 // (may be needed on unclean source string).
1175 pageIndex = 0;
1176 wxPropertyGridPageState* pageState = GetPageState(pageIndex);
1177 while ( pageState )
1178 {
1179 pageState->VirtualHeightChanged();
1180 pageIndex += 1;
1181 pageState = GetPageState(pageIndex);
1182 }
1183
1184 pg->Thaw();
1185
1186 //
1187 // Selection of visible grid page must be set after Thaw() call
1188 if ( pgSelectionSet )
1189 {
1190 if ( newSelection )
1191 pg->SelectProperty(newSelection);
1192 else
1193 pg->ClearSelection();
1194 }
1195
1196 if ( selectedPage != -1 )
1197 {
1198 DoSelectPage(selectedPage);
1199 }
1200
1201 if ( vx >= 0 )
1202 {
1203 pg->Scroll(vx, vy);
1204 }
1205
1206 return res;
1207 }
1208