]> git.saurik.com Git - wxWidgets.git/blob - src/propgrid/propgridiface.cpp
bf59ef030575ffebd55e2cb024e93cc6d44c6c41
[wxWidgets.git] / src / propgrid / propgridiface.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/propgridiface.cpp
3 // Purpose: wxPropertyGridInterface class
4 // Author: Jaakko Salli
5 // Modified by:
6 // Created: 2008-08-24
7 // RCS-ID: $Id:
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include "wx/defs.h"
21 #include "wx/object.h"
22 #include "wx/hash.h"
23 #include "wx/string.h"
24 #include "wx/log.h"
25 #include "wx/event.h"
26 #include "wx/window.h"
27 #include "wx/panel.h"
28 #include "wx/dc.h"
29 #include "wx/dcmemory.h"
30 #include "wx/button.h"
31 #include "wx/pen.h"
32 #include "wx/brush.h"
33 #include "wx/cursor.h"
34 #include "wx/dialog.h"
35 #include "wx/settings.h"
36 #include "wx/msgdlg.h"
37 #include "wx/choice.h"
38 #include "wx/stattext.h"
39 #include "wx/scrolwin.h"
40 #include "wx/dirdlg.h"
41 #include "wx/layout.h"
42 #include "wx/sizer.h"
43 #include "wx/textdlg.h"
44 #include "wx/filedlg.h"
45 #include "wx/statusbr.h"
46 #include "wx/intl.h"
47 #include "wx/frame.h"
48 #endif
49
50 #include <wx/propgrid/property.h>
51 #include <wx/propgrid/propgrid.h>
52
53
54 const wxChar *wxPGTypeName_long = wxT("long");
55 const wxChar *wxPGTypeName_bool = wxT("bool");
56 const wxChar *wxPGTypeName_double = wxT("double");
57 const wxChar *wxPGTypeName_wxString = wxT("string");
58 const wxChar *wxPGTypeName_void = wxT("void*");
59 const wxChar *wxPGTypeName_wxArrayString = wxT("arrstring");
60
61
62 // ----------------------------------------------------------------------------
63 // VariantDatas
64 // ----------------------------------------------------------------------------
65
66 WX_PG_IMPLEMENT_VARIANT_DATA(wxPGVariantDataPoint, wxPoint)
67 WX_PG_IMPLEMENT_VARIANT_DATA(wxPGVariantDataSize, wxSize)
68 WX_PG_IMPLEMENT_VARIANT_DATA(wxPGVariantDataArrayInt, wxArrayInt)
69 WX_PG_IMPLEMENT_VARIANT_DATA(wxPGVariantDataLongLong, wxLongLong)
70 WX_PG_IMPLEMENT_VARIANT_DATA(wxPGVariantDataULongLong, wxULongLong)
71
72 WX_PG_IMPLEMENT_WXOBJECT_VARIANT_DATA(wxPGVariantDataFont, wxFont)
73
74 wxObject* wxPG_VariantToWxObject( const wxVariant& variant, wxClassInfo* classInfo )
75 {
76 if ( !variant.IsValueKindOf(classInfo) )
77 return (wxObject*) NULL;
78
79 wxVariantData* vdata = variant.GetData();
80
81 wxPGVariantData* pgvdata = wxDynamicCastVariantData(vdata, wxPGVariantData);
82 if ( pgvdata )
83 return (wxObject*) pgvdata->GetValuePtr();
84
85 if ( wxPGIsVariantClassInfo(wxPGVariantDataGetClassInfo(vdata), wxobject) )
86 return variant.GetWxObjectPtr();
87
88 return (wxObject*) NULL;
89 }
90
91 // -----------------------------------------------------------------------
92 // wxVariant helpers
93 // -----------------------------------------------------------------------
94
95 long wxPGVariantToInt( const wxVariant& variant, long defVal )
96 {
97 if ( variant.IsNull() )
98 return defVal;
99
100 if ( wxPGIsVariantType(variant, long) )
101 return variant.GetLong();
102
103 if ( wxPGIsVariantType(variant, bool) )
104 return variant.GetBool() ? 1 : 0;
105
106 if ( typeid(*variant.GetData()) == typeid(wxPGVariantDataLongLong) )
107 {
108 wxLongLong ll = ((const wxPGVariantDataLongLong&)variant).GetValue();
109 if ( ll >= LONG_MAX )
110 return LONG_MAX;
111 else if ( ll <= LONG_MIN )
112 return LONG_MIN;
113 return ll.ToLong();
114 }
115
116 long l = defVal;
117
118 if ( wxPGIsVariantType(variant, string) )
119 variant.GetString().ToLong(&l, 0);
120
121 return l;
122 }
123
124 // -----------------------------------------------------------------------
125
126 bool wxPGVariantToLongLong( const wxVariant& variant, wxLongLong_t* pResult )
127 {
128 if ( variant.IsNull() )
129 return false;
130
131 if ( wxPGIsVariantType(variant, long) )
132 {
133 *pResult = variant.GetLong();
134 return true;
135 }
136
137 if ( typeid(*variant.GetData()) == typeid(wxPGVariantDataLongLong) )
138 {
139 *pResult = ((const wxPGVariantDataLongLong&)variant).GetValue().GetValue();
140 return true;
141 }
142
143 return false;
144 }
145
146 // -----------------------------------------------------------------------
147
148 bool wxPGVariantToULongLong( const wxVariant& variant, wxULongLong_t* pResult )
149 {
150 if ( variant.IsNull() )
151 return false;
152
153 if ( wxPGIsVariantType(variant, long) )
154 {
155 *pResult = (unsigned long)variant.GetLong();
156 return true;
157 }
158
159 if ( typeid(*variant.GetData()) == typeid(wxPGVariantDataULongLong) )
160 {
161 *pResult = ((const wxPGVariantDataULongLong&)variant).GetValue().GetValue();
162 return true;
163 }
164
165 return false;
166 }
167
168 // -----------------------------------------------------------------------
169
170 bool wxPGVariantToDouble( const wxVariant& variant, double* pResult )
171 {
172 if ( variant.IsNull() )
173 return false;
174
175 if ( wxPGIsVariantType(variant, double) )
176 {
177 *pResult = variant.GetDouble();
178 return true;
179 }
180
181 if ( wxPGIsVariantType(variant, long) )
182 {
183 *pResult = (double)variant.GetLong();
184 return true;
185 }
186
187 if ( typeid(*variant.GetData()) == typeid(wxPGVariantDataLongLong) )
188 {
189 wxLongLong ll = ((const wxPGVariantDataLongLong&)variant).GetValue();
190 *pResult = ll.ToDouble();
191 return true;
192 }
193
194 if ( wxPGIsVariantType(variant, string) )
195 if ( variant.GetString().ToDouble(pResult) )
196 return true;
197
198 return false;
199 }
200
201 // -----------------------------------------------------------------------
202 // Choice related methods
203 // -----------------------------------------------------------------------
204
205 void wxPropertyGridInterface::AddPropertyChoice( wxPGPropArg id,
206 const wxString& label,
207 int value )
208 {
209 wxPG_PROP_ARG_CALL_PROLOG()
210
211 p->InsertChoice(label,-1,value);
212 }
213
214
215 void wxPropertyGridInterface::InsertPropertyChoice( wxPGPropArg id,
216 const wxString& label,
217 int index,
218 int value )
219 {
220 wxPG_PROP_ARG_CALL_PROLOG()
221
222 p->InsertChoice(label,index,value);
223 }
224
225
226 void wxPropertyGridInterface::DeletePropertyChoice( wxPGPropArg id,
227 int index )
228 {
229 wxPG_PROP_ARG_CALL_PROLOG()
230
231 p->DeleteChoice(index);
232 }
233
234 // -----------------------------------------------------------------------
235
236 void wxPropertyGridInterface::RefreshGrid( wxPropertyGridPageState* state )
237 {
238 if ( !state )
239 state = m_pState;
240
241 wxPropertyGrid* grid = state->GetGrid();
242 if ( grid->GetState() == state && !grid->IsFrozen() )
243 {
244 grid->Refresh();
245 }
246 }
247
248 // -----------------------------------------------------------------------
249
250 wxPGProperty* wxPropertyGridInterface::Append( wxPGProperty* property )
251 {
252 wxPGProperty* retp = m_pState->DoAppend(property);
253
254 wxPropertyGrid* grid = m_pState->GetGrid();
255 if ( grid )
256 grid->RefreshGrid();
257
258 return retp;
259 }
260
261 // -----------------------------------------------------------------------
262
263 wxPGProperty* wxPropertyGridInterface::AppendIn( wxPGPropArg id, wxPGProperty* newproperty )
264 {
265 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
266 wxPGProperty* pwc = (wxPGProperty*) p;
267 wxPGProperty* retp = m_pState->DoInsert(pwc, pwc->GetChildCount(), newproperty);
268 return retp;
269 }
270
271 // -----------------------------------------------------------------------
272
273 wxPGProperty* wxPropertyGridInterface::Insert( wxPGPropArg id, wxPGProperty* property )
274 {
275 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
276 wxPGProperty* retp = m_pState->DoInsert(p->GetParent(), p->GetArrIndex(), property);
277 RefreshGrid();
278 return retp;
279 }
280
281 // -----------------------------------------------------------------------
282
283 wxPGProperty* wxPropertyGridInterface::Insert( wxPGPropArg id, int index, wxPGProperty* newproperty )
284 {
285 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
286 wxPGProperty* retp = m_pState->DoInsert((wxPGProperty*)p,index,newproperty);
287 RefreshGrid();
288 return retp;
289 }
290
291 // -----------------------------------------------------------------------
292
293 void wxPropertyGridInterface::DeleteProperty( wxPGPropArg id )
294 {
295 wxPG_PROP_ARG_CALL_PROLOG()
296
297 wxPropertyGridPageState* state = p->GetParentState();
298 wxPropertyGrid* grid = state->GetGrid();
299
300 if ( grid->GetState() == state )
301 {
302 bool selRes = grid->DoSelectProperty(NULL, wxPG_SEL_DELETING);
303 wxPG_CHECK_RET_DBG( selRes,
304 wxT("failed to deselect a property (editor probably had invalid value)") );
305 }
306
307 state->DoDelete( p );
308
309 RefreshGrid(state);
310 }
311
312 // -----------------------------------------------------------------------
313
314 wxPGProperty* wxPropertyGridInterface::ReplaceProperty( wxPGPropArg id, wxPGProperty* property )
315 {
316 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxNullProperty)
317
318 wxPGProperty* replaced = p;
319 wxCHECK_MSG( replaced && property,
320 wxNullProperty,
321 wxT("NULL property") );
322 wxCHECK_MSG( !replaced->IsCategory(),
323 wxNullProperty,
324 wxT("cannot replace this type of property") );
325 wxCHECK_MSG( !m_pState->IsInNonCatMode(),
326 wxNullProperty,
327 wxT("cannot replace properties in alphabetic mode") );
328
329 // Get address to the slot
330 wxPGProperty* parent = replaced->GetParent();
331 int ind = replaced->GetIndexInParent();
332
333 wxPropertyGridPageState* state = replaced->GetParentState();
334 DeleteProperty(replaced); // Must use generic Delete
335 state->DoInsert(parent,ind,property);
336
337 return property;
338 }
339
340 // -----------------------------------------------------------------------
341 // wxPropertyGridInterface property operations
342 // -----------------------------------------------------------------------
343
344 bool wxPropertyGridInterface::ClearSelection()
345 {
346 wxPropertyGridPageState* state = m_pState;
347 wxPropertyGrid* pg = state->GetGrid();
348 if ( pg->GetState() == state )
349 return pg->DoClearSelection();
350 else
351 state->SetSelection(NULL);
352 return true;
353 }
354
355 // -----------------------------------------------------------------------
356
357 void wxPropertyGridInterface::LimitPropertyEditing( wxPGPropArg id, bool limit )
358 {
359 wxPG_PROP_ARG_CALL_PROLOG()
360
361 m_pState->DoLimitPropertyEditing(p, limit);
362 RefreshProperty(p);
363 }
364
365 // -----------------------------------------------------------------------
366
367 bool wxPropertyGridInterface::EnableProperty( wxPGPropArg id, bool enable )
368 {
369 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
370
371 wxPropertyGridPageState* state = p->GetParentState();
372 wxPropertyGrid* grid = state->GetGrid();
373
374 if ( enable )
375 {
376 if ( !(p->m_flags & wxPG_PROP_DISABLED) )
377 return false;
378
379 // If active, Set active Editor.
380 if ( grid->GetState() == state && p == grid->GetSelection() )
381 grid->DoSelectProperty( p, wxPG_SEL_FORCE );
382 }
383 else
384 {
385 if ( p->m_flags & wxPG_PROP_DISABLED )
386 return false;
387
388 // If active, Disable as active Editor.
389 if ( grid->GetState() == state && p == grid->GetSelection() )
390 grid->DoSelectProperty( p, wxPG_SEL_FORCE );
391 }
392
393 state->DoEnableProperty(p, enable);
394
395 RefreshProperty( p );
396
397 return true;
398 }
399
400 // -----------------------------------------------------------------------
401
402 bool wxPropertyGridInterface::ExpandAll( bool doExpand )
403 {
404 wxPropertyGridPageState* state = m_pState;
405
406 if ( !state->DoGetRoot()->GetChildCount() )
407 return true;
408
409 wxPropertyGrid* pg = state->GetGrid();
410
411 if ( GetSelection() && GetSelection() != state->DoGetRoot() &&
412 !doExpand )
413 {
414 if ( !pg->ClearSelection() )
415 return false;
416 }
417
418 wxPGVIterator it;
419
420 for ( it = GetVIterator( wxPG_ITERATE_ALL ); !it.AtEnd(); it.Next() )
421 {
422 wxPGProperty* p = (wxPGProperty*) it.GetProperty();
423 if ( p->GetChildCount() )
424 {
425 if ( doExpand )
426 {
427 if ( !p->IsExpanded() )
428 {
429 state->DoExpand(p);
430 }
431 }
432 else
433 {
434 if ( p->IsExpanded() )
435 {
436 state->DoCollapse(p);
437 }
438 }
439 }
440 }
441
442 pg->RecalculateVirtualSize();
443
444 RefreshGrid();
445
446 return true;
447 }
448
449 // -----------------------------------------------------------------------
450
451 void wxPropertyGridInterface::SetPropertyValueUnspecified( wxPGPropArg id )
452 {
453 wxPG_PROP_ARG_CALL_PROLOG()
454 wxPropertyGrid* propGrid = p->GetGridIfDisplayed();
455 if ( propGrid )
456 propGrid->DoSetPropertyValueUnspecified(p);
457 else
458 p->GetParentState()->DoSetPropertyValueUnspecified(p);
459 }
460
461 // -----------------------------------------------------------------------
462 // wxPropertyGridInterface property value setting and getting
463 // -----------------------------------------------------------------------
464
465 void wxPGGetFailed( const wxPGProperty* p, const wxChar* typestr )
466 {
467 wxPGTypeOperationFailed(p,typestr,wxT("Get"));
468 }
469
470 // -----------------------------------------------------------------------
471
472 void wxPGTypeOperationFailed( const wxPGProperty* p, const wxChar* typestr,
473 const wxChar* op )
474 {
475 wxASSERT( p != NULL );
476 wxLogError( _("Type operation \"%s\" failed: Property labeled \"%s\" is of type \"%s\", NOT \"%s\"."),
477 op,p->GetLabel().c_str(),p->GetValue().GetType().c_str(),typestr );
478 }
479
480 // -----------------------------------------------------------------------
481
482 void wxPropertyGridInterface::SetPropVal( wxPGPropArg id, wxVariant& value )
483 {
484 wxPG_PROP_ARG_CALL_PROLOG()
485
486 if ( p )
487 {
488 p->SetValue(value);
489 wxPropertyGrid* propGrid = p->GetGridIfDisplayed();
490 if ( propGrid )
491 propGrid->DrawItemAndValueRelated( p );
492
493 }
494 }
495
496 // -----------------------------------------------------------------------
497
498 void wxPropertyGridInterface::SetPropertyValueString( wxPGPropArg id, const wxString& value )
499 {
500 wxPG_PROP_ARG_CALL_PROLOG()
501
502 if ( m_pState->DoSetPropertyValueString(p,value) )
503 {
504 wxPropertyGrid* propGrid = p->GetGridIfDisplayed();
505 if ( propGrid )
506 propGrid->DrawItemAndValueRelated( p );
507 }
508 }
509
510 // -----------------------------------------------------------------------
511
512 void wxPropertyGridInterface::SetValidationFailureBehavior( int vfbFlags )
513 {
514 GetPropertyGrid()->m_permanentValidationFailureBehavior = vfbFlags;
515 }
516
517 // -----------------------------------------------------------------------
518
519 wxPGProperty* wxPropertyGridInterface::GetPropertyByNameA( const wxString& name ) const
520 {
521 wxPGProperty* p = GetPropertyByName(name);
522 wxASSERT_MSG(p,wxString::Format(wxT("no property with name '%s'"),name.c_str()));
523 return p;
524 }
525
526 // ----------------------------------------------------------------------------
527
528 wxPGProperty* wxPropertyGridInterface::GetPropertyByLabel( const wxString& label ) const
529 {
530 wxPGVIterator it;
531
532 for ( it = GetVIterator( wxPG_ITERATE_PROPERTIES ); !it.AtEnd(); it.Next() )
533 {
534 if ( it.GetProperty()->GetLabel() == label )
535 return it.GetProperty();
536 }
537
538 return wxNullProperty;
539 }
540
541 // ----------------------------------------------------------------------------
542
543 void wxPropertyGridInterface::DoSetPropertyAttribute( wxPGPropArg id, const wxString& name,
544 wxVariant& value, long argFlags )
545 {
546 wxPG_PROP_ARG_CALL_PROLOG()
547
548 p->SetAttribute( name, value );
549
550 if ( argFlags & wxPG_RECURSE )
551 {
552 unsigned int i;
553 for ( i = 0; i < p->GetChildCount(); i++ )
554 DoSetPropertyAttribute(p->Item(i), name, value, argFlags);
555 }
556 }
557
558 // -----------------------------------------------------------------------
559
560 void wxPropertyGridInterface::GetPropertiesWithFlag( wxArrayPGProperty* targetArr,
561 wxPGProperty::FlagType flags,
562 bool inverse,
563 int iterFlags ) const
564 {
565 wxASSERT( targetArr );
566 wxPGVIterator it = GetVIterator( iterFlags );
567
568 for ( ;
569 !it.AtEnd();
570 it.Next() )
571 {
572 const wxPGProperty* property = it.GetProperty();
573
574 if ( !inverse )
575 {
576 if ( (property->GetFlags() & flags) == flags )
577 targetArr->push_back((wxPGProperty*)property);
578 }
579 else
580 {
581 if ( (property->GetFlags() & flags) != flags )
582 targetArr->push_back((wxPGProperty*)property);
583 }
584 }
585 }
586
587 // -----------------------------------------------------------------------
588
589 void wxPropertyGridInterface::SetPropertiesFlag( const wxArrayPGProperty& srcArr,
590 wxPGProperty::FlagType flags,
591 bool inverse )
592 {
593 unsigned int i;
594
595 for ( i=0; i<srcArr.size(); i++ )
596 {
597 wxPGProperty* property = srcArr[i];
598
599 if ( !inverse )
600 property->SetFlag(flags);
601 else
602 property->ClearFlag(flags);
603 }
604
605 // If collapsed flag or hidden was manipulated, we need to update virtual
606 // size.
607 wxPropertyGrid* pg = GetPropertyGrid();
608 if ( flags & (wxPG_PROP_COLLAPSED|wxPG_PROP_HIDDEN) )
609 {
610 GetState()->VirtualHeightChanged();
611 pg->RecalculateVirtualSize();
612 }
613 }
614
615 // -----------------------------------------------------------------------
616
617 void wxPropertyGridInterface::SetBoolChoices( const wxString& trueChoice,
618 const wxString& falseChoice )
619 {
620 wxPGGlobalVars->m_boolChoices[0] = falseChoice;
621 wxPGGlobalVars->m_boolChoices[1] = trueChoice;
622 }
623
624 // -----------------------------------------------------------------------
625
626 wxPGChoices gs_emptyChoices;
627
628 wxPGChoices& wxPropertyGridInterface::GetPropertyChoices( wxPGPropArg id )
629 {
630 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(gs_emptyChoices)
631
632 wxPGChoiceInfo ci;
633 ci.m_choices = (wxPGChoices*) NULL;
634
635 p->GetChoiceInfo(&ci);
636
637 if ( !ci.m_choices )
638 return gs_emptyChoices;
639
640 return *ci.m_choices;
641 }
642
643 // -----------------------------------------------------------------------
644
645 wxPGProperty* wxPropertyGridInterface::DoGetPropertyByName( const wxString& name ) const
646 {
647 return m_pState->BaseGetPropertyByName(name);
648 }
649
650 // -----------------------------------------------------------------------
651
652 wxPGProperty* wxPropertyGridInterface::GetPropertyByName( const wxString& name,
653 const wxString& subname ) const
654 {
655 wxPGProperty* p = DoGetPropertyByName(name);
656 if ( !p || !p->GetChildCount() )
657 return wxNullProperty;
658
659 return p->GetPropertyByName(subname);
660 }
661
662 // -----------------------------------------------------------------------
663
664 // Since GetPropertyByName is used *a lot*, this makes sense
665 // since non-virtual method can be called with less code.
666 wxPGProperty* wxPropertyGridInterface::GetPropertyByName( const wxString& name ) const
667 {
668 wxPGProperty* p = DoGetPropertyByName(name);
669 if ( p )
670 return p;
671
672 // Check if its "Property.SubProperty" format
673 int pos = name.Find(wxT('.'));
674 if ( pos <= 0 )
675 return NULL;
676
677 return GetPropertyByName(name.substr(0,pos),
678 name.substr(pos+1,name.length()-pos-1));
679 }
680
681 // -----------------------------------------------------------------------
682
683 bool wxPropertyGridInterface::HideProperty( wxPGPropArg id, bool hide, int flags )
684 {
685 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
686
687 wxPropertyGrid* pg = m_pState->GetGrid();
688
689 if ( pg == p->GetGrid() )
690 return pg->DoHideProperty(p, hide, flags);
691 else
692 m_pState->DoHideProperty(p, hide, flags);
693
694 return true;
695 }
696
697 // -----------------------------------------------------------------------
698
699 bool wxPropertyGridInterface::Collapse( wxPGPropArg id )
700 {
701 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
702 wxPropertyGrid* pg = p->GetGridIfDisplayed();
703 if ( pg )
704 return pg->DoCollapse(p);
705
706 return p->GetParentState()->DoCollapse(p);
707 }
708
709 // -----------------------------------------------------------------------
710
711 bool wxPropertyGridInterface::Expand( wxPGPropArg id )
712 {
713 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
714 wxPropertyGrid* pg = p->GetGridIfDisplayed();
715 if ( pg )
716 return pg->DoExpand(p);
717
718 return p->GetParentState()->DoExpand(p);
719 }
720
721 // -----------------------------------------------------------------------
722
723 void wxPropertyGridInterface::SetPropertyLabel( wxPGPropArg id, const wxString& newproplabel )
724 {
725 wxPG_PROP_ARG_CALL_PROLOG()
726
727 p->SetLabel( newproplabel );
728
729 wxPropertyGridPageState* state = p->GetParentState();
730 wxPropertyGrid* pg = state->GetGrid();
731
732 if ( pg->HasFlag(wxPG_AUTO_SORT) )
733 pg->SortChildren(p->GetParent());
734
735 if ( pg->GetState() == state )
736 {
737 if ( pg->HasFlag(wxPG_AUTO_SORT) )
738 pg->Refresh();
739 else
740 pg->DrawItem( p );
741 }
742 }
743
744 // -----------------------------------------------------------------------
745
746 bool wxPropertyGridInterface::SetPropertyMaxLength( wxPGPropArg id, int maxLen )
747 {
748 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
749
750 wxPropertyGrid* pg = m_pState->GetGrid();
751
752 p->m_maxLen = (short) maxLen;
753
754 // Adjust control if selected currently
755 if ( pg == p->GetGrid() && p == m_pState->GetSelection() )
756 {
757 wxWindow* wnd = pg->GetEditorControl();
758 wxTextCtrl* tc = wxDynamicCast(wnd,wxTextCtrl);
759 if ( tc )
760 tc->SetMaxLength( maxLen );
761 else
762 // Not a text ctrl
763 return false;
764 }
765
766 return true;
767 }
768
769 // -----------------------------------------------------------------------
770 // GetPropertyValueAsXXX methods
771
772 #define IMPLEMENT_GET_VALUE(T,TRET,BIGNAME,DEFRETVAL) \
773 TRET wxPropertyGridInterface::GetPropertyValueAs##BIGNAME( wxPGPropArg id ) const \
774 { \
775 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(DEFRETVAL) \
776 wxVariant value = p->GetValue(); \
777 if ( wxStrcmp(value.GetType(), wxPGTypeName_##T) != 0 ) \
778 { \
779 wxPGGetFailed(p,wxPGTypeName_##T); \
780 return (TRET)DEFRETVAL; \
781 } \
782 return (TRET)value.Get##BIGNAME(); \
783 }
784
785 // String is different than others.
786 wxString wxPropertyGridInterface::GetPropertyValueAsString( wxPGPropArg id ) const
787 {
788 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxEmptyString)
789 return p->GetValueAsString(wxPG_FULL_VALUE);
790 }
791
792 bool wxPropertyGridInterface::GetPropertyValueAsBool( wxPGPropArg id ) const
793 {
794 wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
795 wxVariant value = p->GetValue();
796 if ( wxStrcmp(value.GetType(), wxPGTypeName_bool) == 0 )
797 {
798 return value.GetBool();
799 }
800 if ( wxStrcmp(value.GetType(), wxPGTypeName_long) == 0 )
801 {
802 return value.GetLong()?true:false;
803 }
804 wxPGGetFailed(p,wxPGTypeName_bool);
805 return false;
806 }
807
808 IMPLEMENT_GET_VALUE(long,long,Long,0)
809 IMPLEMENT_GET_VALUE(double,double,Double,0.0)
810 IMPLEMENT_GET_VALUE(void,void*,VoidPtr,NULL)
811
812 // wxObject is different than others.
813 wxObject* wxPropertyGridInterface::GetPropertyValueAsWxObjectPtr( wxPGPropArg id ) const
814 {
815 wxPG_PROP_ARG_CALL_PROLOG_RETVAL((wxObject*)NULL)
816
817 wxVariant value = p->GetValue();
818 wxVariantData* vdata = value.GetData();
819
820 if ( !vdata->GetValueClassInfo() )
821 return (wxObject*) NULL;
822
823 wxPGVariantData* pgvdata = wxDynamicCastVariantData(vdata, wxPGVariantData);
824 if ( pgvdata )
825 return (wxObject*) pgvdata->GetValuePtr();
826
827 if ( wxPGIsVariantClassInfo(wxPGVariantDataGetClassInfo(vdata), wxobject) )
828 return (wxObject*) value.GetWxObjectPtr();
829
830 return (wxObject*) NULL;
831 }
832
833 // -----------------------------------------------------------------------
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