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