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