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