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