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