Moved SetPropertyAttributeAll() to wxPropertyGridInterface
[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::SetPropertyAttributeAll( const wxString& attrName,
553 wxVariant value )
554 {
555 unsigned int pageIndex = 0;
556
557 for (;;)
558 {
559 wxPropertyGridPageState* page = GetPageState(pageIndex);
560 if ( !page ) break;
561
562 DoSetPropertyAttribute(page->DoGetRoot(), attrName, value, wxPG_RECURSE);
563
564 pageIndex++;
565 }
566 }
567
568 // -----------------------------------------------------------------------
569
570 void wxPropertyGridInterface::GetPropertiesWithFlag( wxArrayPGProperty* targetArr,
571 wxPGProperty::FlagType flags,
572 bool inverse,
573 int iterFlags ) const
574 {
575 wxASSERT( targetArr );
576 wxPGVIterator it = GetVIterator( iterFlags );
577
578 for ( ;
579 !it.AtEnd();
580 it.Next() )
581 {
582 const wxPGProperty* property = it.GetProperty();
583
584 if ( !inverse )
585 {
586 if ( (property->GetFlags() & flags) == flags )
587 targetArr->push_back((wxPGProperty*)property);
588 }
589 else
590 {
591 if ( (property->GetFlags() & flags) != flags )
592 targetArr->push_back((wxPGProperty*)property);
593 }
594 }
595 }
596
597 // -----------------------------------------------------------------------
598
599 void wxPropertyGridInterface::SetPropertiesFlag( const wxArrayPGProperty& srcArr,
600 wxPGProperty::FlagType flags,
601 bool inverse )
602 {
603 unsigned int i;
604
605 for ( i=0; i<srcArr.size(); i++ )
606 {
607 wxPGProperty* property = srcArr[i];
608
609 if ( !inverse )
610 property->SetFlag(flags);
611 else
612 property->ClearFlag(flags);
613 }
614
615 // If collapsed flag or hidden was manipulated, we need to update virtual
616 // size.
617 wxPropertyGrid* pg = GetPropertyGrid();
618 if ( flags & (wxPG_PROP_COLLAPSED|wxPG_PROP_HIDDEN) )
619 {
620 GetState()->VirtualHeightChanged();
621 pg->RecalculateVirtualSize();
622 }
623 }
624
625 // -----------------------------------------------------------------------
626
627 void wxPropertyGridInterface::SetBoolChoices( const wxString& trueChoice,
628 const wxString& falseChoice )
629 {
630 wxPGGlobalVars->m_boolChoices[0] = falseChoice;
631 wxPGGlobalVars->m_boolChoices[1] = trueChoice;
632 }
633
634 // -----------------------------------------------------------------------
635
636 wxPGProperty* wxPropertyGridInterface::DoGetPropertyByName( const wxString& name ) const
637 {
638 return m_pState->BaseGetPropertyByName(name);
639 }
640
641 // -----------------------------------------------------------------------
642
643 wxPGProperty* wxPropertyGridInterface::GetPropertyByName( const wxString& name,
644 const wxString& subname ) const
645 {
646 wxPGProperty* p = DoGetPropertyByName(name);
647 if ( !p || !p->GetChildCount() )
648 return wxNullProperty;
649
650 return p->GetPropertyByName(subname);
651 }
652
653 // -----------------------------------------------------------------------
654
655 // Since GetPropertyByName is used *a lot*, this makes sense
656 // since non-virtual method can be called with less code.
657 wxPGProperty* wxPropertyGridInterface::GetPropertyByName( const wxString& name ) const
658 {
659 wxPGProperty* p = DoGetPropertyByName(name);
660 if ( p )
661 return p;
662
663 // Check if its "Property.SubProperty" format
664 int pos = name.Find(wxT('.'));
665 if ( pos <= 0 )
666 return NULL;
667
668 return GetPropertyByName(name.substr(0,pos),
669 name.substr(pos+1,name.length()-pos-1));
670 }
671
672 // -----------------------------------------------------------------------
673
674 bool wxPropertyGridInterface::HideProperty( wxPGPropArg id, bool hide, int flags )
675 {
676 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
677
678 wxPropertyGrid* pg = m_pState->GetGrid();
679
680 if ( pg == p->GetGrid() )
681 return pg->DoHideProperty(p, hide, flags);
682 else
683 m_pState->DoHideProperty(p, hide, flags);
684
685 return true;
686 }
687
688 // -----------------------------------------------------------------------
689
690 bool wxPropertyGridInterface::Collapse( wxPGPropArg id )
691 {
692 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
693 wxPropertyGrid* pg = p->GetGridIfDisplayed();
694 if ( pg )
695 return pg->DoCollapse(p);
696
697 return p->GetParentState()->DoCollapse(p);
698 }
699
700 // -----------------------------------------------------------------------
701
702 bool wxPropertyGridInterface::Expand( wxPGPropArg id )
703 {
704 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
705 wxPropertyGrid* pg = p->GetGridIfDisplayed();
706 if ( pg )
707 return pg->DoExpand(p);
708
709 return p->GetParentState()->DoExpand(p);
710 }
711
712 // -----------------------------------------------------------------------
713
714 void wxPropertyGridInterface::SetPropertyLabel( wxPGPropArg id, const wxString& newproplabel )
715 {
716 wxPG_PROP_ARG_CALL_PROLOG()
717
718 p->SetLabel( newproplabel );
719
720 wxPropertyGridPageState* state = p->GetParentState();
721 wxPropertyGrid* pg = state->GetGrid();
722
723 if ( pg->HasFlag(wxPG_AUTO_SORT) )
724 pg->SortChildren(p->GetParent());
725
726 if ( pg->GetState() == state )
727 {
728 if ( pg->HasFlag(wxPG_AUTO_SORT) )
729 pg->Refresh();
730 else
731 pg->DrawItem( p );
732 }
733 }
734
735 // -----------------------------------------------------------------------
736
737 bool wxPropertyGridInterface::SetPropertyMaxLength( wxPGPropArg id, int maxLen )
738 {
739 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
740
741 wxPropertyGrid* pg = m_pState->GetGrid();
742
743 p->m_maxLen = (short) maxLen;
744
745 // Adjust control if selected currently
746 if ( pg == p->GetGrid() && p == m_pState->GetSelection() )
747 {
748 wxWindow* wnd = pg->GetEditorControl();
749 wxTextCtrl* tc = wxDynamicCast(wnd,wxTextCtrl);
750 if ( tc )
751 tc->SetMaxLength( maxLen );
752 else
753 // Not a text ctrl
754 return false;
755 }
756
757 return true;
758 }
759
760 // -----------------------------------------------------------------------
761 // GetPropertyValueAsXXX methods
762
763 #define IMPLEMENT_GET_VALUE(T,TRET,BIGNAME,DEFRETVAL) \
764 TRET wxPropertyGridInterface::GetPropertyValueAs##BIGNAME( wxPGPropArg id ) const \
765 { \
766 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(DEFRETVAL) \
767 wxVariant value = p->GetValue(); \
768 if ( wxStrcmp(value.GetType(), wxPGTypeName_##T) != 0 ) \
769 { \
770 wxPGGetFailed(p,wxPGTypeName_##T); \
771 return (TRET)DEFRETVAL; \
772 } \
773 return (TRET)value.Get##BIGNAME(); \
774 }
775
776 // String is different than others.
777 wxString wxPropertyGridInterface::GetPropertyValueAsString( wxPGPropArg id ) const
778 {
779 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxEmptyString)
780 return p->GetValueAsString(wxPG_FULL_VALUE);
781 }
782
783 bool wxPropertyGridInterface::GetPropertyValueAsBool( wxPGPropArg id ) const
784 {
785 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
786 wxVariant value = p->GetValue();
787 if ( wxStrcmp(value.GetType(), wxPGTypeName_bool) == 0 )
788 {
789 return value.GetBool();
790 }
791 if ( wxStrcmp(value.GetType(), wxPGTypeName_long) == 0 )
792 {
793 return value.GetLong()?true:false;
794 }
795 wxPGGetFailed(p,wxPGTypeName_bool);
796 return false;
797 }
798
799 IMPLEMENT_GET_VALUE(long,long,Long,0)
800 IMPLEMENT_GET_VALUE(double,double,Double,0.0)
801 IMPLEMENT_GET_VALUE(void,void*,VoidPtr,NULL)
802
803 bool wxPropertyGridInterface::IsPropertyExpanded( wxPGPropArg id ) const
804 {
805 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
806 return p->IsExpanded();
807 }
808
809 // -----------------------------------------------------------------------
810 // wxPropertyGridInterface wrappers
811 // -----------------------------------------------------------------------
812
813 bool wxPropertyGridInterface::ChangePropertyValue( wxPGPropArg id, wxVariant newValue )
814 {
815 return GetPropertyGrid()->ChangePropertyValue(id, newValue);
816 }
817
818 // -----------------------------------------------------------------------
819
820 void wxPropertyGridInterface::BeginAddChildren( wxPGPropArg id )
821 {
822 wxPG_PROP_ARG_CALL_PROLOG()
823 wxCHECK_RET( p->HasFlag(wxPG_PROP_AGGREGATE), wxT("only call on properties with fixed children") );
824 p->ClearFlag(wxPG_PROP_AGGREGATE);
825 p->SetFlag(wxPG_PROP_MISC_PARENT);
826 }
827
828 // -----------------------------------------------------------------------
829
830 bool wxPropertyGridInterface::EditorValidate()
831 {
832 return GetPropertyGrid()->DoEditorValidate();
833 }
834
835 // -----------------------------------------------------------------------
836
837 void wxPropertyGridInterface::EndAddChildren( wxPGPropArg id )
838 {
839 wxPG_PROP_ARG_CALL_PROLOG()
840 wxCHECK_RET( p->HasFlag(wxPG_PROP_MISC_PARENT), wxT("only call on properties for which BeginAddChildren was called prior") );
841 p->ClearFlag(wxPG_PROP_MISC_PARENT);
842 p->SetFlag(wxPG_PROP_AGGREGATE);
843 }
844
845 // -----------------------------------------------------------------------
846 // wxPGVIterator_State
847 // -----------------------------------------------------------------------
848
849 // Default returned by wxPropertyGridInterface::GetVIterator().
850 class wxPGVIteratorBase_State : public wxPGVIteratorBase
851 {
852 public:
853 wxPGVIteratorBase_State( wxPropertyGridPageState* state, int flags )
854 {
855 m_it.Init( state, flags );
856 }
857 virtual ~wxPGVIteratorBase_State() { }
858 virtual void Next() { m_it.Next(); }
859 };
860
861 wxPGVIterator wxPropertyGridInterface::GetVIterator( int flags ) const
862 {
863 return wxPGVIterator( new wxPGVIteratorBase_State( m_pState, flags ) );
864 }
865
866 // -----------------------------------------------------------------------
867 // wxPGEditableState related functions
868 // -----------------------------------------------------------------------
869
870 // EscapeDelimiters() changes ";" into "\;" and "|" into "\|"
871 // in the input string. This is an internal functions which is
872 // used for saving states
873 // NB: Similar function exists in aui/framemanager.cpp
874 static wxString EscapeDelimiters(const wxString& s)
875 {
876 wxString result;
877 result.Alloc(s.length());
878 const wxChar* ch = s.c_str();
879 while (*ch)
880 {
881 if (*ch == wxT(';') || *ch == wxT('|') || *ch == wxT(','))
882 result += wxT('\\');
883 result += *ch;
884 ++ch;
885 }
886 return result;
887 }
888
889 wxString wxPropertyGridInterface::SaveEditableState( int includedStates ) const
890 {
891 wxString result;
892
893 //
894 // Save state on page basis
895 unsigned int pageIndex = 0;
896 wxArrayPtrVoid pageStates;
897
898 for (;;)
899 {
900 wxPropertyGridPageState* page = GetPageState(pageIndex);
901 if ( !page ) break;
902
903 pageStates.Add(page);
904
905 pageIndex++;
906 }
907
908 for ( pageIndex=0; pageIndex < pageStates.size(); pageIndex++ )
909 {
910 wxPropertyGridPageState* pageState = (wxPropertyGridPageState*) pageStates[pageIndex];
911
912 if ( includedStates & SelectionState )
913 {
914 wxString sel;
915 if ( pageState->GetSelection() )
916 sel = pageState->GetSelection()->GetName();
917 result += wxS("selection=");
918 result += EscapeDelimiters(sel);
919 result += wxS(";");
920 }
921 if ( includedStates & ExpandedState )
922 {
923 wxArrayPGProperty ptrs;
924 wxPropertyGridConstIterator it =
925 wxPropertyGridConstIterator( pageState,
926 wxPG_ITERATE_ALL_PARENTS_RECURSIVELY|wxPG_ITERATE_HIDDEN,
927 wxNullProperty );
928
929 result += wxS("expanded=");
930
931 for ( ;
932 !it.AtEnd();
933 it.Next() )
934 {
935 const wxPGProperty* p = it.GetProperty();
936
937 if ( !p->HasFlag(wxPG_PROP_COLLAPSED) )
938 result += EscapeDelimiters(p->GetName());
939 result += wxS(",");
940
941 }
942
943 if ( result.Last() == wxS(',') )
944 result.RemoveLast();
945
946 result += wxS(";");
947 }
948 if ( includedStates & ScrollPosState )
949 {
950 int x, y;
951 GetPropertyGrid()->GetViewStart(&x,&y);
952 result += wxString::Format(wxS("scrollpos=%i,%i;"), x, y);
953 }
954 if ( includedStates & SplitterPosState )
955 {
956 result += wxS("splitterpos=");
957
958 for ( size_t i=0; i<pageState->GetColumnCount(); i++ )
959 result += wxString::Format(wxS("%i,"), pageState->DoGetSplitterPosition(i));
960
961 result.RemoveLast(); // Remove last comma
962 result += wxS(";");
963 }
964 if ( includedStates & PageState )
965 {
966 result += wxS("ispageselected=");
967
968 if ( GetPageState(-1) == pageState )
969 result += wxS("1;");
970 else
971 result += wxS("0;");
972 }
973 result.RemoveLast(); // Remove last semicolon
974 result += wxS("|");
975 }
976
977 // Remove last '|'
978 if ( result.length() )
979 result.RemoveLast();
980
981 return result;
982 }
983
984 bool wxPropertyGridInterface::RestoreEditableState( const wxString& src, int restoreStates )
985 {
986 wxPropertyGrid* pg = GetPropertyGrid();
987 wxPGProperty* newSelection = NULL;
988 size_t pageIndex;
989 long vx = -1;
990 long vy = -1;
991 long selectedPage = -1;
992 bool pgSelectionSet = false;
993 bool res = true;
994
995 pg->Freeze();
996 wxArrayString pageStrings = ::wxSplit(src, wxS('|'), wxS('\\'));
997
998 for ( pageIndex=0; pageIndex<pageStrings.size(); pageIndex++ )
999 {
1000 wxPropertyGridPageState* pageState = GetPageState(pageIndex);
1001 if ( !pageState )
1002 break;
1003
1004 wxArrayString kvpairStrings = ::wxSplit(pageStrings[pageIndex], wxS(';'), wxS('\\'));
1005
1006 for ( size_t i=0; i<kvpairStrings.size(); i++ )
1007 {
1008 const wxString& kvs = kvpairStrings[i];
1009 int eq_pos = kvs.Find(wxS('='));
1010 if ( eq_pos != wxNOT_FOUND )
1011 {
1012 wxString key = kvs.substr(0, eq_pos);
1013 wxString value = kvs.substr(eq_pos+1);
1014
1015 // Further split value by commas
1016 wxArrayString values = ::wxSplit(value, wxS(','), wxS('\\'));
1017
1018 if ( key == wxS("expanded") )
1019 {
1020 if ( restoreStates & ExpandedState )
1021 {
1022 wxPropertyGridIterator it =
1023 wxPropertyGridIterator( pageState,
1024 wxPG_ITERATE_ALL,
1025 wxNullProperty );
1026
1027 // First collapse all
1028 for ( ; !it.AtEnd(); it.Next() )
1029 {
1030 wxPGProperty* p = it.GetProperty();
1031 pageState->DoCollapse(p);
1032 }
1033
1034 // Then expand those which names are in values
1035 for ( size_t n=0; n<values.size(); n++ )
1036 {
1037 const wxString& name = values[n];
1038 wxPGProperty* prop = GetPropertyByName(name);
1039 if ( prop )
1040 pageState->DoExpand(prop);
1041 }
1042 }
1043 }
1044 else if ( key == wxS("scrollpos") )
1045 {
1046 if ( restoreStates & ScrollPosState )
1047 {
1048 if ( values.size() == 2 )
1049 {
1050 values[0].ToLong(&vx);
1051 values[1].ToLong(&vy);
1052 }
1053 else
1054 {
1055 res = false;
1056 }
1057 }
1058 }
1059 else if ( key == wxS("splitterpos") )
1060 {
1061 if ( restoreStates & SplitterPosState )
1062 {
1063 for ( size_t n=1; n<values.size(); n++ )
1064 {
1065 long pos = 0;
1066 values[n].ToLong(&pos);
1067 if ( pos > 0 )
1068 pageState->DoSetSplitterPosition(pos, n);
1069 }
1070 }
1071 }
1072 else if ( key == wxS("selection") )
1073 {
1074 if ( restoreStates & SelectionState )
1075 {
1076 if ( values.size() > 0 )
1077 {
1078 if ( pageState->IsDisplayed() )
1079 {
1080 if ( values[0].length() )
1081 newSelection = GetPropertyByName(value);
1082 pgSelectionSet = true;
1083 }
1084 else
1085 {
1086 if ( values[0].length() )
1087 pageState->SetSelection(GetPropertyByName(value));
1088 else
1089 pageState->DoClearSelection();
1090 }
1091 }
1092 }
1093 }
1094 else if ( key == wxS("ispageselected") )
1095 {
1096 if ( restoreStates & PageState )
1097 {
1098 long pageSelStatus;
1099 if ( values.size() == 1 && values[0].ToLong(&pageSelStatus) )
1100 {
1101 if ( pageSelStatus )
1102 selectedPage = pageIndex;
1103 }
1104 else
1105 {
1106 res = false;
1107 }
1108 }
1109 }
1110 else
1111 {
1112 res = false;
1113 }
1114 }
1115 }
1116 }
1117
1118 //
1119 // Force recalculation of virtual heights of all pages
1120 // (may be needed on unclean source string).
1121 pageIndex = 0;
1122 wxPropertyGridPageState* pageState = GetPageState(pageIndex);
1123 while ( pageState )
1124 {
1125 pageState->VirtualHeightChanged();
1126 pageIndex += 1;
1127 pageState = GetPageState(pageIndex);
1128 }
1129
1130 pg->Thaw();
1131
1132 //
1133 // Selection of visible grid page must be set after Thaw() call
1134 if ( pgSelectionSet )
1135 {
1136 if ( newSelection )
1137 pg->SelectProperty(newSelection);
1138 else
1139 pg->ClearSelection();
1140 }
1141
1142 if ( selectedPage != -1 )
1143 {
1144 DoSelectPage(selectedPage);
1145 }
1146
1147 if ( vx >= 0 )
1148 {
1149 pg->Scroll(vx, vy);
1150 }
1151
1152 return res;
1153 }
1154
1155 #endif // wxUSE_PROPGRID
1156