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());
153 dc
.DrawRectangle(rect
);
155 const wxBitmap
& bmp
= cell
.GetBitmap();
157 // Do not draw oversized bitmap outside choice popup
158 ((flags
& ChoicePopup
) || bmp
.GetHeight() < rect
.height
)
162 rect
.x
+ wxPG_CONTROL_MARGIN
+ wxCC_CUSTOM_IMAGE_MARGIN1
,
163 rect
.y
+ wxPG_CUSTOM_IMAGE_SPACINGY
,
165 imageOffset
= bmp
.GetWidth();
171 // -----------------------------------------------------------------------
172 // wxPGDefaultRenderer
173 // -----------------------------------------------------------------------
175 void wxPGDefaultRenderer
::Render( wxDC
& dc
, const wxRect
& rect
,
176 const wxPropertyGrid
* propertyGrid
, wxPGProperty
* property
,
177 int column
, int item
, int flags
) const
179 bool isUnspecified
= property
->IsValueUnspecified();
181 if ( column
== 1 && item
== -1 )
183 int cmnVal
= property
->GetCommonValue();
187 if ( !isUnspecified
)
188 DrawText( dc
, rect
, 0, propertyGrid
->GetCommonValueLabel(cmnVal
) );
193 const wxPGEditor
* editor
= NULL
;
194 const wxPGCell
* cell
= NULL
;
198 int preDrawFlags
= flags
;
200 property
->GetDisplayInfo(column
, item
, flags
, &text
, &cell
);
202 imageOffset
= PreDrawCell( dc
, rect
, *cell
, preDrawFlags
);
206 if ( !isUnspecified
)
208 editor
= property
->GetColumnEditor(column
);
210 // Regular property value
212 wxSize imageSize
= propertyGrid
->GetImageSize(property
, item
);
214 wxPGPaintData paintdata
;
215 paintdata
.m_parent
= propertyGrid
;
216 paintdata
.m_choiceItem
= item
;
218 if ( imageSize
.x
> 0 )
220 wxRect
imageRect(rect
.x
+ wxPG_CONTROL_MARGIN
+ wxCC_CUSTOM_IMAGE_MARGIN1
,
221 rect
.y
+wxPG_CUSTOM_IMAGE_SPACINGY
,
222 wxPG_CUSTOM_IMAGE_WIDTH
,
223 rect
.height
-(wxPG_CUSTOM_IMAGE_SPACINGY
*2));
225 dc
.SetPen( wxPen(propertyGrid
->GetCellTextColour(), 1, wxSOLID
) );
227 paintdata
.m_drawnWidth
= imageSize
.x
;
228 paintdata
.m_drawnHeight
= imageSize
.y
;
230 if ( !isUnspecified
)
232 property
->OnCustomPaint( dc
, imageRect
, paintdata
);
236 dc
.SetBrush(*wxWHITE_BRUSH
);
237 dc
.DrawRectangle(imageRect
);
240 imageOffset
= paintdata
.m_drawnWidth
;
243 text
= property
->GetValueAsString();
246 if ( propertyGrid
->GetColumnCount() <= 2 )
248 wxString unitsString
= property
->GetAttribute(wxPGGlobalVars
->m_strUnits
, wxEmptyString
);
249 if ( unitsString
.length() )
250 text
= wxString
::Format(wxS("%s %s"), text
.c_str(), unitsString
.c_str() );
254 if ( text
.length() == 0 )
256 // Try to show inline help if no text
257 wxVariant vInlineHelp
= property
->GetAttribute(wxPGGlobalVars
->m_strInlineHelp
);
258 if ( !vInlineHelp
.IsNull() )
260 text
= vInlineHelp
.GetString();
261 dc
.SetTextForeground(propertyGrid
->GetCellDisabledTextColour());
266 DrawEditorValue( dc
, rect
, imageOffset
, text
, property
, editor
);
268 // active caption gets nice dotted rectangle
269 if ( property
->IsCategory() /*&& column == 0*/ )
271 if ( flags
& Selected
)
273 if ( imageOffset
> 0 )
274 imageOffset
+= wxCC_CUSTOM_IMAGE_MARGIN2
+ 4;
276 DrawCaptionSelectionRect( dc
,
277 rect
.x
+wxPG_XBEFORETEXT
-wxPG_CAPRECTXMARGIN
+imageOffset
,
278 rect
.y
-wxPG_CAPRECTYMARGIN
+1,
279 ((wxPropertyCategory
*)property
)->GetTextExtent(propertyGrid
,
280 propertyGrid
->GetCaptionFont())
281 +(wxPG_CAPRECTXMARGIN
*2),
282 propertyGrid
->GetFontHeight()+(wxPG_CAPRECTYMARGIN
*2) );
287 wxSize wxPGDefaultRenderer
::GetImageSize( const wxPGProperty
* property
,
291 if ( property
&& column
== 1 )
295 wxBitmap
* bmp
= property
->GetValueImage();
297 if ( bmp
&& bmp
->Ok() )
298 return wxSize(bmp
->GetWidth(),bmp
->GetHeight());
304 // -----------------------------------------------------------------------
306 // -----------------------------------------------------------------------
308 wxPGCellData
::wxPGCellData()
311 m_hasValidText
= false;
314 // -----------------------------------------------------------------------
316 // -----------------------------------------------------------------------
323 wxPGCell
::wxPGCell( const wxString
& text
,
324 const wxBitmap
& bitmap
,
325 const wxColour
& fgCol
,
326 const wxColour
& bgCol
)
329 wxPGCellData
* data
= new wxPGCellData();
332 data
->m_bitmap
= bitmap
;
333 data
->m_fgCol
= fgCol
;
334 data
->m_bgCol
= bgCol
;
335 data
->m_hasValidText
= true;
338 wxObjectRefData
*wxPGCell
::CloneRefData( const wxObjectRefData
*data
) const
340 wxPGCellData
* c
= new wxPGCellData();
341 const wxPGCellData
* o
= (const wxPGCellData
*) data
;
342 c
->m_text
= o
->m_text
;
343 c
->m_bitmap
= o
->m_bitmap
;
344 c
->m_fgCol
= o
->m_fgCol
;
345 c
->m_bgCol
= o
->m_bgCol
;
346 c
->m_hasValidText
= o
->m_hasValidText
;
350 void wxPGCell
::SetText( const wxString
& text
)
354 GetData()->SetText(text
);
357 void wxPGCell
::SetBitmap( const wxBitmap
& bitmap
)
361 GetData()->SetBitmap(bitmap
);
364 void wxPGCell
::SetFgCol( const wxColour
& col
)
368 GetData()->SetFgCol(col
);
371 void wxPGCell
::SetBgCol( const wxColour
& col
)
375 GetData()->SetBgCol(col
);
378 void wxPGCell
::MergeFrom( const wxPGCell
& srcCell
)
382 wxPGCellData
* data
= GetData();
384 if ( srcCell
.HasText() )
385 data
->SetText(srcCell
.GetText());
387 if ( srcCell
.GetFgCol().IsOk() )
388 data
->SetFgCol(srcCell
.GetFgCol());
390 if ( srcCell
.GetBgCol().IsOk() )
391 data
->SetBgCol(srcCell
.GetBgCol());
393 if ( srcCell
.GetBitmap().IsOk() )
394 data
->SetBitmap(srcCell
.GetBitmap());
397 // -----------------------------------------------------------------------
399 // -----------------------------------------------------------------------
401 IMPLEMENT_ABSTRACT_CLASS(wxPGProperty
, wxObject
)
403 wxString
* wxPGProperty
::sm_wxPG_LABEL
= NULL
;
405 void wxPGProperty
::Init()
411 m_parentState
= (wxPropertyGridPageState
*) NULL
;
414 m_clientObject
= NULL
;
416 m_customEditor
= (wxPGEditor
*) NULL
;
418 m_validator
= (wxValidator
*) NULL
;
420 m_valueBitmap
= (wxBitmap
*) NULL
;
422 m_maxLen
= 0; // infinite maximum length
424 m_flags
= wxPG_PROP_PROPERTY
;
432 void wxPGProperty
::Init( const wxString
& label
, const wxString
& name
)
434 // We really need to check if &label and &name are NULL pointers
435 // (this can if we are called before property grid has been initalized)
437 if ( (&label
) != NULL
&& label
!= wxPG_LABEL
)
440 if ( (&name
) != NULL
&& name
!= wxPG_LABEL
)
443 DoSetName( m_label
);
448 void wxPGProperty
::InitAfterAdded( wxPropertyGridPageState
* pageState
,
449 wxPropertyGrid
* propgrid
)
452 // Called after property has been added to grid or page
453 // (so propgrid can be NULL, too).
455 wxPGProperty
* parent
= m_parent
;
456 bool parentIsRoot
= parent
->IsKindOf(CLASSINFO(wxPGRootProperty
));
458 m_parentState
= pageState
;
460 #if wxPG_COMPATIBILITY_1_4
461 // Make sure deprecated virtual functions are not implemented
462 wxString s
= GetValueAsString( 0xFFFF );
463 wxASSERT_MSG( s
== g_invalidStringContent
,
464 "Implement ValueToString() instead of GetValueAsString()" );
467 if ( !parentIsRoot
&& !parent
->IsCategory() )
469 m_cells
= parent
->m_cells
;
472 // If in hideable adding mode, or if assigned parent is hideable, then
473 // make this one hideable.
475 ( !parentIsRoot
&& parent
->HasFlag(wxPG_PROP_HIDDEN
) ) ||
476 ( propgrid
&& (propgrid
->HasInternalFlag(wxPG_FL_ADDING_HIDEABLES
)) )
478 SetFlag( wxPG_PROP_HIDDEN
);
480 // Set custom image flag.
481 int custImgHeight
= OnMeasureImage().y
;
482 if ( custImgHeight
< 0 )
484 SetFlag(wxPG_PROP_CUSTOMIMAGE
);
487 if ( propgrid
&& (propgrid
->HasFlag(wxPG_LIMITED_EDITING
)) )
488 SetFlag(wxPG_PROP_NOEDITOR
);
490 // Make sure parent has some parental flags
491 if ( !parent
->HasFlag(wxPG_PROP_PARENTAL_FLAGS
) )
492 parent
->SetParentalType(wxPG_PROP_MISC_PARENT
);
496 // This is not a category.
500 unsigned char depth
= 1;
503 depth
= parent
->m_depth
;
504 if ( !parent
->IsCategory() )
508 unsigned char greyDepth
= depth
;
512 wxPropertyCategory
* pc
;
514 if ( parent
->IsCategory() )
515 pc
= (wxPropertyCategory
* ) parent
;
517 // This conditional compile is necessary to
518 // bypass some compiler bug.
519 pc
= pageState
->GetPropertyCategory(parent
);
522 greyDepth
= pc
->GetDepth();
524 greyDepth
= parent
->m_depthBgCol
;
527 m_depthBgCol
= greyDepth
;
531 // This is a category.
534 unsigned char depth
= 1;
537 depth
= parent
->m_depth
+ 1;
540 m_depthBgCol
= depth
;
544 // Has initial children
545 if ( GetChildCount() )
547 FlagType parentalFlags
= m_flags
& wxPG_PROP_PARENTAL_FLAGS
;
549 // Check parental flags
550 wxASSERT_MSG( parentalFlags
,
551 "Call SetFlag(wxPG_PROP_MISC_PARENT) or"
552 "SetFlag(wxPG_PROP_AGGREGATE) before calling"
553 "wxPGProperty::AddChild()." );
555 if ( HasFlag(wxPG_PROP_AGGREGATE
) )
557 // Properties with private children are not expanded by default.
560 else if ( propgrid
&& propgrid
->HasFlag(wxPG_HIDE_MARGIN
) )
562 // ...unless it cannot be expanded by user and therefore must
563 // remain visible at all times
568 // Prepare children recursively
569 for ( unsigned int i
=0; i
<GetChildCount(); i
++ )
571 wxPGProperty
* child
= Item(i
);
572 child
->InitAfterAdded(pageState
, pageState
->GetGrid());
575 if ( propgrid
&& (propgrid
->GetExtraStyle() & wxPG_EX_AUTO_UNSPECIFIED_VALUES
) )
576 SetFlagRecursively(wxPG_PROP_AUTO_UNSPECIFIED
, true);
580 wxPGProperty
::wxPGProperty()
587 wxPGProperty
::wxPGProperty( const wxString
& label
, const wxString
& name
)
594 wxPGProperty
::~wxPGProperty()
596 delete m_clientObject
;
598 Empty(); // this deletes items
600 delete m_valueBitmap
;
605 // This makes it easier for us to detect dangling pointers
610 bool wxPGProperty
::IsSomeParent( wxPGProperty
* candidate
) const
612 wxPGProperty
* parent
= m_parent
;
615 if ( parent
== candidate
)
617 parent
= parent
->m_parent
;
623 wxString wxPGProperty
::GetName() const
625 wxPGProperty
* parent
= GetParent();
627 if ( !m_name
.length() || !parent
|| parent
->IsCategory() || parent
->IsRoot() )
630 return m_parent
->GetName() + wxS(".") + m_name
;
633 wxPropertyGrid
* wxPGProperty
::GetGrid() const
635 if ( !m_parentState
)
637 return m_parentState
->GetGrid();
640 int wxPGProperty
::Index( const wxPGProperty
* p
) const
642 for ( unsigned int i
= 0; i
<m_children
.size(); i
++ )
644 if ( p
== m_children
[i
] )
650 void wxPGProperty
::UpdateControl( wxWindow
* primary
)
653 GetEditorClass()->UpdateControl(this, primary
);
656 bool wxPGProperty
::ValidateValue( wxVariant
& WXUNUSED(value
), wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
661 void wxPGProperty
::OnSetValue()
665 void wxPGProperty
::RefreshChildren ()
669 void wxPGProperty
::GetDisplayInfo( unsigned int column
,
673 const wxPGCell
** pCell
)
675 const wxPGCell
* cell
= NULL
;
677 if ( !(flags
& wxPGCellRenderer
::ChoicePopup
) )
679 // Not painting listi of choice popups, so get text from property
680 cell
= &GetCell(column
);
681 if ( cell
->HasText() )
683 *pString
= cell
->GetText();
688 *pString
= GetLabel();
689 else if ( column
== 1 )
690 *pString
= GetDisplayedString();
691 else if ( column
== 2 )
692 *pString
= GetAttribute(wxPGGlobalVars
->m_strUnits
, wxEmptyString
);
697 wxASSERT( column
== 1 );
699 if ( choiceIndex
!= wxNOT_FOUND
)
701 const wxPGChoiceEntry
& entry
= m_choices
[choiceIndex
];
702 if ( entry
.GetBitmap().IsOk() ||
703 entry
.GetFgCol().IsOk() ||
704 entry
.GetBgCol().IsOk() )
706 *pString
= m_choices
.GetLabel(choiceIndex
);
711 cell
= &GetCell(column
);
713 wxASSERT_MSG( cell
->GetData(),
714 wxString
::Format("Invalid cell for property %s",
715 GetName().c_str()) );
721 wxString wxPGProperty::GetColumnText( unsigned int col, int choiceIndex ) const
724 if ( col != 1 || choiceIndex == wxNOT_FOUND )
726 const wxPGCell& cell = GetCell(col);
727 if ( cell->HasText() )
729 return cell->GetText();
736 return GetDisplayedString();
738 return GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
744 return m_choices.GetLabel(choiceIndex);
747 return wxEmptyString;
751 void wxPGProperty
::DoGenerateComposedValue( wxString
& text
,
753 const wxVariantList
* valueOverrides
,
754 wxPGHashMapS2S
* childResults
) const
757 int iMax
= m_children
.size();
763 if ( iMax
> PWC_CHILD_SUMMARY_LIMIT
&&
764 !(argFlags
& wxPG_FULL_VALUE
) )
765 iMax
= PWC_CHILD_SUMMARY_LIMIT
;
767 int iMaxMinusOne
= iMax
-1;
769 if ( !IsTextEditable() )
770 argFlags
|= wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
;
772 wxPGProperty
* curChild
= m_children
[0];
774 bool overridesLeft
= false;
775 wxVariant overrideValue
;
776 wxVariantList
::const_iterator node
;
778 if ( valueOverrides
)
780 node
= valueOverrides
->begin();
781 if ( node
!= valueOverrides
->end() )
783 overrideValue
= *node
;
784 overridesLeft
= true;
788 for ( i
= 0; i
< iMax
; i
++ )
790 wxVariant childValue
;
792 wxString childLabel
= curChild
->GetLabel();
794 // Check for value override
795 if ( overridesLeft
&& overrideValue
.GetName() == childLabel
)
797 if ( !overrideValue
.IsNull() )
798 childValue
= overrideValue
;
800 childValue
= curChild
->GetValue();
802 if ( node
!= valueOverrides
->end() )
803 overrideValue
= *node
;
805 overridesLeft
= false;
809 childValue
= curChild
->GetValue();
813 if ( !childValue
.IsNull() )
815 if ( overridesLeft
&&
816 curChild
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) &&
817 childValue
.GetType() == wxPG_VARIANT_TYPE_LIST
)
819 wxVariantList
& childList
= childValue
.GetList();
820 DoGenerateComposedValue(s
, argFlags
|wxPG_COMPOSITE_FRAGMENT
,
821 &childList
, childResults
);
825 s
= curChild
->ValueToString(childValue
,
826 argFlags
|wxPG_COMPOSITE_FRAGMENT
);
830 if ( childResults
&& curChild
->GetChildCount() )
831 (*childResults
)[curChild
->GetName()] = s
;
834 if ( (argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
) && !s
.length() )
837 if ( !curChild
->GetChildCount() || skip
)
840 text
+= wxS("[") + s
+ wxS("]");
842 if ( i
< iMaxMinusOne
)
844 if ( text
.length() > PWC_CHILD_SUMMARY_CHAR_LIMIT
&&
845 !(argFlags
& wxPG_EDITABLE_VALUE
) &&
846 !(argFlags
& wxPG_FULL_VALUE
) )
851 if ( !curChild
->GetChildCount() )
857 curChild
= m_children
[i
+1];
861 // Remove superfluous semicolon and space
863 if ( text
.EndsWith(wxS("; "), &rest
) )
866 if ( (unsigned int)i
< m_children
.size() )
867 text
+= wxS("; ...");
870 wxString wxPGProperty
::ValueToString( wxVariant
& WXUNUSED(value
),
873 wxCHECK_MSG( GetChildCount() > 0,
875 "If user property does not have any children, it must "
876 "override GetValueAsString" );
878 // FIXME: Currently code below only works if value is actually m_value
879 wxASSERT_MSG( argFlags
& wxPG_VALUE_IS_CURRENT
,
880 "Sorry, currently default wxPGProperty::ValueToString() "
881 "implementation only works if value is m_value." );
884 DoGenerateComposedValue(text
, argFlags
);
888 wxString wxPGProperty
::GetValueAsString( int argFlags
) const
890 #if wxPG_COMPATIBILITY_1_4
891 // This is backwards compatibility test
892 // That is, to make sure this function is not overridden
893 // (instead, ValueToString() should be).
894 if ( argFlags
== 0xFFFF )
896 // Do not override! (for backwards compliancy)
897 return g_invalidStringContent
;
901 if ( IsValueUnspecified() )
902 return wxEmptyString
;
904 if ( m_commonValue
== -1 )
906 wxVariant
value(GetValue());
907 return ValueToString(value
, argFlags
|wxPG_VALUE_IS_CURRENT
);
911 // Return common value's string representation
912 wxPropertyGrid
* pg
= GetGrid();
913 const wxPGCommonValue
* cv
= pg
->GetCommonValue(m_commonValue
);
915 if ( argFlags
& wxPG_FULL_VALUE
)
917 return cv
->GetLabel();
919 else if ( argFlags
& wxPG_EDITABLE_VALUE
)
921 return cv
->GetEditableText();
925 return cv
->GetLabel();
929 wxString wxPGProperty
::GetValueString( int argFlags
) const
931 return GetValueAsString(argFlags
);
934 bool wxPGProperty
::IntToValue( wxVariant
& variant
, int number
, int WXUNUSED(argFlags
) ) const
936 variant
= (long)number
;
940 // Convert semicolon delimited tokens into child values.
941 bool wxPGProperty
::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
943 if ( !GetChildCount() )
946 unsigned int curChild
= 0;
948 unsigned int iMax
= m_children
.size();
950 if ( iMax
> PWC_CHILD_SUMMARY_LIMIT
&&
951 !(argFlags
& wxPG_FULL_VALUE
) )
952 iMax
= PWC_CHILD_SUMMARY_LIMIT
;
954 bool changed
= false;
959 // Its best only to add non-empty group items
960 bool addOnlyIfNotEmpty
= false;
961 const wxChar delimeter
= wxS(';');
963 size_t tokenStart
= 0xFFFFFF;
965 wxVariantList temp_list
;
966 wxVariant
list(temp_list
);
968 int propagatedFlags
= argFlags
& (wxPG_REPORT_ERROR
|wxPG_PROGRAMMATIC_VALUE
);
971 bool debug_print
= false;
976 wxLogDebug(wxT(">> %s.StringToValue('%s')"),GetLabel().c_str(),text
.c_str());
979 wxString
::const_iterator it
= text
.begin();
982 if ( it
!= text
.end() )
989 if ( tokenStart
!= 0xFFFFFF )
992 if ( a
== delimeter
|| a
== 0 )
994 token
= text
.substr(tokenStart
,pos
-tokenStart
);
996 size_t len
= token
.length();
998 if ( !addOnlyIfNotEmpty
|| len
> 0 )
1000 const wxPGProperty
* child
= Item(curChild
);
1001 wxVariant
variant(child
->GetValue());
1002 variant
.SetName(child
->GetBaseName());
1006 wxLogDebug(wxT("token = '%s', child = %s"),token
.c_str(),child
->GetLabel().c_str());
1009 // Add only if editable or setting programmatically
1010 if ( (argFlags
& wxPG_PROGRAMMATIC_VALUE
) ||
1011 !child
->HasFlag(wxPG_PROP_DISABLED
|wxPG_PROP_READONLY
) )
1015 bool wasUnspecified
= child
->IsValueUnspecified();
1017 if ( child
->StringToValue(variant
, token
, propagatedFlags
|wxPG_COMPOSITE_FRAGMENT
) )
1019 // Clear unspecified flag only if OnSetValue() didn't
1021 if ( child
->IsValueUnspecified() &&
1022 (wasUnspecified
|| !UsesAutoUnspecified()) )
1024 variant
= child
->GetDefaultValue();
1027 list
.Append(variant
);
1034 // Empty, becomes unspecified
1036 list
.Append(variant
);
1042 if ( curChild
>= iMax
)
1046 tokenStart
= 0xFFFFFF;
1051 // Token is not running
1052 if ( a
!= wxS(' ') )
1055 addOnlyIfNotEmpty
= false;
1057 // Is this a group of tokens?
1058 if ( a
== wxS('[') )
1062 if ( it
!= text
.end() ) it
++;
1064 size_t startPos
= pos
;
1066 // Group item - find end
1067 while ( it
!= text
.end() && depth
> 0 )
1073 if ( a
== wxS(']') )
1075 else if ( a
== wxS('[') )
1079 token
= text
.substr(startPos
,pos
-startPos
-1);
1081 if ( !token
.length() )
1084 const wxPGProperty
* child
= Item(curChild
);
1086 wxVariant oldChildValue
= child
->GetValue();
1087 wxVariant
variant(oldChildValue
);
1089 if ( (argFlags
& wxPG_PROGRAMMATIC_VALUE
) ||
1090 !child
->HasFlag(wxPG_PROP_DISABLED
|wxPG_PROP_READONLY
) )
1092 bool stvRes
= child
->StringToValue( variant
, token
, propagatedFlags
);
1093 if ( stvRes
|| (variant
!= oldChildValue
) )
1100 // Failed, becomes unspecified
1106 variant
.SetName(child
->GetBaseName());
1107 list
.Append(variant
);
1110 if ( curChild
>= iMax
)
1113 addOnlyIfNotEmpty
= true;
1115 tokenStart
= 0xFFFFFF;
1121 if ( a
== delimeter
)
1134 if ( it
!= text
.end() )
1151 bool wxPGProperty
::SetValueFromString( const wxString
& text
, int argFlags
)
1153 wxVariant
variant(m_value
);
1154 bool res
= StringToValue(variant
, text
, argFlags
);
1160 bool wxPGProperty
::SetValueFromInt( long number
, int argFlags
)
1162 wxVariant
variant(m_value
);
1163 bool res
= IntToValue(variant
, number
, argFlags
);
1169 wxSize wxPGProperty
::OnMeasureImage( int WXUNUSED(item
) ) const
1171 if ( m_valueBitmap
)
1172 return wxSize(m_valueBitmap
->GetWidth(),-1);
1177 wxPGCellRenderer
* wxPGProperty
::GetCellRenderer( int WXUNUSED(column
) ) const
1179 return wxPGGlobalVars
->m_defaultRenderer
;
1182 void wxPGProperty
::OnCustomPaint( wxDC
& dc
,
1186 wxBitmap
* bmp
= m_valueBitmap
;
1188 wxCHECK_RET( bmp
&& bmp
->Ok(), wxT("invalid bitmap") );
1190 wxCHECK_RET( rect
.x
>= 0, wxT("unexpected measure call") );
1192 dc
.DrawBitmap(*bmp
,rect
.x
,rect
.y
);
1195 const wxPGEditor
* wxPGProperty
::DoGetEditorClass() const
1197 return wxPGEditor_TextCtrl
;
1200 // Default extra property event handling - that is, none at all.
1201 bool wxPGProperty
::OnEvent( wxPropertyGrid
*, wxWindow
*, wxEvent
& )
1207 void wxPGProperty
::SetValue( wxVariant value
, wxVariant
* pList
, int flags
)
1209 // If auto unspecified values are not wanted (via window or property style),
1210 // then get default value instead of wxNullVariant.
1211 if ( value
.IsNull() && (flags
& wxPG_SETVAL_BY_USER
) &&
1212 !UsesAutoUnspecified() )
1214 value
= GetDefaultValue();
1217 if ( !value
.IsNull() )
1219 wxVariant tempListVariant
;
1222 // List variants are reserved a special purpose
1223 // as intermediate containers for child values
1224 // of properties with children.
1225 if ( value
.GetType() == wxPG_VARIANT_TYPE_LIST
)
1228 // However, situation is different for composed string properties
1229 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
1231 tempListVariant
= value
;
1232 pList
= &tempListVariant
;
1236 AdaptListToValue(value
, &newValue
);
1238 //wxLogDebug(wxT(">> %s.SetValue() adapted list value to type '%s'"),GetName().c_str(),value.GetType().c_str());
1241 if ( HasFlag( wxPG_PROP_AGGREGATE
) )
1242 flags
|= wxPG_SETVAL_AGGREGATED
;
1244 if ( pList
&& !pList
->IsNull() )
1246 wxASSERT( pList
->GetType() == wxPG_VARIANT_TYPE_LIST
);
1247 wxASSERT( GetChildCount() );
1248 wxASSERT( !IsCategory() );
1250 wxVariantList
& list
= pList
->GetList();
1251 wxVariantList
::iterator node
;
1254 //wxLogDebug(wxT(">> %s.SetValue() pList parsing"),GetName().c_str());
1256 // Children in list can be in any order, but we will give hint to
1257 // GetPropertyByNameWH(). This optimizes for full list parsing.
1258 for ( node
= list
.begin(); node
!= list
.end(); node
++ )
1260 wxVariant
& childValue
= *((wxVariant
*)*node
);
1261 wxPGProperty
* child
= GetPropertyByNameWH(childValue
.GetName(), i
);
1264 //wxLogDebug(wxT("%i: child = %s, childValue.GetType()=%s"),i,child->GetBaseName().c_str(),childValue.GetType().c_str());
1265 if ( childValue
.GetType() == wxPG_VARIANT_TYPE_LIST
)
1267 if ( child
->HasFlag(wxPG_PROP_AGGREGATE
) && !(flags
& wxPG_SETVAL_AGGREGATED
) )
1269 wxVariant listRefCopy
= childValue
;
1270 child
->SetValue(childValue
, &listRefCopy
, flags
|wxPG_SETVAL_FROM_PARENT
);
1274 wxVariant oldVal
= child
->GetValue();
1275 child
->SetValue(oldVal
, &childValue
, flags
|wxPG_SETVAL_FROM_PARENT
);
1278 else if ( child
->GetValue() != childValue
)
1280 // For aggregate properties, we will trust RefreshChildren()
1281 // to update child values.
1282 if ( !HasFlag(wxPG_PROP_AGGREGATE
) )
1283 child
->SetValue(childValue
, NULL
, flags
|wxPG_SETVAL_FROM_PARENT
);
1284 if ( flags
& wxPG_SETVAL_BY_USER
)
1285 child
->SetFlag(wxPG_PROP_MODIFIED
);
1292 if ( !value
.IsNull() )
1297 if ( !(flags
& wxPG_SETVAL_FROM_PARENT
) )
1298 UpdateParentValues();
1301 if ( flags
& wxPG_SETVAL_BY_USER
)
1302 SetFlag(wxPG_PROP_MODIFIED
);
1304 if ( HasFlag(wxPG_PROP_AGGREGATE
) )
1309 if ( m_commonValue
!= -1 )
1311 wxPropertyGrid
* pg
= GetGrid();
1312 if ( !pg
|| m_commonValue
!= pg
->GetUnspecifiedCommonValue() )
1318 // Set children to unspecified, but only if aggregate or
1319 // value is <composed>
1320 if ( AreChildrenComponents() )
1323 for ( i
=0; i
<GetChildCount(); i
++ )
1324 Item(i
)->SetValue(value
, NULL
, flags
|wxPG_SETVAL_FROM_PARENT
);
1329 // Update editor control
1332 // We need to check for these, otherwise GetGrid() may fail.
1333 if ( flags
& wxPG_SETVAL_REFRESH_EDITOR
)
1338 void wxPGProperty
::SetValueInEvent( wxVariant value
) const
1340 GetGrid()->ValueChangeInEvent(value
);
1343 void wxPGProperty
::SetFlagRecursively( FlagType flag
, bool set
)
1351 for ( i
= 0; i
< GetChildCount(); i
++ )
1352 Item(i
)->SetFlagRecursively(flag
, set
);
1355 void wxPGProperty
::RefreshEditor()
1357 if ( m_parent
&& GetParentState() )
1359 wxPropertyGrid
* pg
= GetParentState()->GetGrid();
1360 if ( pg
->GetSelectedProperty() == this )
1362 wxWindow
* editor
= pg
->GetEditorControl();
1364 GetEditorClass()->UpdateControl( this, editor
);
1370 wxVariant wxPGProperty
::GetDefaultValue() const
1372 wxVariant defVal
= GetAttribute(wxS("DefaultValue"));
1373 if ( !defVal
.IsNull() )
1376 wxVariant value
= GetValue();
1378 if ( !value
.IsNull() )
1380 wxString
valueType(value
.GetType());
1382 if ( valueType
== wxPG_VARIANT_TYPE_LONG
)
1383 return wxPGVariant_Zero
;
1384 if ( valueType
== wxPG_VARIANT_TYPE_STRING
)
1385 return wxPGVariant_EmptyString
;
1386 if ( valueType
== wxPG_VARIANT_TYPE_BOOL
)
1387 return wxPGVariant_False
;
1388 if ( valueType
== wxPG_VARIANT_TYPE_DOUBLE
)
1389 return wxVariant(0.0);
1390 if ( valueType
== wxPG_VARIANT_TYPE_ARRSTRING
)
1391 return wxVariant(wxArrayString());
1392 if ( valueType
== wxS("wxLongLong") )
1393 return WXVARIANT(wxLongLong(0));
1394 if ( valueType
== wxS("wxULongLong") )
1395 return WXVARIANT(wxULongLong(0));
1396 if ( valueType
== wxS("wxColour") )
1397 return WXVARIANT(*wxBLACK
);
1399 if ( valueType
== wxPG_VARIANT_TYPE_DATETIME
)
1400 return wxVariant(wxDateTime
::Now());
1402 if ( valueType
== wxS("wxFont") )
1403 return WXVARIANT(*wxNORMAL_FONT
);
1404 if ( valueType
== wxS("wxPoint") )
1405 return WXVARIANT(wxPoint(0, 0));
1406 if ( valueType
== wxS("wxSize") )
1407 return WXVARIANT(wxSize(0, 0));
1413 void wxPGProperty
::EnsureCells( unsigned int column
)
1415 if ( column
>= m_cells
.size() )
1417 // Fill empty slots with default cells
1418 wxPropertyGrid
* pg
= GetGrid();
1419 wxPGCell defaultCell
;
1421 if ( !HasFlag(wxPG_PROP_CATEGORY
) )
1422 defaultCell
= pg
->GetPropertyDefaultCell();
1424 defaultCell
= pg
->GetCategoryDefaultCell();
1426 // TODO: Replace with resize() call
1427 unsigned int cellCountMax
= column
+1;
1429 for ( unsigned int i
=m_cells
.size(); i
<cellCountMax
; i
++ )
1430 m_cells
.push_back(defaultCell
);
1434 void wxPGProperty
::SetCell( int column
,
1435 const wxPGCell
& cell
)
1437 EnsureCells(column
);
1439 m_cells
[column
] = cell
;
1442 void wxPGProperty
::AdaptiveSetCell( unsigned int firstCol
,
1443 unsigned int lastCol
,
1444 const wxPGCell
& cell
,
1445 const wxPGCell
& srcData
,
1446 wxPGCellData
* unmodCellData
,
1447 FlagType ignoreWithFlags
,
1451 // Sets cell in memory optimizing fashion. That is, if
1452 // current cell data matches unmodCellData, we will
1453 // simply get reference to data from cell. Otherwise,
1454 // cell information from srcData is merged into current.
1457 if ( !(m_flags
& ignoreWithFlags
) && !IsRoot() )
1459 EnsureCells(lastCol
);
1461 for ( unsigned int col
=firstCol
; col
<=lastCol
; col
++ )
1463 if ( m_cells
[col
].GetData() == unmodCellData
)
1465 // Data matches... use cell directly
1466 m_cells
[col
] = cell
;
1470 // Data did not match... merge valid information
1471 m_cells
[col
].MergeFrom(srcData
);
1478 for ( unsigned int i
=0; i
<GetChildCount(); i
++ )
1479 Item(i
)->AdaptiveSetCell( firstCol
,
1489 const wxPGCell
& wxPGProperty
::GetCell( unsigned int column
) const
1491 if ( m_cells
.size() > column
)
1492 return m_cells
[column
];
1494 wxPropertyGrid
* pg
= GetGrid();
1497 return pg
->GetCategoryDefaultCell();
1499 return pg
->GetPropertyDefaultCell();
1502 wxPGCell
& wxPGProperty
::GetCell( unsigned int column
)
1504 EnsureCells(column
);
1505 return m_cells
[column
];
1508 void wxPGProperty
::SetBackgroundColour( const wxColour
& colour
,
1511 wxPGProperty
* firstProp
= this;
1514 // If category is tried to set recursively, skip it and only
1515 // affect the children.
1518 while ( firstProp
->IsCategory() )
1520 if ( !firstProp
->GetChildCount() )
1522 firstProp
= firstProp
->Item(0);
1526 wxPGCell
& firstCell
= firstProp
->GetCell(0);
1527 wxPGCellData
* firstCellData
= firstCell
.GetData();
1529 wxPGCell
newCell(firstCell
);
1530 newCell
.SetBgCol(colour
);
1532 srcCell
.SetBgCol(colour
);
1535 GetParentState()->GetColumnCount()-1,
1539 recursively ? wxPG_PROP_CATEGORY
: 0,
1543 void wxPGProperty
::SetTextColour( const wxColour
& colour
,
1546 wxPGProperty
* firstProp
= this;
1549 // If category is tried to set recursively, skip it and only
1550 // affect the children.
1553 while ( firstProp
->IsCategory() )
1555 if ( !firstProp
->GetChildCount() )
1557 firstProp
= firstProp
->Item(0);
1561 wxPGCell
& firstCell
= firstProp
->GetCell(0);
1562 wxPGCellData
* firstCellData
= firstCell
.GetData();
1564 wxPGCell
newCell(firstCell
);
1565 newCell
.SetFgCol(colour
);
1567 srcCell
.SetFgCol(colour
);
1570 GetParentState()->GetColumnCount()-1,
1574 recursively ? wxPG_PROP_CATEGORY
: 0,
1578 wxPGEditorDialogAdapter
* wxPGProperty
::GetEditorDialog() const
1583 bool wxPGProperty
::DoSetAttribute( const wxString
& WXUNUSED(name
), wxVariant
& WXUNUSED(value
) )
1588 void wxPGProperty
::SetAttribute( const wxString
& name
, wxVariant value
)
1590 if ( DoSetAttribute( name
, value
) )
1592 // Support working without grid, when possible
1593 if ( wxPGGlobalVars
->HasExtraStyle( wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES
) )
1597 m_attributes
.Set( name
, value
);
1600 void wxPGProperty
::SetAttributes( const wxPGAttributeStorage
& attributes
)
1602 wxPGAttributeStorage
::const_iterator it
= attributes
.StartIteration();
1605 while ( attributes
.GetNext(it
, variant
) )
1606 SetAttribute( variant
.GetName(), variant
);
1609 wxVariant wxPGProperty
::DoGetAttribute( const wxString
& WXUNUSED(name
) ) const
1615 wxVariant wxPGProperty
::GetAttribute( const wxString
& name
) const
1617 return m_attributes
.FindValue(name
);
1620 wxString wxPGProperty
::GetAttribute( const wxString
& name
, const wxString
& defVal
) const
1622 wxVariant variant
= m_attributes
.FindValue(name
);
1624 if ( !variant
.IsNull() )
1625 return variant
.GetString();
1630 long wxPGProperty
::GetAttributeAsLong( const wxString
& name
, long defVal
) const
1632 wxVariant variant
= m_attributes
.FindValue(name
);
1634 return wxPGVariantToInt(variant
, defVal
);
1637 double wxPGProperty
::GetAttributeAsDouble( const wxString
& name
, double defVal
) const
1640 wxVariant variant
= m_attributes
.FindValue(name
);
1642 if ( wxPGVariantToDouble(variant
, &retVal
) )
1648 wxVariant wxPGProperty
::GetAttributesAsList() const
1650 wxVariantList tempList
;
1651 wxVariant
v( tempList
, wxString
::Format(wxS("@%s@attr"),m_name
.c_str()) );
1653 wxPGAttributeStorage
::const_iterator it
= m_attributes
.StartIteration();
1656 while ( m_attributes
.GetNext(it
, variant
) )
1662 // Slots of utility flags are NULL
1663 const unsigned int gs_propFlagToStringSize
= 14;
1665 static const wxChar
* gs_propFlagToString
[gs_propFlagToStringSize
] = {
1682 wxString wxPGProperty
::GetFlagsAsString( FlagType flagsMask
) const
1685 int relevantFlags
= m_flags
& flagsMask
& wxPG_STRING_STORED_FLAGS
;
1689 for ( i
=0; i
<gs_propFlagToStringSize
; i
++ )
1691 if ( relevantFlags
& a
)
1693 const wxChar
* fs
= gs_propFlagToString
[i
];
1705 void wxPGProperty
::SetFlagsFromString( const wxString
& str
)
1709 WX_PG_TOKENIZER1_BEGIN(str
, wxS('|'))
1711 for ( i
=0; i
<gs_propFlagToStringSize
; i
++ )
1713 const wxChar
* fs
= gs_propFlagToString
[i
];
1714 if ( fs
&& str
== fs
)
1720 WX_PG_TOKENIZER1_END()
1722 m_flags
= (m_flags
& ~wxPG_STRING_STORED_FLAGS
) | flags
;
1725 wxValidator
* wxPGProperty
::DoGetValidator() const
1727 return (wxValidator
*) NULL
;
1730 int wxPGProperty
::InsertChoice( const wxString
& label
, int index
, int value
)
1732 wxPropertyGrid
* pg
= GetGrid();
1733 int sel
= GetChoiceSelection();
1737 if ( index
== wxNOT_FOUND
)
1738 index
= m_choices
.GetCount();
1743 m_choices
.Insert(label
, index
, value
);
1745 if ( sel
!= newSel
)
1746 SetChoiceSelection(newSel
);
1748 if ( this == pg
->GetSelection() )
1749 GetEditorClass()->InsertItem(pg
->GetEditorControl(),label
,index
);
1755 void wxPGProperty
::DeleteChoice( int index
)
1757 wxPropertyGrid
* pg
= GetGrid();
1759 int sel
= GetChoiceSelection();
1762 // Adjust current value
1765 SetValueToUnspecified();
1768 else if ( index
< sel
)
1773 m_choices
.RemoveAt(index
);
1775 if ( sel
!= newSel
)
1776 SetChoiceSelection(newSel
);
1778 if ( this == pg
->GetSelection() )
1779 GetEditorClass()->DeleteItem(pg
->GetEditorControl(), index
);
1782 int wxPGProperty
::GetChoiceSelection() const
1784 wxVariant value
= GetValue();
1785 wxString valueType
= value
.GetType();
1786 int index
= wxNOT_FOUND
;
1788 if ( IsValueUnspecified() || !m_choices
.GetCount() )
1791 if ( valueType
== wxPG_VARIANT_TYPE_LONG
)
1793 index
= value
.GetLong();
1795 else if ( valueType
== wxPG_VARIANT_TYPE_STRING
)
1797 index
= m_choices
.Index(value
.GetString());
1799 else if ( valueType
== wxPG_VARIANT_TYPE_BOOL
)
1801 index
= value
.GetBool()?
1 : 0;
1807 void wxPGProperty
::SetChoiceSelection( int newValue
)
1809 // Changes value of a property with choices, but only
1810 // works if the value type is long or string.
1811 wxString valueType
= GetValue().GetType();
1813 wxCHECK_RET( m_choices
.IsOk(), wxT("invalid choiceinfo") );
1815 if ( valueType
== wxPG_VARIANT_TYPE_STRING
)
1817 SetValue( m_choices
.GetLabel(newValue
) );
1819 else // if ( valueType == wxPG_VARIANT_TYPE_LONG )
1821 SetValue( (long) newValue
);
1825 bool wxPGProperty
::SetChoices( wxPGChoices
& choices
)
1827 m_choices
.Assign(choices
);
1830 // This may be needed to trigger some initialization
1831 // (but don't do it if property is somewhat uninitialized)
1832 wxVariant defVal
= GetDefaultValue();
1833 if ( defVal
.IsNull() )
1843 const wxPGEditor
* wxPGProperty
::GetEditorClass() const
1845 const wxPGEditor
* editor
;
1847 if ( !m_customEditor
)
1849 editor
= DoGetEditorClass();
1852 editor
= m_customEditor
;
1855 // Maybe override editor if common value specified
1856 if ( GetDisplayedCommonValueCount() )
1858 // TextCtrlAndButton -> ComboBoxAndButton
1859 if ( editor
->IsKindOf(CLASSINFO(wxPGTextCtrlAndButtonEditor
)) )
1860 editor
= wxPGEditor_ChoiceAndButton
;
1862 // TextCtrl -> ComboBox
1863 else if ( editor
->IsKindOf(CLASSINFO(wxPGTextCtrlEditor
)) )
1864 editor
= wxPGEditor_ComboBox
;
1870 bool wxPGProperty
::HasVisibleChildren() const
1874 for ( i
=0; i
<GetChildCount(); i
++ )
1876 wxPGProperty
* child
= Item(i
);
1878 if ( !child
->HasFlag(wxPG_PROP_HIDDEN
) )
1885 bool wxPGProperty
::RecreateEditor()
1887 wxPropertyGrid
* pg
= GetGrid();
1890 wxPGProperty
* selected
= pg
->GetSelection();
1891 if ( this == selected
)
1893 pg
->DoSelectProperty(this, wxPG_SEL_FORCE
);
1900 void wxPGProperty
::SetValueImage( wxBitmap
& bmp
)
1902 delete m_valueBitmap
;
1904 if ( &bmp
&& bmp
.Ok() )
1907 wxSize maxSz
= GetGrid()->GetImageSize();
1908 wxSize
imSz(bmp
.GetWidth(),bmp
.GetHeight());
1910 if ( imSz
.x
!= maxSz
.x
|| imSz
.y
!= maxSz
.y
)
1912 // Create a memory DC
1913 wxBitmap
* bmpNew
= new wxBitmap(maxSz
.x
,maxSz
.y
,bmp
.GetDepth());
1916 dc
.SelectObject(*bmpNew
);
1919 // FIXME: This is ugly - use image or wait for scaling patch.
1920 double scaleX
= (double)maxSz
.x
/ (double)imSz
.x
;
1921 double scaleY
= (double)maxSz
.y
/ (double)imSz
.y
;
1923 dc
.SetUserScale(scaleX
,scaleY
);
1925 dc
.DrawBitmap( bmp
, 0, 0 );
1927 m_valueBitmap
= bmpNew
;
1931 m_valueBitmap
= new wxBitmap(bmp
);
1934 m_flags
|= wxPG_PROP_CUSTOMIMAGE
;
1938 m_valueBitmap
= NULL
;
1939 m_flags
&= ~(wxPG_PROP_CUSTOMIMAGE
);
1944 wxPGProperty
* wxPGProperty
::GetMainParent() const
1946 const wxPGProperty
* curChild
= this;
1947 const wxPGProperty
* curParent
= m_parent
;
1949 while ( curParent
&& !curParent
->IsCategory() )
1951 curChild
= curParent
;
1952 curParent
= curParent
->m_parent
;
1955 return (wxPGProperty
*) curChild
;
1959 const wxPGProperty
* wxPGProperty
::GetLastVisibleSubItem() const
1962 // Returns last visible sub-item, recursively.
1963 if ( !IsExpanded() || !GetChildCount() )
1966 return Last()->GetLastVisibleSubItem();
1970 bool wxPGProperty
::IsVisible() const
1972 const wxPGProperty
* parent
;
1974 if ( HasFlag(wxPG_PROP_HIDDEN
) )
1977 for ( parent
= GetParent(); parent
!= NULL
; parent
= parent
->GetParent() )
1979 if ( !parent
->IsExpanded() || parent
->HasFlag(wxPG_PROP_HIDDEN
) )
1986 wxPropertyGrid
* wxPGProperty
::GetGridIfDisplayed() const
1988 wxPropertyGridPageState
* state
= GetParentState();
1989 wxPropertyGrid
* propGrid
= state
->GetGrid();
1990 if ( state
== propGrid
->GetState() )
1996 int wxPGProperty
::GetY2( int lh
) const
1998 const wxPGProperty
* parent
;
1999 const wxPGProperty
* child
= this;
2003 for ( parent
= GetParent(); parent
!= NULL
; parent
= child
->GetParent() )
2005 if ( !parent
->IsExpanded() )
2007 y
+= parent
->GetChildrenHeight(lh
, child
->GetIndexInParent());
2012 y
-= lh
; // need to reduce one level
2018 int wxPGProperty
::GetY() const
2020 return GetY2(GetGrid()->GetRowHeight());
2023 // This is used by Insert etc.
2024 void wxPGProperty
::AddChild2( wxPGProperty
* prop
, int index
, bool correct_mode
)
2026 if ( index
< 0 || (size_t)index
>= m_children
.size() )
2028 if ( correct_mode
) prop
->m_arrIndex
= m_children
.size();
2029 m_children
.push_back( prop
);
2033 m_children
.insert( m_children
.begin()+index
, prop
);
2034 if ( correct_mode
) FixIndicesOfChildren( index
);
2037 prop
->m_parent
= this;
2040 // This is used by properties that have fixed sub-properties
2041 void wxPGProperty
::AddChild( wxPGProperty
* prop
)
2043 wxASSERT_MSG( prop
->GetBaseName().length(),
2044 "Property's children must have unique, non-empty names within their scope" );
2046 prop
->m_arrIndex
= m_children
.size();
2047 m_children
.push_back( prop
);
2049 int custImgHeight
= prop
->OnMeasureImage().y
;
2050 if ( custImgHeight
< 0 /*|| custImgHeight > 1*/ )
2051 prop
->m_flags
|= wxPG_PROP_CUSTOMIMAGE
;
2053 prop
->m_parent
= this;
2056 void wxPGProperty
::RemoveChild( wxPGProperty
* p
)
2058 wxArrayPGProperty
::iterator it
;
2059 wxArrayPGProperty
& children
= m_children
;
2061 for ( it
=children
.begin(); it
!= children
.end(); it
++ )
2065 m_children
.erase(it
);
2071 void wxPGProperty
::AdaptListToValue( wxVariant
& list
, wxVariant
* value
) const
2073 wxASSERT( GetChildCount() );
2074 wxASSERT( !IsCategory() );
2076 *value
= GetValue();
2078 if ( !list
.GetCount() )
2081 wxASSERT( GetChildCount() >= (unsigned int)list
.GetCount() );
2083 bool allChildrenSpecified
;
2085 // Don't fully update aggregate properties unless all children have
2087 if ( HasFlag(wxPG_PROP_AGGREGATE
) )
2088 allChildrenSpecified
= AreAllChildrenSpecified(&list
);
2090 allChildrenSpecified
= true;
2092 wxVariant childValue
= list
[0];
2096 //wxLogDebug(wxT(">> %s.AdaptListToValue()"),GetBaseName().c_str());
2098 for ( i
=0; i
<GetChildCount(); i
++ )
2100 const wxPGProperty
* child
= Item(i
);
2102 if ( childValue
.GetName() == child
->GetBaseName() )
2104 //wxLogDebug(wxT(" %s(n=%i), %s"),childValue.GetName().c_str(),n,childValue.GetType().c_str());
2106 if ( childValue
.GetType() == wxPG_VARIANT_TYPE_LIST
)
2108 wxVariant
cv2(child
->GetValue());
2109 child
->AdaptListToValue(childValue
, &cv2
);
2113 if ( allChildrenSpecified
)
2114 ChildChanged(*value
, i
, childValue
);
2116 if ( n
== (unsigned int)list
.GetCount() )
2118 childValue
= list
[n
];
2124 void wxPGProperty
::FixIndicesOfChildren( unsigned int starthere
)
2127 for ( i
=starthere
;i
<GetChildCount();i
++)
2128 Item(i
)->m_arrIndex
= i
;
2132 // Returns (direct) child property with given name (or NULL if not found)
2133 wxPGProperty
* wxPGProperty
::GetPropertyByName( const wxString
& name
) const
2137 for ( i
=0; i
<GetChildCount(); i
++ )
2139 wxPGProperty
* p
= Item(i
);
2140 if ( p
->m_name
== name
)
2144 // Does it have point, then?
2145 int pos
= name
.Find(wxS('.'));
2147 return (wxPGProperty
*) NULL
;
2149 wxPGProperty
* p
= GetPropertyByName(name
. substr(0,pos
));
2151 if ( !p
|| !p
->GetChildCount() )
2154 return p
->GetPropertyByName(name
.substr(pos
+1,name
.length()-pos
-1));
2157 wxPGProperty
* wxPGProperty
::GetPropertyByNameWH( const wxString
& name
, unsigned int hintIndex
) const
2159 unsigned int i
= hintIndex
;
2161 if ( i
>= GetChildCount() )
2164 unsigned int lastIndex
= i
- 1;
2166 if ( lastIndex
>= GetChildCount() )
2167 lastIndex
= GetChildCount() - 1;
2171 wxPGProperty
* p
= Item(i
);
2172 if ( p
->m_name
== name
)
2175 if ( i
== lastIndex
)
2179 if ( i
== GetChildCount() )
2186 int wxPGProperty
::GetChildrenHeight( int lh
, int iMax_
) const
2188 // Returns height of children, recursively, and
2189 // by taking expanded/collapsed status into account.
2191 // iMax is used when finding property y-positions.
2197 iMax_
= GetChildCount();
2199 unsigned int iMax
= iMax_
;
2201 wxASSERT( iMax
<= GetChildCount() );
2203 if ( !IsExpanded() && GetParent() )
2208 wxPGProperty
* pwc
= (wxPGProperty
*) Item(i
);
2210 if ( !pwc
->HasFlag(wxPG_PROP_HIDDEN
) )
2212 if ( !pwc
->IsExpanded() ||
2213 pwc
->GetChildCount() == 0 )
2216 h
+= pwc
->GetChildrenHeight(lh
) + lh
;
2225 wxPGProperty
* wxPGProperty
::GetItemAtY( unsigned int y
, unsigned int lh
, unsigned int* nextItemY
) const
2227 wxASSERT( nextItemY
);
2229 // Linear search at the moment
2231 // nextItemY = y of next visible property, final value will be written back.
2232 wxPGProperty
* result
= NULL
;
2233 wxPGProperty
* current
= NULL
;
2234 unsigned int iy
= *nextItemY
;
2236 unsigned int iMax
= GetChildCount();
2240 wxPGProperty
* pwc
= Item(i
);
2242 if ( !pwc
->HasFlag(wxPG_PROP_HIDDEN
) )
2253 if ( pwc
->IsExpanded() &&
2254 pwc
->GetChildCount() > 0 )
2256 result
= (wxPGProperty
*) pwc
->GetItemAtY( y
, lh
, &iy
);
2268 if ( !result
&& y
< iy
)
2275 wxLogDebug(wxT("%s::GetItemAtY(%i) -> %s"),this->GetLabel().c_str(),y,current->GetLabel().c_str());
2277 wxLogDebug(wxT("%s::GetItemAtY(%i) -> NULL"),this->GetLabel().c_str(),y);
2280 return (wxPGProperty
*) result
;
2283 void wxPGProperty
::Empty()
2286 if ( !HasFlag(wxPG_PROP_CHILDREN_ARE_COPIES
) )
2288 for ( i
=0; i
<GetChildCount(); i
++ )
2290 delete m_children
[i
];
2297 void wxPGProperty
::ChildChanged( wxVariant
& WXUNUSED(thisValue
),
2298 int WXUNUSED(childIndex
),
2299 wxVariant
& WXUNUSED(childValue
) ) const
2303 bool wxPGProperty
::AreAllChildrenSpecified( wxVariant
* pendingList
) const
2307 const wxVariantList
* pList
= NULL
;
2308 wxVariantList
::const_iterator node
;
2312 pList
= &pendingList
->GetList();
2313 node
= pList
->begin();
2316 for ( i
=0; i
<GetChildCount(); i
++ )
2318 wxPGProperty
* child
= Item(i
);
2319 const wxVariant
* listValue
= NULL
;
2324 const wxString
& childName
= child
->GetBaseName();
2326 for ( ; node
!= pList
->end(); node
++ )
2328 const wxVariant
& item
= *((const wxVariant
*)*node
);
2329 if ( item
.GetName() == childName
)
2339 value
= child
->GetValue();
2341 if ( value
.IsNull() )
2344 // Check recursively
2345 if ( child
->GetChildCount() )
2347 const wxVariant
* childList
= NULL
;
2349 if ( listValue
&& listValue
->GetType() == wxPG_VARIANT_TYPE_LIST
)
2350 childList
= listValue
;
2352 if ( !child
->AreAllChildrenSpecified((wxVariant
*)childList
) )
2360 wxPGProperty
* wxPGProperty
::UpdateParentValues()
2362 wxPGProperty
* parent
= m_parent
;
2363 if ( parent
&& parent
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) &&
2364 !parent
->IsCategory() && !parent
->IsRoot() )
2367 parent
->DoGenerateComposedValue(s
);
2368 parent
->m_value
= s
;
2369 return parent
->UpdateParentValues();
2374 bool wxPGProperty
::IsTextEditable() const
2376 if ( HasFlag(wxPG_PROP_READONLY
) )
2379 if ( HasFlag(wxPG_PROP_NOEDITOR
) &&
2381 wxString(GetEditorClass()->GetClassInfo()->GetClassName()).EndsWith(wxS("Button")))
2388 // Call after fixed sub-properties added/removed after creation.
2389 // if oldSelInd >= 0 and < new max items, then selection is
2390 // moved to it. Note: oldSelInd -2 indicates that this property
2391 // should be selected.
2392 void wxPGProperty
::SubPropsChanged( int oldSelInd
)
2394 wxPropertyGridPageState
* state
= GetParentState();
2395 wxPropertyGrid
* grid
= state
->GetGrid();
2398 // Re-repare children (recursively)
2399 for ( unsigned int i
=0; i
<GetChildCount(); i
++ )
2401 wxPGProperty
* child
= Item(i
);
2402 child
->InitAfterAdded(state
, grid
);
2405 wxPGProperty
* sel
= (wxPGProperty
*) NULL
;
2406 if ( oldSelInd
>= (int)m_children
.size() )
2407 oldSelInd
= (int)m_children
.size() - 1;
2409 if ( oldSelInd
>= 0 )
2410 sel
= m_children
[oldSelInd
];
2411 else if ( oldSelInd
== -2 )
2415 state
->DoSelectProperty(sel
);
2417 if ( state
== grid
->GetState() )
2419 grid
->GetPanel()->Refresh();
2423 // -----------------------------------------------------------------------
2425 // -----------------------------------------------------------------------
2427 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty
,none
,TextCtrl
)
2428 IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty
, wxPGProperty
)
2431 wxPGRootProperty
::wxPGRootProperty()
2435 m_name
= wxS("<root>");
2442 wxPGRootProperty
::~wxPGRootProperty()
2447 // -----------------------------------------------------------------------
2448 // wxPropertyCategory
2449 // -----------------------------------------------------------------------
2451 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPropertyCategory
,none
,TextCtrl
)
2452 IMPLEMENT_DYNAMIC_CLASS(wxPropertyCategory
, wxPGProperty
)
2454 void wxPropertyCategory
::Init()
2456 // don't set colour - prepareadditem method should do this
2457 SetParentalType(wxPG_PROP_CATEGORY
);
2458 m_capFgColIndex
= 1;
2462 wxPropertyCategory
::wxPropertyCategory()
2469 wxPropertyCategory
::wxPropertyCategory( const wxString
&label
, const wxString
& name
)
2470 : wxPGProperty(label
,name
)
2476 wxPropertyCategory
::~wxPropertyCategory()
2481 wxString wxPropertyCategory
::ValueToString( wxVariant
& WXUNUSED(value
),
2482 int WXUNUSED(argFlags
) ) const
2484 return wxEmptyString
;
2487 int wxPropertyCategory
::GetTextExtent( const wxWindow
* wnd
, const wxFont
& font
) const
2489 if ( m_textExtent
> 0 )
2490 return m_textExtent
;
2492 ((wxWindow
*)wnd
)->GetTextExtent( m_label
, &x
, &y
, 0, 0, &font
);
2496 void wxPropertyCategory
::CalculateTextExtent( wxWindow
* wnd
, const wxFont
& font
)
2499 wnd
->GetTextExtent( m_label
, &x
, &y
, 0, 0, &font
);
2503 // -----------------------------------------------------------------------
2504 // wxPGAttributeStorage
2505 // -----------------------------------------------------------------------
2507 wxPGAttributeStorage
::wxPGAttributeStorage()
2511 wxPGAttributeStorage
::~wxPGAttributeStorage()
2513 wxPGHashMapS2P
::iterator it
;
2515 for ( it
= m_map
.begin(); it
!= m_map
.end(); it
++ )
2517 wxVariantData
* data
= (wxVariantData
*) it
->second
;
2522 void wxPGAttributeStorage
::Set( const wxString
& name
, const wxVariant
& value
)
2524 wxVariantData
* data
= value
.GetData();
2527 wxPGHashMapS2P
::iterator it
= m_map
.find(name
);
2528 if ( it
!= m_map
.end() )
2530 ((wxVariantData
*)it
->second
)->DecRef();
2534 // If Null variant, just remove from set
2548 #endif // wxUSE_PROPGRID