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