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