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