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