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