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