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