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