1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/property.cpp
3 // Purpose: wxPGProperty and related support classes
4 // Author: Jaakko Salli
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
23 #include "wx/object.h"
25 #include "wx/string.h"
28 #include "wx/window.h"
31 #include "wx/dcmemory.h"
34 #include "wx/settings.h"
38 #include "wx/propgrid/propgrid.h"
41 #define PWC_CHILD_SUMMARY_LIMIT 16 // Maximum number of children summarized in a parent property's
44 #define PWC_CHILD_SUMMARY_CHAR_LIMIT 64 // Character limit of summary field when not editing
46 #if wxPG_COMPATIBILITY_1_4
48 // Used to establish backwards compatiblity
49 const char* g_invalidStringContent
= "@__TOTALLY_INVALID_STRING__@";
53 // -----------------------------------------------------------------------
55 static void wxPGDrawFocusRect( wxDC
& dc
, const wxRect
& rect
)
57 #if defined(__WXMSW__) && !defined(__WXWINCE__)
58 // FIXME: Use DrawFocusRect code above (currently it draws solid line
59 // for caption focus but works ok for other stuff).
60 // Also, it seems that this code may not work in future wx versions.
61 dc
.SetLogicalFunction(wxINVERT
);
63 wxPen
pen(*wxBLACK
,1,wxDOT
);
64 pen
.SetCap(wxCAP_BUTT
);
66 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
68 dc
.DrawRectangle(rect
);
70 dc
.SetLogicalFunction(wxCOPY
);
72 dc
.SetLogicalFunction(wxINVERT
);
74 dc
.SetPen(wxPen(*wxBLACK
,1,wxDOT
));
75 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
77 dc
.DrawRectangle(rect
);
79 dc
.SetLogicalFunction(wxCOPY
);
83 // -----------------------------------------------------------------------
85 // -----------------------------------------------------------------------
87 wxSize
wxPGCellRenderer::GetImageSize( const wxPGProperty
* WXUNUSED(property
),
89 int WXUNUSED(item
) ) const
94 void wxPGCellRenderer::DrawText( wxDC
& dc
, const wxRect
& rect
,
95 int xOffset
, const wxString
& text
) const
98 xOffset
+= wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
;
100 rect
.x
+xOffset
+wxPG_XBEFORETEXT
,
101 rect
.y
+((rect
.height
-dc
.GetCharHeight())/2) );
104 void wxPGCellRenderer::DrawEditorValue( wxDC
& dc
, const wxRect
& rect
,
105 int xOffset
, const wxString
& text
,
106 wxPGProperty
* property
,
107 const wxPGEditor
* editor
) const
110 xOffset
+= wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
;
112 int yOffset
= ((rect
.height
-dc
.GetCharHeight())/2);
119 rect2
.height
-= yOffset
;
120 editor
->DrawValue( dc
, rect2
, property
, text
);
125 rect
.x
+xOffset
+wxPG_XBEFORETEXT
,
130 void wxPGCellRenderer::DrawCaptionSelectionRect( wxDC
& dc
, int x
, int y
, int w
, int h
) const
132 wxRect
focusRect(x
,y
+((h
-dc
.GetCharHeight())/2),w
,h
);
133 wxPGDrawFocusRect(dc
,focusRect
);
136 int wxPGCellRenderer::PreDrawCell( wxDC
& dc
, const wxRect
& rect
, const wxPGCell
& cell
, int flags
) const
140 // If possible, use cell colours
141 if ( !(flags
& DontUseCellBgCol
) )
143 dc
.SetPen(cell
.GetBgCol());
144 dc
.SetBrush(cell
.GetBgCol());
147 if ( !(flags
& DontUseCellFgCol
) )
149 dc
.SetTextForeground(cell
.GetFgCol());
152 // Draw Background, but only if not rendering in control
153 // (as control already has rendered correct background).
154 if ( !(flags
& (Control
|ChoicePopup
)) )
155 dc
.DrawRectangle(rect
);
157 const wxBitmap
& bmp
= cell
.GetBitmap();
159 // Do not draw oversized bitmap outside choice popup
160 ((flags
& ChoicePopup
) || bmp
.GetHeight() < rect
.height
)
164 rect
.x
+ wxPG_CONTROL_MARGIN
+ wxCC_CUSTOM_IMAGE_MARGIN1
,
165 rect
.y
+ wxPG_CUSTOM_IMAGE_SPACINGY
,
167 imageOffset
= bmp
.GetWidth();
173 // -----------------------------------------------------------------------
174 // wxPGDefaultRenderer
175 // -----------------------------------------------------------------------
177 void wxPGDefaultRenderer::Render( wxDC
& dc
, const wxRect
& rect
,
178 const wxPropertyGrid
* propertyGrid
, wxPGProperty
* property
,
179 int column
, int item
, int flags
) const
181 bool isUnspecified
= property
->IsValueUnspecified();
183 if ( column
== 1 && item
== -1 )
185 int cmnVal
= property
->GetCommonValue();
189 if ( !isUnspecified
)
190 DrawText( dc
, rect
, 0, propertyGrid
->GetCommonValueLabel(cmnVal
) );
195 const wxPGEditor
* editor
= NULL
;
196 const wxPGCell
* cell
= NULL
;
200 int preDrawFlags
= flags
;
202 property
->GetDisplayInfo(column
, item
, flags
, &text
, &cell
);
204 imageOffset
= PreDrawCell( dc
, rect
, *cell
, preDrawFlags
);
208 if ( !isUnspecified
)
210 editor
= property
->GetColumnEditor(column
);
212 // Regular property value
214 wxSize imageSize
= propertyGrid
->GetImageSize(property
, item
);
216 wxPGPaintData paintdata
;
217 paintdata
.m_parent
= propertyGrid
;
218 paintdata
.m_choiceItem
= item
;
220 if ( imageSize
.x
> 0 )
222 wxRect
imageRect(rect
.x
+ wxPG_CONTROL_MARGIN
+ wxCC_CUSTOM_IMAGE_MARGIN1
,
223 rect
.y
+wxPG_CUSTOM_IMAGE_SPACINGY
,
224 wxPG_CUSTOM_IMAGE_WIDTH
,
225 rect
.height
-(wxPG_CUSTOM_IMAGE_SPACINGY
*2));
227 dc
.SetPen( wxPen(propertyGrid
->GetCellTextColour(), 1, wxSOLID
) );
229 paintdata
.m_drawnWidth
= imageSize
.x
;
230 paintdata
.m_drawnHeight
= imageSize
.y
;
232 property
->OnCustomPaint( dc
, imageRect
, paintdata
);
234 imageOffset
= paintdata
.m_drawnWidth
;
237 text
= property
->GetValueAsString();
240 if ( propertyGrid
->GetColumnCount() <= 2 )
242 wxString unitsString
= property
->GetAttribute(wxPGGlobalVars
->m_strUnits
, wxEmptyString
);
243 if ( unitsString
.length() )
244 text
= wxString::Format(wxS("%s %s"), text
.c_str(), unitsString
.c_str() );
248 if ( text
.length() == 0 )
250 // Try to show inline help if no text
251 wxVariant vInlineHelp
= property
->GetAttribute(wxPGGlobalVars
->m_strInlineHelp
);
252 if ( !vInlineHelp
.IsNull() )
254 text
= vInlineHelp
.GetString();
255 dc
.SetTextForeground(propertyGrid
->GetCellDisabledTextColour());
260 DrawEditorValue( dc
, rect
, imageOffset
, text
, property
, editor
);
262 // active caption gets nice dotted rectangle
263 if ( property
->IsCategory() /*&& column == 0*/ )
265 if ( flags
& Selected
)
267 if ( imageOffset
> 0 )
268 imageOffset
+= wxCC_CUSTOM_IMAGE_MARGIN2
+ 4;
270 DrawCaptionSelectionRect( dc
,
271 rect
.x
+wxPG_XBEFORETEXT
-wxPG_CAPRECTXMARGIN
+imageOffset
,
272 rect
.y
-wxPG_CAPRECTYMARGIN
+1,
273 ((wxPropertyCategory
*)property
)->GetTextExtent(propertyGrid
,
274 propertyGrid
->GetCaptionFont())
275 +(wxPG_CAPRECTXMARGIN
*2),
276 propertyGrid
->GetFontHeight()+(wxPG_CAPRECTYMARGIN
*2) );
281 wxSize
wxPGDefaultRenderer::GetImageSize( const wxPGProperty
* property
,
285 if ( property
&& column
== 1 )
289 wxBitmap
* bmp
= property
->GetValueImage();
291 if ( bmp
&& bmp
->Ok() )
292 return wxSize(bmp
->GetWidth(),bmp
->GetHeight());
298 // -----------------------------------------------------------------------
300 // -----------------------------------------------------------------------
302 wxPGCellData::wxPGCellData()
305 m_hasValidText
= false;
308 // -----------------------------------------------------------------------
310 // -----------------------------------------------------------------------
317 wxPGCell::wxPGCell( const wxString
& text
,
318 const wxBitmap
& bitmap
,
319 const wxColour
& fgCol
,
320 const wxColour
& bgCol
)
323 wxPGCellData
* data
= new wxPGCellData();
326 data
->m_bitmap
= bitmap
;
327 data
->m_fgCol
= fgCol
;
328 data
->m_bgCol
= bgCol
;
329 data
->m_hasValidText
= true;
332 wxObjectRefData
*wxPGCell::CloneRefData( const wxObjectRefData
*data
) const
334 wxPGCellData
* c
= new wxPGCellData();
335 const wxPGCellData
* o
= (const wxPGCellData
*) data
;
336 c
->m_text
= o
->m_text
;
337 c
->m_bitmap
= o
->m_bitmap
;
338 c
->m_fgCol
= o
->m_fgCol
;
339 c
->m_bgCol
= o
->m_bgCol
;
340 c
->m_hasValidText
= o
->m_hasValidText
;
344 void wxPGCell::SetText( const wxString
& text
)
348 GetData()->SetText(text
);
351 void wxPGCell::SetBitmap( const wxBitmap
& bitmap
)
355 GetData()->SetBitmap(bitmap
);
358 void wxPGCell::SetFgCol( const wxColour
& col
)
362 GetData()->SetFgCol(col
);
365 void wxPGCell::SetBgCol( const wxColour
& col
)
369 GetData()->SetBgCol(col
);
372 void wxPGCell::MergeFrom( const wxPGCell
& srcCell
)
376 wxPGCellData
* data
= GetData();
378 if ( srcCell
.HasText() )
379 data
->SetText(srcCell
.GetText());
381 if ( srcCell
.GetFgCol().IsOk() )
382 data
->SetFgCol(srcCell
.GetFgCol());
384 if ( srcCell
.GetBgCol().IsOk() )
385 data
->SetBgCol(srcCell
.GetBgCol());
387 if ( srcCell
.GetBitmap().IsOk() )
388 data
->SetBitmap(srcCell
.GetBitmap());
391 // -----------------------------------------------------------------------
393 // -----------------------------------------------------------------------
395 IMPLEMENT_ABSTRACT_CLASS(wxPGProperty
, wxObject
)
397 wxString
* wxPGProperty::sm_wxPG_LABEL
= NULL
;
399 void wxPGProperty::Init()
405 m_parentState
= NULL
;
408 m_clientObject
= NULL
;
410 m_customEditor
= NULL
;
414 m_valueBitmap
= NULL
;
416 m_maxLen
= 0; // infinite maximum length
418 m_flags
= wxPG_PROP_PROPERTY
;
426 void wxPGProperty::Init( const wxString
& label
, const wxString
& name
)
428 // We really need to check if &label and &name are NULL pointers
429 // (this can if we are called before property grid has been initalized)
431 if ( (&label
) != NULL
&& label
!= wxPG_LABEL
)
434 if ( (&name
) != NULL
&& name
!= wxPG_LABEL
)
437 DoSetName( m_label
);
442 void wxPGProperty::InitAfterAdded( wxPropertyGridPageState
* pageState
,
443 wxPropertyGrid
* propgrid
)
446 // Called after property has been added to grid or page
447 // (so propgrid can be NULL, too).
449 wxPGProperty
* parent
= m_parent
;
450 bool parentIsRoot
= parent
->IsKindOf(CLASSINFO(wxPGRootProperty
));
452 m_parentState
= pageState
;
454 #if wxPG_COMPATIBILITY_1_4
455 // Make sure deprecated virtual functions are not implemented
456 wxString s
= GetValueAsString( 0xFFFF );
457 wxASSERT_MSG( s
== g_invalidStringContent
,
458 "Implement ValueToString() instead of GetValueAsString()" );
461 if ( !parentIsRoot
&& !parent
->IsCategory() )
463 m_cells
= parent
->m_cells
;
466 // If in hideable adding mode, or if assigned parent is hideable, then
467 // make this one hideable.
469 ( !parentIsRoot
&& parent
->HasFlag(wxPG_PROP_HIDDEN
) ) ||
470 ( propgrid
&& (propgrid
->HasInternalFlag(wxPG_FL_ADDING_HIDEABLES
)) )
472 SetFlag( wxPG_PROP_HIDDEN
);
474 // Set custom image flag.
475 int custImgHeight
= OnMeasureImage().y
;
476 if ( custImgHeight
< 0 )
478 SetFlag(wxPG_PROP_CUSTOMIMAGE
);
481 if ( propgrid
&& (propgrid
->HasFlag(wxPG_LIMITED_EDITING
)) )
482 SetFlag(wxPG_PROP_NOEDITOR
);
484 // Make sure parent has some parental flags
485 if ( !parent
->HasFlag(wxPG_PROP_PARENTAL_FLAGS
) )
486 parent
->SetParentalType(wxPG_PROP_MISC_PARENT
);
490 // This is not a category.
494 unsigned char depth
= 1;
497 depth
= parent
->m_depth
;
498 if ( !parent
->IsCategory() )
502 unsigned char greyDepth
= depth
;
506 wxPropertyCategory
* pc
;
508 if ( parent
->IsCategory() )
509 pc
= (wxPropertyCategory
* ) parent
;
511 // This conditional compile is necessary to
512 // bypass some compiler bug.
513 pc
= pageState
->GetPropertyCategory(parent
);
516 greyDepth
= pc
->GetDepth();
518 greyDepth
= parent
->m_depthBgCol
;
521 m_depthBgCol
= greyDepth
;
525 // This is a category.
528 unsigned char depth
= 1;
531 depth
= parent
->m_depth
+ 1;
534 m_depthBgCol
= depth
;
538 // Has initial children
539 if ( GetChildCount() )
541 // Check parental flags
542 wxASSERT_MSG( (m_flags
& wxPG_PROP_PARENTAL_FLAGS
),
543 "Call SetFlag(wxPG_PROP_MISC_PARENT) or"
544 "SetFlag(wxPG_PROP_AGGREGATE) before calling"
545 "wxPGProperty::AddChild()." );
547 if ( HasFlag(wxPG_PROP_AGGREGATE
) )
549 // Properties with private children are not expanded by default.
552 else if ( propgrid
&& propgrid
->HasFlag(wxPG_HIDE_MARGIN
) )
554 // ...unless it cannot be expanded by user and therefore must
555 // remain visible at all times
560 // Prepare children recursively
561 for ( unsigned int i
=0; i
<GetChildCount(); i
++ )
563 wxPGProperty
* child
= Item(i
);
564 child
->InitAfterAdded(pageState
, pageState
->GetGrid());
567 if ( propgrid
&& (propgrid
->GetExtraStyle() & wxPG_EX_AUTO_UNSPECIFIED_VALUES
) )
568 SetFlagRecursively(wxPG_PROP_AUTO_UNSPECIFIED
, true);
572 wxPGProperty::wxPGProperty()
579 wxPGProperty::wxPGProperty( const wxString
& label
, const wxString
& name
)
586 wxPGProperty::~wxPGProperty()
588 delete m_clientObject
;
590 Empty(); // this deletes items
592 delete m_valueBitmap
;
597 // This makes it easier for us to detect dangling pointers
602 bool wxPGProperty::IsSomeParent( wxPGProperty
* candidate
) const
604 wxPGProperty
* parent
= m_parent
;
607 if ( parent
== candidate
)
609 parent
= parent
->m_parent
;
615 wxString
wxPGProperty::GetName() const
617 wxPGProperty
* parent
= GetParent();
619 if ( !m_name
.length() || !parent
|| parent
->IsCategory() || parent
->IsRoot() )
622 return m_parent
->GetName() + wxS(".") + m_name
;
625 wxPropertyGrid
* wxPGProperty::GetGrid() const
627 if ( !m_parentState
)
629 return m_parentState
->GetGrid();
632 int wxPGProperty::Index( const wxPGProperty
* p
) const
634 for ( unsigned int i
= 0; i
<m_children
.size(); i
++ )
636 if ( p
== m_children
[i
] )
642 bool wxPGProperty::ValidateValue( wxVariant
& WXUNUSED(value
), wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
647 void wxPGProperty::OnSetValue()
651 void wxPGProperty::RefreshChildren ()
655 void wxPGProperty::OnValidationFailure( wxVariant
& WXUNUSED(pendingValue
) )
659 void wxPGProperty::GetDisplayInfo( unsigned int column
,
663 const wxPGCell
** pCell
)
665 const wxPGCell
* cell
= NULL
;
667 if ( !(flags
& wxPGCellRenderer::ChoicePopup
) )
669 // Not painting listi of choice popups, so get text from property
670 cell
= &GetCell(column
);
671 if ( cell
->HasText() )
673 *pString
= cell
->GetText();
678 *pString
= GetLabel();
679 else if ( column
== 1 )
680 *pString
= GetDisplayedString();
681 else if ( column
== 2 )
682 *pString
= GetAttribute(wxPGGlobalVars
->m_strUnits
, wxEmptyString
);
687 wxASSERT( column
== 1 );
689 if ( choiceIndex
!= wxNOT_FOUND
)
691 const wxPGChoiceEntry
& entry
= m_choices
[choiceIndex
];
692 if ( entry
.GetBitmap().IsOk() ||
693 entry
.GetFgCol().IsOk() ||
694 entry
.GetBgCol().IsOk() )
696 *pString
= m_choices
.GetLabel(choiceIndex
);
701 cell
= &GetCell(column
);
703 wxASSERT_MSG( cell
->GetData(),
704 wxString::Format("Invalid cell for property %s",
705 GetName().c_str()) );
711 wxString wxPGProperty::GetColumnText( unsigned int col, int choiceIndex ) const
714 if ( col != 1 || choiceIndex == wxNOT_FOUND )
716 const wxPGCell& cell = GetCell(col);
717 if ( cell->HasText() )
719 return cell->GetText();
726 return GetDisplayedString();
728 return GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
734 return m_choices.GetLabel(choiceIndex);
737 return wxEmptyString;
741 void wxPGProperty::DoGenerateComposedValue( wxString
& text
,
743 const wxVariantList
* valueOverrides
,
744 wxPGHashMapS2S
* childResults
) const
747 int iMax
= m_children
.size();
753 if ( iMax
> PWC_CHILD_SUMMARY_LIMIT
&&
754 !(argFlags
& wxPG_FULL_VALUE
) )
755 iMax
= PWC_CHILD_SUMMARY_LIMIT
;
757 int iMaxMinusOne
= iMax
-1;
759 if ( !IsTextEditable() )
760 argFlags
|= wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
;
762 wxPGProperty
* curChild
= m_children
[0];
764 bool overridesLeft
= false;
765 wxVariant overrideValue
;
766 wxVariantList::const_iterator node
;
768 if ( valueOverrides
)
770 node
= valueOverrides
->begin();
771 if ( node
!= valueOverrides
->end() )
773 overrideValue
= *node
;
774 overridesLeft
= true;
778 for ( i
= 0; i
< iMax
; i
++ )
780 wxVariant childValue
;
782 wxString childLabel
= curChild
->GetLabel();
784 // Check for value override
785 if ( overridesLeft
&& overrideValue
.GetName() == childLabel
)
787 if ( !overrideValue
.IsNull() )
788 childValue
= overrideValue
;
790 childValue
= curChild
->GetValue();
792 if ( node
!= valueOverrides
->end() )
793 overrideValue
= *node
;
795 overridesLeft
= false;
799 childValue
= curChild
->GetValue();
803 if ( !childValue
.IsNull() )
805 if ( overridesLeft
&&
806 curChild
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) &&
807 childValue
.GetType() == wxPG_VARIANT_TYPE_LIST
)
809 wxVariantList
& childList
= childValue
.GetList();
810 DoGenerateComposedValue(s
, argFlags
|wxPG_COMPOSITE_FRAGMENT
,
811 &childList
, childResults
);
815 s
= curChild
->ValueToString(childValue
,
816 argFlags
|wxPG_COMPOSITE_FRAGMENT
);
820 if ( childResults
&& curChild
->GetChildCount() )
821 (*childResults
)[curChild
->GetName()] = s
;
824 if ( (argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
) && !s
.length() )
827 if ( !curChild
->GetChildCount() || skip
)
830 text
+= wxS("[") + s
+ wxS("]");
832 if ( i
< iMaxMinusOne
)
834 if ( text
.length() > PWC_CHILD_SUMMARY_CHAR_LIMIT
&&
835 !(argFlags
& wxPG_EDITABLE_VALUE
) &&
836 !(argFlags
& wxPG_FULL_VALUE
) )
841 if ( !curChild
->GetChildCount() )
847 curChild
= m_children
[i
+1];
851 if ( (unsigned int)i
< m_children
.size() )
853 if ( !text
.EndsWith(wxS("; ")) )
854 text
+= wxS("; ...");
860 wxString
wxPGProperty::ValueToString( wxVariant
& WXUNUSED(value
),
863 wxCHECK_MSG( GetChildCount() > 0,
865 "If user property does not have any children, it must "
866 "override GetValueAsString" );
868 // FIXME: Currently code below only works if value is actually m_value
869 wxASSERT_MSG( argFlags
& wxPG_VALUE_IS_CURRENT
,
870 "Sorry, currently default wxPGProperty::ValueToString() "
871 "implementation only works if value is m_value." );
874 DoGenerateComposedValue(text
, argFlags
);
878 wxString
wxPGProperty::GetValueAsString( int argFlags
) const
880 #if wxPG_COMPATIBILITY_1_4
881 // This is backwards compatibility test
882 // That is, to make sure this function is not overridden
883 // (instead, ValueToString() should be).
884 if ( argFlags
== 0xFFFF )
886 // Do not override! (for backwards compliancy)
887 return g_invalidStringContent
;
891 if ( IsValueUnspecified() )
892 return wxEmptyString
;
894 if ( m_commonValue
== -1 )
896 wxVariant
value(GetValue());
897 return ValueToString(value
, argFlags
|wxPG_VALUE_IS_CURRENT
);
901 // Return common value's string representation
902 wxPropertyGrid
* pg
= GetGrid();
903 const wxPGCommonValue
* cv
= pg
->GetCommonValue(m_commonValue
);
905 if ( argFlags
& wxPG_FULL_VALUE
)
907 return cv
->GetLabel();
909 else if ( argFlags
& wxPG_EDITABLE_VALUE
)
911 return cv
->GetEditableText();
915 return cv
->GetLabel();
919 wxString
wxPGProperty::GetValueString( int argFlags
) const
921 return GetValueAsString(argFlags
);
924 bool wxPGProperty::IntToValue( wxVariant
& variant
, int number
, int WXUNUSED(argFlags
) ) const
926 variant
= (long)number
;
930 // Convert semicolon delimited tokens into child values.
931 bool wxPGProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
933 if ( !GetChildCount() )
936 unsigned int curChild
= 0;
938 unsigned int iMax
= m_children
.size();
940 if ( iMax
> PWC_CHILD_SUMMARY_LIMIT
&&
941 !(argFlags
& wxPG_FULL_VALUE
) )
942 iMax
= PWC_CHILD_SUMMARY_LIMIT
;
944 bool changed
= false;
949 // Its best only to add non-empty group items
950 bool addOnlyIfNotEmpty
= false;
951 const wxChar delimeter
= wxS(';');
953 size_t tokenStart
= 0xFFFFFF;
955 wxVariantList temp_list
;
956 wxVariant
list(temp_list
);
958 int propagatedFlags
= argFlags
& (wxPG_REPORT_ERROR
|wxPG_PROGRAMMATIC_VALUE
);
961 bool debug_print
= false;
966 wxLogDebug(wxT(">> %s.StringToValue('%s')"),GetLabel().c_str(),text
.c_str());
969 wxString::const_iterator it
= text
.begin();
972 if ( it
!= text
.end() )
979 // How many units we iterate string forward at the end of loop?
980 // We need to keep track of this or risk going to negative
981 // with it-- operation.
982 unsigned int strPosIncrement
= 1;
984 if ( tokenStart
!= 0xFFFFFF )
987 if ( a
== delimeter
|| a
== 0 )
989 token
= text
.substr(tokenStart
,pos
-tokenStart
);
991 size_t len
= token
.length();
993 if ( !addOnlyIfNotEmpty
|| len
> 0 )
995 const wxPGProperty
* child
= Item(curChild
);
996 wxVariant
variant(child
->GetValue());
997 wxString childName
= child
->GetBaseName();
1001 wxLogDebug(wxT("token = '%s', child = %s"),
1002 token
.c_str(), childName
.c_str());
1005 // Add only if editable or setting programmatically
1006 if ( (argFlags
& wxPG_PROGRAMMATIC_VALUE
) ||
1007 !child
->HasFlag(wxPG_PROP_DISABLED
|wxPG_PROP_READONLY
) )
1011 if ( child
->StringToValue(variant
, token
,
1012 propagatedFlags
|wxPG_COMPOSITE_FRAGMENT
) )
1014 // We really need to set the variant's name
1015 // *after* child->StringToValue() has been
1016 // called, since variant's value may be set by
1017 // assigning another variant into it, which
1018 // then usually causes name to be copied (ie.
1019 // usually cleared) as well. wxBoolProperty
1020 // being case in point with its use of
1021 // wxPGVariant_Bool macro as an optimization.
1022 variant
.SetName(childName
);
1023 list
.Append(variant
);
1030 // Empty, becomes unspecified
1032 variant
.SetName(childName
);
1033 list
.Append(variant
);
1039 if ( curChild
>= iMax
)
1043 tokenStart
= 0xFFFFFF;
1048 // Token is not running
1049 if ( a
!= wxS(' ') )
1052 addOnlyIfNotEmpty
= false;
1054 // Is this a group of tokens?
1055 if ( a
== wxS('[') )
1059 if ( it
!= text
.end() ) ++it
;
1061 size_t startPos
= pos
;
1063 // Group item - find end
1064 while ( it
!= text
.end() && depth
> 0 )
1070 if ( a
== wxS(']') )
1072 else if ( a
== wxS('[') )
1076 token
= text
.substr(startPos
,pos
-startPos
-1);
1078 if ( !token
.length() )
1081 const wxPGProperty
* child
= Item(curChild
);
1083 wxVariant oldChildValue
= child
->GetValue();
1084 wxVariant
variant(oldChildValue
);
1086 if ( (argFlags
& wxPG_PROGRAMMATIC_VALUE
) ||
1087 !child
->HasFlag(wxPG_PROP_DISABLED
|wxPG_PROP_READONLY
) )
1089 wxString childName
= child
->GetBaseName();
1091 bool stvRes
= child
->StringToValue( variant
, token
,
1093 if ( stvRes
|| (variant
!= oldChildValue
) )
1095 variant
.SetName(childName
);
1096 list
.Append(variant
);
1107 if ( curChild
>= iMax
)
1110 addOnlyIfNotEmpty
= true;
1112 tokenStart
= 0xFFFFFF;
1118 if ( a
== delimeter
)
1119 strPosIncrement
-= 1;
1127 it
+= strPosIncrement
;
1129 if ( it
!= text
.end() )
1138 pos
+= strPosIncrement
;
1147 bool wxPGProperty::SetValueFromString( const wxString
& text
, int argFlags
)
1149 wxVariant
variant(m_value
);
1150 bool res
= StringToValue(variant
, text
, argFlags
);
1156 bool wxPGProperty::SetValueFromInt( long number
, int argFlags
)
1158 wxVariant
variant(m_value
);
1159 bool res
= IntToValue(variant
, number
, argFlags
);
1165 wxSize
wxPGProperty::OnMeasureImage( int WXUNUSED(item
) ) const
1167 if ( m_valueBitmap
)
1168 return wxSize(m_valueBitmap
->GetWidth(),-1);
1173 wxPGCellRenderer
* wxPGProperty::GetCellRenderer( int WXUNUSED(column
) ) const
1175 return wxPGGlobalVars
->m_defaultRenderer
;
1178 void wxPGProperty::OnCustomPaint( wxDC
& dc
,
1182 wxBitmap
* bmp
= m_valueBitmap
;
1184 wxCHECK_RET( bmp
&& bmp
->Ok(), wxT("invalid bitmap") );
1186 wxCHECK_RET( rect
.x
>= 0, wxT("unexpected measure call") );
1188 dc
.DrawBitmap(*bmp
,rect
.x
,rect
.y
);
1191 const wxPGEditor
* wxPGProperty::DoGetEditorClass() const
1193 return wxPGEditor_TextCtrl
;
1196 // Default extra property event handling - that is, none at all.
1197 bool wxPGProperty::OnEvent( wxPropertyGrid
*, wxWindow
*, wxEvent
& )
1203 void wxPGProperty::SetValue( wxVariant value
, wxVariant
* pList
, int flags
)
1205 // If auto unspecified values are not wanted (via window or property style),
1206 // then get default value instead of wxNullVariant.
1207 if ( value
.IsNull() && (flags
& wxPG_SETVAL_BY_USER
) &&
1208 !UsesAutoUnspecified() )
1210 value
= GetDefaultValue();
1213 if ( !value
.IsNull() )
1215 wxVariant tempListVariant
;
1218 // List variants are reserved a special purpose
1219 // as intermediate containers for child values
1220 // of properties with children.
1221 if ( value
.GetType() == wxPG_VARIANT_TYPE_LIST
)
1224 // However, situation is different for composed string properties
1225 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
1227 tempListVariant
= value
;
1228 pList
= &tempListVariant
;
1232 AdaptListToValue(value
, &newValue
);
1234 //wxLogDebug(wxT(">> %s.SetValue() adapted list value to type '%s'"),GetName().c_str(),value.GetType().c_str());
1237 if ( HasFlag( wxPG_PROP_AGGREGATE
) )
1238 flags
|= wxPG_SETVAL_AGGREGATED
;
1240 if ( pList
&& !pList
->IsNull() )
1242 wxASSERT( pList
->GetType() == wxPG_VARIANT_TYPE_LIST
);
1243 wxASSERT( GetChildCount() );
1244 wxASSERT( !IsCategory() );
1246 wxVariantList
& list
= pList
->GetList();
1247 wxVariantList::iterator node
;
1250 //wxLogDebug(wxT(">> %s.SetValue() pList parsing"),GetName().c_str());
1252 // Children in list can be in any order, but we will give hint to
1253 // GetPropertyByNameWH(). This optimizes for full list parsing.
1254 for ( node
= list
.begin(); node
!= list
.end(); ++node
)
1256 wxVariant
& childValue
= *((wxVariant
*)*node
);
1257 wxPGProperty
* child
= GetPropertyByNameWH(childValue
.GetName(), i
);
1260 //wxLogDebug(wxT("%i: child = %s, childValue.GetType()=%s"),i,child->GetBaseName().c_str(),childValue.GetType().c_str());
1261 if ( childValue
.GetType() == wxPG_VARIANT_TYPE_LIST
)
1263 if ( child
->HasFlag(wxPG_PROP_AGGREGATE
) && !(flags
& wxPG_SETVAL_AGGREGATED
) )
1265 wxVariant listRefCopy
= childValue
;
1266 child
->SetValue(childValue
, &listRefCopy
, flags
|wxPG_SETVAL_FROM_PARENT
);
1270 wxVariant oldVal
= child
->GetValue();
1271 child
->SetValue(oldVal
, &childValue
, flags
|wxPG_SETVAL_FROM_PARENT
);
1274 else if ( child
->GetValue() != childValue
)
1276 // For aggregate properties, we will trust RefreshChildren()
1277 // to update child values.
1278 if ( !HasFlag(wxPG_PROP_AGGREGATE
) )
1279 child
->SetValue(childValue
, NULL
, flags
|wxPG_SETVAL_FROM_PARENT
);
1280 if ( flags
& wxPG_SETVAL_BY_USER
)
1281 child
->SetFlag(wxPG_PROP_MODIFIED
);
1288 if ( !value
.IsNull() )
1294 if ( flags
& wxPG_SETVAL_BY_USER
)
1295 SetFlag(wxPG_PROP_MODIFIED
);
1297 if ( HasFlag(wxPG_PROP_AGGREGATE
) )
1302 if ( m_commonValue
!= -1 )
1304 wxPropertyGrid
* pg
= GetGrid();
1305 if ( !pg
|| m_commonValue
!= pg
->GetUnspecifiedCommonValue() )
1311 // Set children to unspecified, but only if aggregate or
1312 // value is <composed>
1313 if ( AreChildrenComponents() )
1316 for ( i
=0; i
<GetChildCount(); i
++ )
1317 Item(i
)->SetValue(value
, NULL
, flags
|wxPG_SETVAL_FROM_PARENT
);
1321 if ( !(flags
& wxPG_SETVAL_FROM_PARENT
) )
1322 UpdateParentValues();
1325 // Update editor control
1328 // We need to check for these, otherwise GetGrid() may fail.
1329 if ( flags
& wxPG_SETVAL_REFRESH_EDITOR
)
1332 wxPropertyGrid
* pg
= GetGridIfDisplayed();
1334 pg
->DrawItemAndValueRelated(this);
1339 void wxPGProperty::SetValueInEvent( wxVariant value
) const
1341 GetGrid()->ValueChangeInEvent(value
);
1344 void wxPGProperty::SetFlagRecursively( FlagType flag
, bool set
)
1352 for ( i
= 0; i
< GetChildCount(); i
++ )
1353 Item(i
)->SetFlagRecursively(flag
, set
);
1356 void wxPGProperty::RefreshEditor()
1361 wxPropertyGrid
* pg
= GetGrid();
1362 if ( pg
&& pg
->GetSelectedProperty() == this )
1363 pg
->RefreshEditor();
1366 wxVariant
wxPGProperty::GetDefaultValue() const
1368 wxVariant defVal
= GetAttribute(wxS("DefaultValue"));
1369 if ( !defVal
.IsNull() )
1372 wxVariant value
= GetValue();
1374 if ( !value
.IsNull() )
1376 wxString
valueType(value
.GetType());
1378 if ( valueType
== wxPG_VARIANT_TYPE_LONG
)
1379 return wxPGVariant_Zero
;
1380 if ( valueType
== wxPG_VARIANT_TYPE_STRING
)
1381 return wxPGVariant_EmptyString
;
1382 if ( valueType
== wxPG_VARIANT_TYPE_BOOL
)
1383 return wxPGVariant_False
;
1384 if ( valueType
== wxPG_VARIANT_TYPE_DOUBLE
)
1385 return wxVariant(0.0);
1386 if ( valueType
== wxPG_VARIANT_TYPE_ARRSTRING
)
1387 return wxVariant(wxArrayString());
1388 if ( valueType
== wxS("wxLongLong") )
1389 return WXVARIANT(wxLongLong(0));
1390 if ( valueType
== wxS("wxULongLong") )
1391 return WXVARIANT(wxULongLong(0));
1392 if ( valueType
== wxS("wxColour") )
1393 return WXVARIANT(*wxBLACK
);
1395 if ( valueType
== wxPG_VARIANT_TYPE_DATETIME
)
1396 return wxVariant(wxDateTime::Now());
1398 if ( valueType
== wxS("wxFont") )
1399 return WXVARIANT(*wxNORMAL_FONT
);
1400 if ( valueType
== wxS("wxPoint") )
1401 return WXVARIANT(wxPoint(0, 0));
1402 if ( valueType
== wxS("wxSize") )
1403 return WXVARIANT(wxSize(0, 0));
1409 void wxPGProperty::EnsureCells( unsigned int column
)
1411 if ( column
>= m_cells
.size() )
1413 // Fill empty slots with default cells
1414 wxPropertyGrid
* pg
= GetGrid();
1415 wxPGCell defaultCell
;
1417 if ( !HasFlag(wxPG_PROP_CATEGORY
) )
1418 defaultCell
= pg
->GetPropertyDefaultCell();
1420 defaultCell
= pg
->GetCategoryDefaultCell();
1422 // TODO: Replace with resize() call
1423 unsigned int cellCountMax
= column
+1;
1425 for ( unsigned int i
=m_cells
.size(); i
<cellCountMax
; i
++ )
1426 m_cells
.push_back(defaultCell
);
1430 void wxPGProperty::SetCell( int column
,
1431 const wxPGCell
& cell
)
1433 EnsureCells(column
);
1435 m_cells
[column
] = cell
;
1438 void wxPGProperty::AdaptiveSetCell( unsigned int firstCol
,
1439 unsigned int lastCol
,
1440 const wxPGCell
& cell
,
1441 const wxPGCell
& srcData
,
1442 wxPGCellData
* unmodCellData
,
1443 FlagType ignoreWithFlags
,
1447 // Sets cell in memory optimizing fashion. That is, if
1448 // current cell data matches unmodCellData, we will
1449 // simply get reference to data from cell. Otherwise,
1450 // cell information from srcData is merged into current.
1453 if ( !(m_flags
& ignoreWithFlags
) && !IsRoot() )
1455 EnsureCells(lastCol
);
1457 for ( unsigned int col
=firstCol
; col
<=lastCol
; col
++ )
1459 if ( m_cells
[col
].GetData() == unmodCellData
)
1461 // Data matches... use cell directly
1462 m_cells
[col
] = cell
;
1466 // Data did not match... merge valid information
1467 m_cells
[col
].MergeFrom(srcData
);
1474 for ( unsigned int i
=0; i
<GetChildCount(); i
++ )
1475 Item(i
)->AdaptiveSetCell( firstCol
,
1485 const wxPGCell
& wxPGProperty::GetCell( unsigned int column
) const
1487 if ( m_cells
.size() > column
)
1488 return m_cells
[column
];
1490 wxPropertyGrid
* pg
= GetGrid();
1493 return pg
->GetCategoryDefaultCell();
1495 return pg
->GetPropertyDefaultCell();
1498 wxPGCell
& wxPGProperty::GetCell( unsigned int column
)
1500 EnsureCells(column
);
1501 return m_cells
[column
];
1504 void wxPGProperty::SetBackgroundColour( const wxColour
& colour
,
1507 wxPGProperty
* firstProp
= this;
1510 // If category is tried to set recursively, skip it and only
1511 // affect the children.
1514 while ( firstProp
->IsCategory() )
1516 if ( !firstProp
->GetChildCount() )
1518 firstProp
= firstProp
->Item(0);
1522 wxPGCell
& firstCell
= firstProp
->GetCell(0);
1523 wxPGCellData
* firstCellData
= firstCell
.GetData();
1525 wxPGCell
newCell(firstCell
);
1526 newCell
.SetBgCol(colour
);
1528 srcCell
.SetBgCol(colour
);
1531 GetParentState()->GetColumnCount()-1,
1535 recursively
? wxPG_PROP_CATEGORY
: 0,
1539 void wxPGProperty::SetTextColour( const wxColour
& colour
,
1542 wxPGProperty
* firstProp
= this;
1545 // If category is tried to set recursively, skip it and only
1546 // affect the children.
1549 while ( firstProp
->IsCategory() )
1551 if ( !firstProp
->GetChildCount() )
1553 firstProp
= firstProp
->Item(0);
1557 wxPGCell
& firstCell
= firstProp
->GetCell(0);
1558 wxPGCellData
* firstCellData
= firstCell
.GetData();
1560 wxPGCell
newCell(firstCell
);
1561 newCell
.SetFgCol(colour
);
1563 srcCell
.SetFgCol(colour
);
1566 GetParentState()->GetColumnCount()-1,
1570 recursively
? wxPG_PROP_CATEGORY
: 0,
1574 wxPGEditorDialogAdapter
* wxPGProperty::GetEditorDialog() const
1579 bool wxPGProperty::DoSetAttribute( const wxString
& WXUNUSED(name
), wxVariant
& WXUNUSED(value
) )
1584 void wxPGProperty::SetAttribute( const wxString
& name
, wxVariant value
)
1586 if ( DoSetAttribute( name
, value
) )
1588 // Support working without grid, when possible
1589 if ( wxPGGlobalVars
->HasExtraStyle( wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES
) )
1593 m_attributes
.Set( name
, value
);
1596 void wxPGProperty::SetAttributes( const wxPGAttributeStorage
& attributes
)
1598 wxPGAttributeStorage::const_iterator it
= attributes
.StartIteration();
1601 while ( attributes
.GetNext(it
, variant
) )
1602 SetAttribute( variant
.GetName(), variant
);
1605 wxVariant
wxPGProperty::DoGetAttribute( const wxString
& WXUNUSED(name
) ) const
1611 wxVariant
wxPGProperty::GetAttribute( const wxString
& name
) const
1613 return m_attributes
.FindValue(name
);
1616 wxString
wxPGProperty::GetAttribute( const wxString
& name
, const wxString
& defVal
) const
1618 wxVariant variant
= m_attributes
.FindValue(name
);
1620 if ( !variant
.IsNull() )
1621 return variant
.GetString();
1626 long wxPGProperty::GetAttributeAsLong( const wxString
& name
, long defVal
) const
1628 wxVariant variant
= m_attributes
.FindValue(name
);
1630 return wxPGVariantToInt(variant
, defVal
);
1633 double wxPGProperty::GetAttributeAsDouble( const wxString
& name
, double defVal
) const
1636 wxVariant variant
= m_attributes
.FindValue(name
);
1638 if ( wxPGVariantToDouble(variant
, &retVal
) )
1644 wxVariant
wxPGProperty::GetAttributesAsList() const
1646 wxVariantList tempList
;
1647 wxVariant
v( tempList
, wxString::Format(wxS("@%s@attr"),m_name
.c_str()) );
1649 wxPGAttributeStorage::const_iterator it
= m_attributes
.StartIteration();
1652 while ( m_attributes
.GetNext(it
, variant
) )
1658 // Slots of utility flags are NULL
1659 const unsigned int gs_propFlagToStringSize
= 14;
1661 static const wxChar
* gs_propFlagToString
[gs_propFlagToStringSize
] = {
1678 wxString
wxPGProperty::GetFlagsAsString( FlagType flagsMask
) const
1681 int relevantFlags
= m_flags
& flagsMask
& wxPG_STRING_STORED_FLAGS
;
1685 for ( i
=0; i
<gs_propFlagToStringSize
; i
++ )
1687 if ( relevantFlags
& a
)
1689 const wxChar
* fs
= gs_propFlagToString
[i
];
1701 void wxPGProperty::SetFlagsFromString( const wxString
& str
)
1705 WX_PG_TOKENIZER1_BEGIN(str
, wxS('|'))
1707 for ( i
=0; i
<gs_propFlagToStringSize
; i
++ )
1709 const wxChar
* fs
= gs_propFlagToString
[i
];
1710 if ( fs
&& str
== fs
)
1716 WX_PG_TOKENIZER1_END()
1718 m_flags
= (m_flags
& ~wxPG_STRING_STORED_FLAGS
) | flags
;
1721 wxValidator
* wxPGProperty::DoGetValidator() const
1726 int wxPGProperty::InsertChoice( const wxString
& label
, int index
, int value
)
1728 wxPropertyGrid
* pg
= GetGrid();
1729 int sel
= GetChoiceSelection();
1733 if ( index
== wxNOT_FOUND
)
1734 index
= m_choices
.GetCount();
1739 m_choices
.Insert(label
, index
, value
);
1741 if ( sel
!= newSel
)
1742 SetChoiceSelection(newSel
);
1744 if ( this == pg
->GetSelection() )
1745 GetEditorClass()->InsertItem(pg
->GetEditorControl(),label
,index
);
1751 void wxPGProperty::DeleteChoice( int index
)
1753 wxPropertyGrid
* pg
= GetGrid();
1755 int sel
= GetChoiceSelection();
1758 // Adjust current value
1761 SetValueToUnspecified();
1764 else if ( index
< sel
)
1769 m_choices
.RemoveAt(index
);
1771 if ( sel
!= newSel
)
1772 SetChoiceSelection(newSel
);
1774 if ( this == pg
->GetSelection() )
1775 GetEditorClass()->DeleteItem(pg
->GetEditorControl(), index
);
1778 int wxPGProperty::GetChoiceSelection() const
1780 wxVariant value
= GetValue();
1781 wxString valueType
= value
.GetType();
1782 int index
= wxNOT_FOUND
;
1784 if ( IsValueUnspecified() || !m_choices
.GetCount() )
1787 if ( valueType
== wxPG_VARIANT_TYPE_LONG
)
1789 index
= value
.GetLong();
1791 else if ( valueType
== wxPG_VARIANT_TYPE_STRING
)
1793 index
= m_choices
.Index(value
.GetString());
1795 else if ( valueType
== wxPG_VARIANT_TYPE_BOOL
)
1797 index
= value
.GetBool()? 1 : 0;
1803 void wxPGProperty::SetChoiceSelection( int newValue
)
1805 // Changes value of a property with choices, but only
1806 // works if the value type is long or string.
1807 wxString valueType
= GetValue().GetType();
1809 wxCHECK_RET( m_choices
.IsOk(), wxT("invalid choiceinfo") );
1811 if ( valueType
== wxPG_VARIANT_TYPE_STRING
)
1813 SetValue( m_choices
.GetLabel(newValue
) );
1815 else // if ( valueType == wxPG_VARIANT_TYPE_LONG )
1817 SetValue( (long) newValue
);
1821 bool wxPGProperty::SetChoices( wxPGChoices
& choices
)
1823 m_choices
.Assign(choices
);
1826 // This may be needed to trigger some initialization
1827 // (but don't do it if property is somewhat uninitialized)
1828 wxVariant defVal
= GetDefaultValue();
1829 if ( defVal
.IsNull() )
1839 const wxPGEditor
* wxPGProperty::GetEditorClass() const
1841 const wxPGEditor
* editor
;
1843 if ( !m_customEditor
)
1845 editor
= DoGetEditorClass();
1848 editor
= m_customEditor
;
1851 // Maybe override editor if common value specified
1852 if ( GetDisplayedCommonValueCount() )
1854 // TextCtrlAndButton -> ComboBoxAndButton
1855 if ( editor
->IsKindOf(CLASSINFO(wxPGTextCtrlAndButtonEditor
)) )
1856 editor
= wxPGEditor_ChoiceAndButton
;
1858 // TextCtrl -> ComboBox
1859 else if ( editor
->IsKindOf(CLASSINFO(wxPGTextCtrlEditor
)) )
1860 editor
= wxPGEditor_ComboBox
;
1866 bool wxPGProperty::HasVisibleChildren() const
1870 for ( i
=0; i
<GetChildCount(); i
++ )
1872 wxPGProperty
* child
= Item(i
);
1874 if ( !child
->HasFlag(wxPG_PROP_HIDDEN
) )
1881 bool wxPGProperty::RecreateEditor()
1883 wxPropertyGrid
* pg
= GetGrid();
1886 wxPGProperty
* selected
= pg
->GetSelection();
1887 if ( this == selected
)
1889 pg
->DoSelectProperty(this, wxPG_SEL_FORCE
);
1896 void wxPGProperty::SetValueImage( wxBitmap
& bmp
)
1898 delete m_valueBitmap
;
1900 if ( &bmp
&& bmp
.Ok() )
1903 wxSize maxSz
= GetGrid()->GetImageSize();
1904 wxSize
imSz(bmp
.GetWidth(),bmp
.GetHeight());
1906 if ( imSz
.x
!= maxSz
.x
|| imSz
.y
!= maxSz
.y
)
1908 // Create a memory DC
1909 wxBitmap
* bmpNew
= new wxBitmap(maxSz
.x
,maxSz
.y
,bmp
.GetDepth());
1912 dc
.SelectObject(*bmpNew
);
1915 // FIXME: This is ugly - use image or wait for scaling patch.
1916 double scaleX
= (double)maxSz
.x
/ (double)imSz
.x
;
1917 double scaleY
= (double)maxSz
.y
/ (double)imSz
.y
;
1919 dc
.SetUserScale(scaleX
,scaleY
);
1921 dc
.DrawBitmap( bmp
, 0, 0 );
1923 m_valueBitmap
= bmpNew
;
1927 m_valueBitmap
= new wxBitmap(bmp
);
1930 m_flags
|= wxPG_PROP_CUSTOMIMAGE
;
1934 m_valueBitmap
= NULL
;
1935 m_flags
&= ~(wxPG_PROP_CUSTOMIMAGE
);
1940 wxPGProperty
* wxPGProperty::GetMainParent() const
1942 const wxPGProperty
* curChild
= this;
1943 const wxPGProperty
* curParent
= m_parent
;
1945 while ( curParent
&& !curParent
->IsCategory() )
1947 curChild
= curParent
;
1948 curParent
= curParent
->m_parent
;
1951 return (wxPGProperty
*) curChild
;
1955 const wxPGProperty
* wxPGProperty::GetLastVisibleSubItem() const
1958 // Returns last visible sub-item, recursively.
1959 if ( !IsExpanded() || !GetChildCount() )
1962 return Last()->GetLastVisibleSubItem();
1966 bool wxPGProperty::IsVisible() const
1968 const wxPGProperty
* parent
;
1970 if ( HasFlag(wxPG_PROP_HIDDEN
) )
1973 for ( parent
= GetParent(); parent
!= NULL
; parent
= parent
->GetParent() )
1975 if ( !parent
->IsExpanded() || parent
->HasFlag(wxPG_PROP_HIDDEN
) )
1982 wxPropertyGrid
* wxPGProperty::GetGridIfDisplayed() const
1984 wxPropertyGridPageState
* state
= GetParentState();
1987 wxPropertyGrid
* propGrid
= state
->GetGrid();
1988 if ( state
== propGrid
->GetState() )
1994 int wxPGProperty::GetY2( int lh
) const
1996 const wxPGProperty
* parent
;
1997 const wxPGProperty
* child
= this;
2001 for ( parent
= GetParent(); parent
!= NULL
; parent
= child
->GetParent() )
2003 if ( !parent
->IsExpanded() )
2005 y
+= parent
->GetChildrenHeight(lh
, child
->GetIndexInParent());
2010 y
-= lh
; // need to reduce one level
2016 int wxPGProperty::GetY() const
2018 return GetY2(GetGrid()->GetRowHeight());
2021 // This is used by Insert etc.
2022 void wxPGProperty::AddChild2( wxPGProperty
* prop
, int index
, bool correct_mode
)
2024 if ( index
< 0 || (size_t)index
>= m_children
.size() )
2026 if ( correct_mode
) prop
->m_arrIndex
= m_children
.size();
2027 m_children
.push_back( prop
);
2031 m_children
.insert( m_children
.begin()+index
, prop
);
2032 if ( correct_mode
) FixIndicesOfChildren( index
);
2035 prop
->m_parent
= this;
2038 // This is used by properties that have fixed sub-properties
2039 void wxPGProperty::AddChild( wxPGProperty
* prop
)
2041 wxASSERT_MSG( prop
->GetBaseName().length(),
2042 "Property's children must have unique, non-empty names within their scope" );
2044 prop
->m_arrIndex
= m_children
.size();
2045 m_children
.push_back( prop
);
2047 int custImgHeight
= prop
->OnMeasureImage().y
;
2048 if ( custImgHeight
< 0 /*|| custImgHeight > 1*/ )
2049 prop
->m_flags
|= wxPG_PROP_CUSTOMIMAGE
;
2051 prop
->m_parent
= this;
2054 void wxPGProperty::RemoveChild( wxPGProperty
* p
)
2056 wxArrayPGProperty::iterator it
;
2057 wxArrayPGProperty
& children
= m_children
;
2059 for ( it
=children
.begin(); it
!= children
.end(); it
++ )
2063 m_children
.erase(it
);
2069 void wxPGProperty::AdaptListToValue( wxVariant
& list
, wxVariant
* value
) const
2071 wxASSERT( GetChildCount() );
2072 wxASSERT( !IsCategory() );
2074 *value
= GetValue();
2076 if ( !list
.GetCount() )
2079 wxASSERT( GetChildCount() >= (unsigned int)list
.GetCount() );
2081 bool allChildrenSpecified
;
2083 // Don't fully update aggregate properties unless all children have
2085 if ( HasFlag(wxPG_PROP_AGGREGATE
) )
2086 allChildrenSpecified
= AreAllChildrenSpecified(&list
);
2088 allChildrenSpecified
= true;
2090 wxVariant childValue
= list
[0];
2094 //wxLogDebug(wxT(">> %s.AdaptListToValue()"),GetBaseName().c_str());
2096 for ( i
=0; i
<GetChildCount(); i
++ )
2098 const wxPGProperty
* child
= Item(i
);
2100 if ( childValue
.GetName() == child
->GetBaseName() )
2102 //wxLogDebug(wxT(" %s(n=%i), %s"),childValue.GetName().c_str(),n,childValue.GetType().c_str());
2104 if ( childValue
.GetType() == wxPG_VARIANT_TYPE_LIST
)
2106 wxVariant
cv2(child
->GetValue());
2107 child
->AdaptListToValue(childValue
, &cv2
);
2111 if ( allChildrenSpecified
)
2112 ChildChanged(*value
, i
, childValue
);
2114 if ( n
== (unsigned int)list
.GetCount() )
2116 childValue
= list
[n
];
2122 void wxPGProperty::FixIndicesOfChildren( unsigned int starthere
)
2125 for ( i
=starthere
;i
<GetChildCount();i
++)
2126 Item(i
)->m_arrIndex
= i
;
2130 // Returns (direct) child property with given name (or NULL if not found)
2131 wxPGProperty
* wxPGProperty::GetPropertyByName( const wxString
& name
) const
2135 for ( i
=0; i
<GetChildCount(); i
++ )
2137 wxPGProperty
* p
= Item(i
);
2138 if ( p
->m_name
== name
)
2142 // Does it have point, then?
2143 int pos
= name
.Find(wxS('.'));
2147 wxPGProperty
* p
= GetPropertyByName(name
. substr(0,pos
));
2149 if ( !p
|| !p
->GetChildCount() )
2152 return p
->GetPropertyByName(name
.substr(pos
+1,name
.length()-pos
-1));
2155 wxPGProperty
* wxPGProperty::GetPropertyByNameWH( const wxString
& name
, unsigned int hintIndex
) const
2157 unsigned int i
= hintIndex
;
2159 if ( i
>= GetChildCount() )
2162 unsigned int lastIndex
= i
- 1;
2164 if ( lastIndex
>= GetChildCount() )
2165 lastIndex
= GetChildCount() - 1;
2169 wxPGProperty
* p
= Item(i
);
2170 if ( p
->m_name
== name
)
2173 if ( i
== lastIndex
)
2177 if ( i
== GetChildCount() )
2184 int wxPGProperty::GetChildrenHeight( int lh
, int iMax_
) const
2186 // Returns height of children, recursively, and
2187 // by taking expanded/collapsed status into account.
2189 // iMax is used when finding property y-positions.
2195 iMax_
= GetChildCount();
2197 unsigned int iMax
= iMax_
;
2199 wxASSERT( iMax
<= GetChildCount() );
2201 if ( !IsExpanded() && GetParent() )
2206 wxPGProperty
* pwc
= (wxPGProperty
*) Item(i
);
2208 if ( !pwc
->HasFlag(wxPG_PROP_HIDDEN
) )
2210 if ( !pwc
->IsExpanded() ||
2211 pwc
->GetChildCount() == 0 )
2214 h
+= pwc
->GetChildrenHeight(lh
) + lh
;
2223 wxPGProperty
* wxPGProperty::GetItemAtY( unsigned int y
, unsigned int lh
, unsigned int* nextItemY
) const
2225 wxASSERT( nextItemY
);
2227 // Linear search at the moment
2229 // nextItemY = y of next visible property, final value will be written back.
2230 wxPGProperty
* result
= NULL
;
2231 wxPGProperty
* current
= NULL
;
2232 unsigned int iy
= *nextItemY
;
2234 unsigned int iMax
= GetChildCount();
2238 wxPGProperty
* pwc
= Item(i
);
2240 if ( !pwc
->HasFlag(wxPG_PROP_HIDDEN
) )
2251 if ( pwc
->IsExpanded() &&
2252 pwc
->GetChildCount() > 0 )
2254 result
= (wxPGProperty
*) pwc
->GetItemAtY( y
, lh
, &iy
);
2266 if ( !result
&& y
< iy
)
2273 wxLogDebug(wxT("%s::GetItemAtY(%i) -> %s"),this->GetLabel().c_str(),y,current->GetLabel().c_str());
2275 wxLogDebug(wxT("%s::GetItemAtY(%i) -> NULL"),this->GetLabel().c_str(),y);
2278 return (wxPGProperty
*) result
;
2281 void wxPGProperty::Empty()
2284 if ( !HasFlag(wxPG_PROP_CHILDREN_ARE_COPIES
) )
2286 for ( i
=0; i
<GetChildCount(); i
++ )
2288 delete m_children
[i
];
2295 void wxPGProperty::DeleteChildren()
2297 wxPropertyGridPageState
* state
= m_parentState
;
2299 while ( GetChildCount() )
2301 wxPGProperty
* child
= Item(GetChildCount()-1);
2302 state
->DoDelete(child
, true);
2306 void wxPGProperty::ChildChanged( wxVariant
& WXUNUSED(thisValue
),
2307 int WXUNUSED(childIndex
),
2308 wxVariant
& WXUNUSED(childValue
) ) const
2312 bool wxPGProperty::AreAllChildrenSpecified( wxVariant
* pendingList
) const
2316 const wxVariantList
* pList
= NULL
;
2317 wxVariantList::const_iterator node
;
2321 pList
= &pendingList
->GetList();
2322 node
= pList
->begin();
2325 for ( i
=0; i
<GetChildCount(); i
++ )
2327 wxPGProperty
* child
= Item(i
);
2328 const wxVariant
* listValue
= NULL
;
2333 const wxString
& childName
= child
->GetBaseName();
2335 for ( ; node
!= pList
->end(); ++node
)
2337 const wxVariant
& item
= *((const wxVariant
*)*node
);
2338 if ( item
.GetName() == childName
)
2348 value
= child
->GetValue();
2350 if ( value
.IsNull() )
2353 // Check recursively
2354 if ( child
->GetChildCount() )
2356 const wxVariant
* childList
= NULL
;
2358 if ( listValue
&& listValue
->GetType() == wxPG_VARIANT_TYPE_LIST
)
2359 childList
= listValue
;
2361 if ( !child
->AreAllChildrenSpecified((wxVariant
*)childList
) )
2369 wxPGProperty
* wxPGProperty::UpdateParentValues()
2371 wxPGProperty
* parent
= m_parent
;
2372 if ( parent
&& parent
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) &&
2373 !parent
->IsCategory() && !parent
->IsRoot() )
2376 parent
->DoGenerateComposedValue(s
);
2377 parent
->m_value
= s
;
2378 return parent
->UpdateParentValues();
2383 bool wxPGProperty::IsTextEditable() const
2385 if ( HasFlag(wxPG_PROP_READONLY
) )
2388 if ( HasFlag(wxPG_PROP_NOEDITOR
) &&
2390 wxString(GetEditorClass()->GetClassInfo()->GetClassName()).EndsWith(wxS("Button")))
2397 // Call after fixed sub-properties added/removed after creation.
2398 // if oldSelInd >= 0 and < new max items, then selection is
2399 // moved to it. Note: oldSelInd -2 indicates that this property
2400 // should be selected.
2401 void wxPGProperty::SubPropsChanged( int oldSelInd
)
2403 wxPropertyGridPageState
* state
= GetParentState();
2404 wxPropertyGrid
* grid
= state
->GetGrid();
2407 // Re-repare children (recursively)
2408 for ( unsigned int i
=0; i
<GetChildCount(); i
++ )
2410 wxPGProperty
* child
= Item(i
);
2411 child
->InitAfterAdded(state
, grid
);
2414 wxPGProperty
* sel
= NULL
;
2415 if ( oldSelInd
>= (int)m_children
.size() )
2416 oldSelInd
= (int)m_children
.size() - 1;
2418 if ( oldSelInd
>= 0 )
2419 sel
= m_children
[oldSelInd
];
2420 else if ( oldSelInd
== -2 )
2424 state
->DoSelectProperty(sel
);
2426 if ( state
== grid
->GetState() )
2428 grid
->GetPanel()->Refresh();
2432 // -----------------------------------------------------------------------
2434 // -----------------------------------------------------------------------
2436 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty
,none
,TextCtrl
)
2437 IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty
, wxPGProperty
)
2440 wxPGRootProperty::wxPGRootProperty( const wxString
& name
)
2454 wxPGRootProperty::~wxPGRootProperty()
2459 // -----------------------------------------------------------------------
2460 // wxPropertyCategory
2461 // -----------------------------------------------------------------------
2463 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPropertyCategory
,none
,TextCtrl
)
2464 IMPLEMENT_DYNAMIC_CLASS(wxPropertyCategory
, wxPGProperty
)
2466 void wxPropertyCategory::Init()
2468 // don't set colour - prepareadditem method should do this
2469 SetParentalType(wxPG_PROP_CATEGORY
);
2470 m_capFgColIndex
= 1;
2474 wxPropertyCategory::wxPropertyCategory()
2481 wxPropertyCategory::wxPropertyCategory( const wxString
&label
, const wxString
& name
)
2482 : wxPGProperty(label
,name
)
2488 wxPropertyCategory::~wxPropertyCategory()
2493 wxString
wxPropertyCategory::ValueToString( wxVariant
& WXUNUSED(value
),
2494 int WXUNUSED(argFlags
) ) const
2496 return wxEmptyString
;
2499 int wxPropertyCategory::GetTextExtent( const wxWindow
* wnd
, const wxFont
& font
) const
2501 if ( m_textExtent
> 0 )
2502 return m_textExtent
;
2504 ((wxWindow
*)wnd
)->GetTextExtent( m_label
, &x
, &y
, 0, 0, &font
);
2508 void wxPropertyCategory::CalculateTextExtent( wxWindow
* wnd
, const wxFont
& font
)
2511 wnd
->GetTextExtent( m_label
, &x
, &y
, 0, 0, &font
);
2515 // -----------------------------------------------------------------------
2517 // -----------------------------------------------------------------------
2519 wxPGChoiceEntry
& wxPGChoices::Add( const wxString
& label
, int value
)
2523 wxPGChoiceEntry
entry(label
, value
);
2524 return m_data
->Insert( -1, entry
);
2527 // -----------------------------------------------------------------------
2529 wxPGChoiceEntry
& wxPGChoices::Add( const wxString
& label
, const wxBitmap
& bitmap
, int value
)
2533 wxPGChoiceEntry
entry(label
, value
);
2534 entry
.SetBitmap(bitmap
);
2535 return m_data
->Insert( -1, entry
);
2538 // -----------------------------------------------------------------------
2540 wxPGChoiceEntry
& wxPGChoices::Insert( const wxPGChoiceEntry
& entry
, int index
)
2544 return m_data
->Insert( index
, entry
);
2547 // -----------------------------------------------------------------------
2549 wxPGChoiceEntry
& wxPGChoices::Insert( const wxString
& label
, int index
, int value
)
2553 wxPGChoiceEntry
entry(label
, value
);
2554 return m_data
->Insert( index
, entry
);
2557 // -----------------------------------------------------------------------
2559 wxPGChoiceEntry
& wxPGChoices::AddAsSorted( const wxString
& label
, int value
)
2565 while ( index
< GetCount() )
2567 int cmpRes
= GetLabel(index
).Cmp(label
);
2573 wxPGChoiceEntry
entry(label
, value
);
2574 return m_data
->Insert( index
, entry
);
2577 // -----------------------------------------------------------------------
2579 void wxPGChoices::Add( const wxChar
** labels
, const ValArrItem
* values
)
2583 unsigned int itemcount
= 0;
2584 const wxChar
** p
= &labels
[0];
2585 while ( *p
) { p
++; itemcount
++; }
2588 for ( i
= 0; i
< itemcount
; i
++ )
2593 wxPGChoiceEntry
entry(labels
[i
], value
);
2594 m_data
->Insert( i
, entry
);
2598 // -----------------------------------------------------------------------
2600 void wxPGChoices::Add( const wxArrayString
& arr
, const wxArrayInt
& arrint
)
2605 unsigned int itemcount
= arr
.size();
2607 for ( i
= 0; i
< itemcount
; i
++ )
2610 if ( &arrint
&& arrint
.size() )
2612 wxPGChoiceEntry
entry(arr
[i
], value
);
2613 m_data
->Insert( i
, entry
);
2617 // -----------------------------------------------------------------------
2619 void wxPGChoices::RemoveAt(size_t nIndex
, size_t count
)
2623 wxASSERT( m_data
->m_refCount
!= 0xFFFFFFF );
2624 m_data
->m_items
.erase(m_data
->m_items
.begin()+nIndex
,
2625 m_data
->m_items
.begin()+nIndex
+count
);
2628 // -----------------------------------------------------------------------
2630 void wxPGChoices::Clear()
2632 if ( m_data
!= wxPGChoicesEmptyData
)
2639 // -----------------------------------------------------------------------
2641 int wxPGChoices::Index( const wxString
& str
) const
2646 for ( i
=0; i
< m_data
->GetCount(); i
++ )
2648 const wxPGChoiceEntry
& entry
= m_data
->Item(i
);
2649 if ( entry
.HasText() && entry
.GetText() == str
)
2656 // -----------------------------------------------------------------------
2658 int wxPGChoices::Index( int val
) const
2663 for ( i
=0; i
< m_data
->GetCount(); i
++ )
2665 const wxPGChoiceEntry
& entry
= m_data
->Item(i
);
2666 if ( entry
.GetValue() == val
)
2673 // -----------------------------------------------------------------------
2675 wxArrayString
wxPGChoices::GetLabels() const
2680 if ( this && IsOk() )
2681 for ( i
=0; i
<GetCount(); i
++ )
2682 arr
.push_back(GetLabel(i
));
2687 // -----------------------------------------------------------------------
2689 wxArrayInt
wxPGChoices::GetValuesForStrings( const wxArrayString
& strings
) const
2696 for ( i
=0; i
< strings
.size(); i
++ )
2698 int index
= Index(strings
[i
]);
2700 arr
.Add(GetValue(index
));
2702 arr
.Add(wxPG_INVALID_VALUE
);
2709 // -----------------------------------------------------------------------
2711 wxArrayInt
wxPGChoices::GetIndicesForStrings( const wxArrayString
& strings
,
2712 wxArrayString
* unmatched
) const
2719 for ( i
=0; i
< strings
.size(); i
++ )
2721 const wxString
& str
= strings
[i
];
2722 int index
= Index(str
);
2725 else if ( unmatched
)
2726 unmatched
->Add(str
);
2733 // -----------------------------------------------------------------------
2735 void wxPGChoices::AllocExclusive()
2739 if ( m_data
->m_refCount
!= 1 )
2741 wxPGChoicesData
* data
= new wxPGChoicesData();
2742 data
->CopyDataFrom(m_data
);
2748 // -----------------------------------------------------------------------
2750 void wxPGChoices::AssignData( wxPGChoicesData
* data
)
2754 if ( data
!= wxPGChoicesEmptyData
)
2761 // -----------------------------------------------------------------------
2763 void wxPGChoices::Init()
2765 m_data
= wxPGChoicesEmptyData
;
2768 // -----------------------------------------------------------------------
2770 void wxPGChoices::Free()
2772 if ( m_data
!= wxPGChoicesEmptyData
)
2775 m_data
= wxPGChoicesEmptyData
;
2779 // -----------------------------------------------------------------------
2780 // wxPGAttributeStorage
2781 // -----------------------------------------------------------------------
2783 wxPGAttributeStorage::wxPGAttributeStorage()
2787 wxPGAttributeStorage::~wxPGAttributeStorage()
2789 wxPGHashMapS2P::iterator it
;
2791 for ( it
= m_map
.begin(); it
!= m_map
.end(); ++it
)
2793 wxVariantData
* data
= (wxVariantData
*) it
->second
;
2798 void wxPGAttributeStorage::Set( const wxString
& name
, const wxVariant
& value
)
2800 wxVariantData
* data
= value
.GetData();
2803 wxPGHashMapS2P::iterator it
= m_map
.find(name
);
2804 if ( it
!= m_map
.end() )
2806 ((wxVariantData
*)it
->second
)->DecRef();
2810 // If Null variant, just remove from set
2824 #endif // wxUSE_PROPGRID