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 rect
.x
+xOffset
+wxPG_XBEFORETEXT
,
99 rect
.y
+((rect
.height
-dc
.GetCharHeight())/2) );
102 void wxPGCellRenderer
::DrawEditorValue( wxDC
& dc
, const wxRect
& rect
,
103 int xOffset
, const wxString
& text
,
104 wxPGProperty
* property
,
105 const wxPGEditor
* editor
) const
107 int yOffset
= ((rect
.height
-dc
.GetCharHeight())/2);
114 rect2
.height
-= yOffset
;
115 editor
->DrawValue( dc
, rect2
, property
, text
);
120 rect
.x
+xOffset
+wxPG_XBEFORETEXT
,
125 void wxPGCellRenderer
::DrawCaptionSelectionRect( wxDC
& dc
, int x
, int y
, int w
, int h
) const
127 wxRect
focusRect(x
,y
+((h
-dc
.GetCharHeight())/2),w
,h
);
128 wxPGDrawFocusRect(dc
,focusRect
);
131 int wxPGCellRenderer
::PreDrawCell( wxDC
& dc
, const wxRect
& rect
, const wxPGCell
& cell
, int flags
) const
135 // If possible, use cell colours
136 if ( !(flags
& DontUseCellBgCol
) )
138 const wxColour
& bgCol
= cell
.GetBgCol();
143 if ( !(flags
& DontUseCellFgCol
) )
145 dc
.SetTextForeground(cell
.GetFgCol());
148 // Draw Background, but only if not rendering in control
149 // (as control already has rendered correct background).
150 if ( !(flags
& (Control
|ChoicePopup
)) )
151 dc
.DrawRectangle(rect
);
153 // Use cell font, if provided
154 const wxFont
& font
= cell
.GetFont();
158 const wxBitmap
& bmp
= cell
.GetBitmap();
160 // Do not draw oversized bitmap outside choice popup
161 ((flags
& ChoicePopup
) || bmp
.GetHeight() < rect
.height
)
165 rect
.x
+ wxPG_CONTROL_MARGIN
+ wxCC_CUSTOM_IMAGE_MARGIN1
,
166 rect
.y
+ wxPG_CUSTOM_IMAGE_SPACINGY
,
168 imageWidth
= bmp
.GetWidth();
174 void wxPGCellRenderer
::PostDrawCell( wxDC
& dc
,
175 const wxPropertyGrid
* propGrid
,
176 const wxPGCell
& cell
,
177 int WXUNUSED(flags
) ) const
180 const wxFont
& font
= cell
.GetFont();
182 dc
.SetFont(propGrid
->GetFont());
185 // -----------------------------------------------------------------------
186 // wxPGDefaultRenderer
187 // -----------------------------------------------------------------------
189 void wxPGDefaultRenderer
::Render( wxDC
& dc
, const wxRect
& rect
,
190 const wxPropertyGrid
* propertyGrid
, wxPGProperty
* property
,
191 int column
, int item
, int flags
) const
193 bool isUnspecified
= property
->IsValueUnspecified();
195 if ( column
== 1 && item
== -1 )
197 int cmnVal
= property
->GetCommonValue();
201 if ( !isUnspecified
)
202 DrawText( dc
, rect
, 0, propertyGrid
->GetCommonValueLabel(cmnVal
) );
207 const wxPGEditor
* editor
= NULL
;
208 const wxPGCell
* cell
= NULL
;
212 int preDrawFlags
= flags
;
214 property
->GetDisplayInfo(column
, item
, flags
, &text
, &cell
);
216 imageWidth
= PreDrawCell( dc
, rect
, *cell
, preDrawFlags
);
220 editor
= property
->GetColumnEditor(column
);
222 if ( !isUnspecified
)
224 // Regular property value
226 wxSize imageSize
= propertyGrid
->GetImageSize(property
, item
);
228 wxPGPaintData paintdata
;
229 paintdata
.m_parent
= propertyGrid
;
230 paintdata
.m_choiceItem
= item
;
232 if ( imageSize
.x
> 0 )
234 wxRect
imageRect(rect
.x
+ wxPG_CONTROL_MARGIN
+ wxCC_CUSTOM_IMAGE_MARGIN1
,
235 rect
.y
+wxPG_CUSTOM_IMAGE_SPACINGY
,
236 wxPG_CUSTOM_IMAGE_WIDTH
,
237 rect
.height
-(wxPG_CUSTOM_IMAGE_SPACINGY
*2));
239 dc
.SetPen( wxPen(propertyGrid
->GetCellTextColour(), 1, wxSOLID
) );
241 paintdata
.m_drawnWidth
= imageSize
.x
;
242 paintdata
.m_drawnHeight
= imageSize
.y
;
244 property
->OnCustomPaint( dc
, imageRect
, paintdata
);
246 imageWidth
= paintdata
.m_drawnWidth
;
249 text
= property
->GetValueAsString();
252 if ( propertyGrid
->GetColumnCount() <= 2 )
254 wxString unitsString
= property
->GetAttribute(wxPGGlobalVars
->m_strUnits
, wxEmptyString
);
255 if ( unitsString
.length() )
256 text
= wxString
::Format(wxS("%s %s"), text
.c_str(), unitsString
.c_str() );
260 if ( text
.length() == 0 )
262 // Try to show inline help if no text
263 wxVariant vInlineHelp
= property
->GetAttribute(wxPGGlobalVars
->m_strInlineHelp
);
264 if ( !vInlineHelp
.IsNull() )
266 text
= vInlineHelp
.GetString();
267 dc
.SetTextForeground(propertyGrid
->GetCellDisabledTextColour());
269 // Must make the editor NULL to override it's own rendering
276 int imageOffset
= property
->GetImageOffset(imageWidth
);
278 DrawEditorValue( dc
, rect
, imageOffset
, text
, property
, editor
);
280 // active caption gets nice dotted rectangle
281 if ( property
->IsCategory() /*&& column == 0*/ )
283 if ( flags
& Selected
)
285 if ( imageOffset
> 0 )
287 imageOffset
-= DEFAULT_IMAGE_OFFSET_INCREMENT
;
288 imageOffset
+= wxCC_CUSTOM_IMAGE_MARGIN2
+ 4;
291 DrawCaptionSelectionRect( dc
,
292 rect
.x
+wxPG_XBEFORETEXT
-wxPG_CAPRECTXMARGIN
+imageOffset
,
293 rect
.y
-wxPG_CAPRECTYMARGIN
+1,
294 ((wxPropertyCategory
*)property
)->GetTextExtent(propertyGrid
,
295 propertyGrid
->GetCaptionFont())
296 +(wxPG_CAPRECTXMARGIN
*2),
297 propertyGrid
->GetFontHeight()+(wxPG_CAPRECTYMARGIN
*2) );
301 PostDrawCell(dc
, propertyGrid
, *cell
, preDrawFlags
);
304 wxSize wxPGDefaultRenderer
::GetImageSize( const wxPGProperty
* property
,
308 if ( property
&& column
== 1 )
312 wxBitmap
* bmp
= property
->GetValueImage();
314 if ( bmp
&& bmp
->Ok() )
315 return wxSize(bmp
->GetWidth(),bmp
->GetHeight());
321 // -----------------------------------------------------------------------
323 // -----------------------------------------------------------------------
325 wxPGCellData
::wxPGCellData()
328 m_hasValidText
= false;
331 // -----------------------------------------------------------------------
333 // -----------------------------------------------------------------------
340 wxPGCell
::wxPGCell( const wxString
& text
,
341 const wxBitmap
& bitmap
,
342 const wxColour
& fgCol
,
343 const wxColour
& bgCol
)
346 wxPGCellData
* data
= new wxPGCellData();
349 data
->m_bitmap
= bitmap
;
350 data
->m_fgCol
= fgCol
;
351 data
->m_bgCol
= bgCol
;
352 data
->m_hasValidText
= true;
355 wxObjectRefData
*wxPGCell
::CloneRefData( const wxObjectRefData
*data
) const
357 wxPGCellData
* c
= new wxPGCellData();
358 const wxPGCellData
* o
= (const wxPGCellData
*) data
;
359 c
->m_text
= o
->m_text
;
360 c
->m_bitmap
= o
->m_bitmap
;
361 c
->m_fgCol
= o
->m_fgCol
;
362 c
->m_bgCol
= o
->m_bgCol
;
363 c
->m_hasValidText
= o
->m_hasValidText
;
367 void wxPGCell
::SetText( const wxString
& text
)
371 GetData()->SetText(text
);
374 void wxPGCell
::SetBitmap( const wxBitmap
& bitmap
)
378 GetData()->SetBitmap(bitmap
);
381 void wxPGCell
::SetFgCol( const wxColour
& col
)
385 GetData()->SetFgCol(col
);
388 void wxPGCell
::SetFont( const wxFont
& font
)
392 GetData()->SetFont(font
);
395 void wxPGCell
::SetBgCol( const wxColour
& col
)
399 GetData()->SetBgCol(col
);
402 void wxPGCell
::MergeFrom( const wxPGCell
& srcCell
)
406 wxPGCellData
* data
= GetData();
408 if ( srcCell
.HasText() )
409 data
->SetText(srcCell
.GetText());
411 if ( srcCell
.GetFgCol().IsOk() )
412 data
->SetFgCol(srcCell
.GetFgCol());
414 if ( srcCell
.GetBgCol().IsOk() )
415 data
->SetBgCol(srcCell
.GetBgCol());
417 if ( srcCell
.GetBitmap().IsOk() )
418 data
->SetBitmap(srcCell
.GetBitmap());
421 void wxPGCell
::SetEmptyData()
427 // -----------------------------------------------------------------------
429 // -----------------------------------------------------------------------
431 IMPLEMENT_ABSTRACT_CLASS(wxPGProperty
, wxObject
)
433 wxString
* wxPGProperty
::sm_wxPG_LABEL
= NULL
;
435 void wxPGProperty
::Init()
441 m_parentState
= NULL
;
444 m_clientObject
= NULL
;
446 m_customEditor
= NULL
;
450 m_valueBitmap
= NULL
;
452 m_maxLen
= 0; // infinite maximum length
454 m_flags
= wxPG_PROP_PROPERTY
;
462 void wxPGProperty
::Init( const wxString
& label
, const wxString
& name
)
464 // We really need to check if &label and &name are NULL pointers
465 // (this can if we are called before property grid has been initalized)
467 if ( (&label
) != NULL
&& label
!= wxPG_LABEL
)
470 if ( (&name
) != NULL
&& name
!= wxPG_LABEL
)
473 DoSetName( m_label
);
478 void wxPGProperty
::InitAfterAdded( wxPropertyGridPageState
* pageState
,
479 wxPropertyGrid
* propgrid
)
482 // Called after property has been added to grid or page
483 // (so propgrid can be NULL, too).
485 wxPGProperty
* parent
= m_parent
;
486 bool parentIsRoot
= parent
->IsKindOf(CLASSINFO(wxPGRootProperty
));
488 m_parentState
= pageState
;
490 #if wxPG_COMPATIBILITY_1_4
491 // Make sure deprecated virtual functions are not implemented
492 wxString s
= GetValueAsString( 0xFFFF );
493 wxASSERT_MSG( s
== g_invalidStringContent
,
494 "Implement ValueToString() instead of GetValueAsString()" );
497 if ( !parentIsRoot
&& !parent
->IsCategory() )
499 m_cells
= parent
->m_cells
;
502 // If in hideable adding mode, or if assigned parent is hideable, then
503 // make this one hideable.
505 ( !parentIsRoot
&& parent
->HasFlag(wxPG_PROP_HIDDEN
) ) ||
506 ( propgrid
&& (propgrid
->HasInternalFlag(wxPG_FL_ADDING_HIDEABLES
)) )
508 SetFlag( wxPG_PROP_HIDDEN
);
510 // Set custom image flag.
511 int custImgHeight
= OnMeasureImage().y
;
512 if ( custImgHeight
< 0 )
514 SetFlag(wxPG_PROP_CUSTOMIMAGE
);
517 if ( propgrid
&& (propgrid
->HasFlag(wxPG_LIMITED_EDITING
)) )
518 SetFlag(wxPG_PROP_NOEDITOR
);
520 // Make sure parent has some parental flags
521 if ( !parent
->HasFlag(wxPG_PROP_PARENTAL_FLAGS
) )
522 parent
->SetParentalType(wxPG_PROP_MISC_PARENT
);
526 // This is not a category.
530 unsigned char depth
= 1;
533 depth
= parent
->m_depth
;
534 if ( !parent
->IsCategory() )
538 unsigned char greyDepth
= depth
;
542 wxPropertyCategory
* pc
;
544 if ( parent
->IsCategory() )
545 pc
= (wxPropertyCategory
* ) parent
;
547 // This conditional compile is necessary to
548 // bypass some compiler bug.
549 pc
= pageState
->GetPropertyCategory(parent
);
552 greyDepth
= pc
->GetDepth();
554 greyDepth
= parent
->m_depthBgCol
;
557 m_depthBgCol
= greyDepth
;
561 // This is a category.
564 unsigned char depth
= 1;
567 depth
= parent
->m_depth
+ 1;
570 m_depthBgCol
= depth
;
574 // Has initial children
575 if ( GetChildCount() )
577 // Check parental flags
578 wxASSERT_MSG( ((m_flags
& wxPG_PROP_PARENTAL_FLAGS
) ==
579 wxPG_PROP_AGGREGATE
) ||
580 ((m_flags
& wxPG_PROP_PARENTAL_FLAGS
) ==
581 wxPG_PROP_MISC_PARENT
),
582 "wxPGProperty parental flags set incorrectly at "
585 if ( HasFlag(wxPG_PROP_AGGREGATE
) )
587 // Properties with private children are not expanded by default.
590 else if ( propgrid
&& propgrid
->HasFlag(wxPG_HIDE_MARGIN
) )
592 // ...unless it cannot be expanded by user and therefore must
593 // remain visible at all times
598 // Prepare children recursively
599 for ( unsigned int i
=0; i
<GetChildCount(); i
++ )
601 wxPGProperty
* child
= Item(i
);
602 child
->InitAfterAdded(pageState
, pageState
->GetGrid());
605 if ( propgrid
&& (propgrid
->GetExtraStyle() & wxPG_EX_AUTO_UNSPECIFIED_VALUES
) )
606 SetFlagRecursively(wxPG_PROP_AUTO_UNSPECIFIED
, true);
610 wxPGProperty
::wxPGProperty()
617 wxPGProperty
::wxPGProperty( const wxString
& label
, const wxString
& name
)
624 wxPGProperty
::~wxPGProperty()
626 delete m_clientObject
;
628 Empty(); // this deletes items
630 delete m_valueBitmap
;
635 // This makes it easier for us to detect dangling pointers
640 bool wxPGProperty
::IsSomeParent( wxPGProperty
* candidate
) const
642 wxPGProperty
* parent
= m_parent
;
645 if ( parent
== candidate
)
647 parent
= parent
->m_parent
;
652 void wxPGProperty
::SetName( const wxString
& newName
)
654 wxPropertyGrid
* pg
= GetGrid();
657 pg
->SetPropertyName(this, newName
);
662 wxString wxPGProperty
::GetName() const
664 wxPGProperty
* parent
= GetParent();
666 if ( !m_name
.length() || !parent
|| parent
->IsCategory() || parent
->IsRoot() )
669 return m_parent
->GetName() + wxS(".") + m_name
;
672 wxPropertyGrid
* wxPGProperty
::GetGrid() const
674 if ( !m_parentState
)
676 return m_parentState
->GetGrid();
679 int wxPGProperty
::Index( const wxPGProperty
* p
) const
681 for ( unsigned int i
= 0; i
<m_children
.size(); i
++ )
683 if ( p
== m_children
[i
] )
689 bool wxPGProperty
::ValidateValue( wxVariant
& WXUNUSED(value
), wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
694 void wxPGProperty
::OnSetValue()
698 void wxPGProperty
::RefreshChildren ()
702 void wxPGProperty
::OnValidationFailure( wxVariant
& WXUNUSED(pendingValue
) )
706 void wxPGProperty
::GetDisplayInfo( unsigned int column
,
710 const wxPGCell
** pCell
)
712 const wxPGCell
* cell
= NULL
;
714 if ( !(flags
& wxPGCellRenderer
::ChoicePopup
) )
716 // Not painting list of choice popups, so get text from property
717 if ( column
!= 1 || !IsValueUnspecified() || IsCategory() )
719 cell
= &GetCell(column
);
723 // Use special unspecified value cell
724 cell
= &GetGrid()->GetUnspecifiedValueAppearance();
727 if ( cell
->HasText() )
729 *pString
= cell
->GetText();
734 *pString
= GetLabel();
735 else if ( column
== 1 )
736 *pString
= GetDisplayedString();
737 else if ( column
== 2 )
738 *pString
= GetAttribute(wxPGGlobalVars
->m_strUnits
, wxEmptyString
);
743 wxASSERT( column
== 1 );
745 if ( choiceIndex
!= wxNOT_FOUND
)
747 const wxPGChoiceEntry
& entry
= m_choices
[choiceIndex
];
748 if ( entry
.GetBitmap().IsOk() ||
749 entry
.GetFgCol().IsOk() ||
750 entry
.GetBgCol().IsOk() )
752 *pString
= m_choices
.GetLabel(choiceIndex
);
757 cell
= &GetCell(column
);
759 wxASSERT_MSG( cell
->GetData(),
760 wxString
::Format("Invalid cell for property %s",
761 GetName().c_str()) );
767 wxString wxPGProperty::GetColumnText( unsigned int col, int choiceIndex ) const
770 if ( col != 1 || choiceIndex == wxNOT_FOUND )
772 const wxPGCell& cell = GetCell(col);
773 if ( cell->HasText() )
775 return cell->GetText();
782 return GetDisplayedString();
784 return GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
790 return m_choices.GetLabel(choiceIndex);
793 return wxEmptyString;
797 void wxPGProperty
::DoGenerateComposedValue( wxString
& text
,
799 const wxVariantList
* valueOverrides
,
800 wxPGHashMapS2S
* childResults
) const
803 int iMax
= m_children
.size();
809 if ( iMax
> PWC_CHILD_SUMMARY_LIMIT
&&
810 !(argFlags
& wxPG_FULL_VALUE
) )
811 iMax
= PWC_CHILD_SUMMARY_LIMIT
;
813 int iMaxMinusOne
= iMax
-1;
815 if ( !IsTextEditable() )
816 argFlags
|= wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
;
818 wxPGProperty
* curChild
= m_children
[0];
820 bool overridesLeft
= false;
821 wxVariant overrideValue
;
822 wxVariantList
::const_iterator node
;
824 if ( valueOverrides
)
826 node
= valueOverrides
->begin();
827 if ( node
!= valueOverrides
->end() )
829 overrideValue
= *node
;
830 overridesLeft
= true;
834 for ( i
= 0; i
< iMax
; i
++ )
836 wxVariant childValue
;
838 wxString childLabel
= curChild
->GetLabel();
840 // Check for value override
841 if ( overridesLeft
&& overrideValue
.GetName() == childLabel
)
843 if ( !overrideValue
.IsNull() )
844 childValue
= overrideValue
;
846 childValue
= curChild
->GetValue();
848 if ( node
!= valueOverrides
->end() )
849 overrideValue
= *node
;
851 overridesLeft
= false;
855 childValue
= curChild
->GetValue();
859 if ( !childValue
.IsNull() )
861 if ( overridesLeft
&&
862 curChild
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) &&
863 childValue
.GetType() == wxPG_VARIANT_TYPE_LIST
)
865 wxVariantList
& childList
= childValue
.GetList();
866 DoGenerateComposedValue(s
, argFlags
|wxPG_COMPOSITE_FRAGMENT
,
867 &childList
, childResults
);
871 s
= curChild
->ValueToString(childValue
,
872 argFlags
|wxPG_COMPOSITE_FRAGMENT
);
876 if ( childResults
&& curChild
->GetChildCount() )
877 (*childResults
)[curChild
->GetName()] = s
;
880 if ( (argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
) && !s
.length() )
883 if ( !curChild
->GetChildCount() || skip
)
886 text
+= wxS("[") + s
+ wxS("]");
888 if ( i
< iMaxMinusOne
)
890 if ( text
.length() > PWC_CHILD_SUMMARY_CHAR_LIMIT
&&
891 !(argFlags
& wxPG_EDITABLE_VALUE
) &&
892 !(argFlags
& wxPG_FULL_VALUE
) )
897 if ( !curChild
->GetChildCount() )
903 curChild
= m_children
[i
+1];
907 if ( (unsigned int)i
< m_children
.size() )
909 if ( !text
.EndsWith(wxS("; ")) )
910 text
+= wxS("; ...");
916 wxString wxPGProperty
::ValueToString( wxVariant
& WXUNUSED(value
),
919 wxCHECK_MSG( GetChildCount() > 0,
921 "If user property does not have any children, it must "
922 "override GetValueAsString" );
924 // FIXME: Currently code below only works if value is actually m_value
925 wxASSERT_MSG( argFlags
& wxPG_VALUE_IS_CURRENT
,
926 "Sorry, currently default wxPGProperty::ValueToString() "
927 "implementation only works if value is m_value." );
930 DoGenerateComposedValue(text
, argFlags
);
934 wxString wxPGProperty
::GetValueAsString( int argFlags
) const
936 #if wxPG_COMPATIBILITY_1_4
937 // This is backwards compatibility test
938 // That is, to make sure this function is not overridden
939 // (instead, ValueToString() should be).
940 if ( argFlags
== 0xFFFF )
942 // Do not override! (for backwards compliancy)
943 return g_invalidStringContent
;
947 wxPropertyGrid
* pg
= GetGrid();
949 if ( IsValueUnspecified() )
950 return pg
->GetUnspecifiedValueText(argFlags
);
952 if ( m_commonValue
== -1 )
954 wxVariant
value(GetValue());
955 return ValueToString(value
, argFlags
|wxPG_VALUE_IS_CURRENT
);
959 // Return common value's string representation
960 const wxPGCommonValue
* cv
= pg
->GetCommonValue(m_commonValue
);
962 if ( argFlags
& wxPG_FULL_VALUE
)
964 return cv
->GetLabel();
966 else if ( argFlags
& wxPG_EDITABLE_VALUE
)
968 return cv
->GetEditableText();
972 return cv
->GetLabel();
976 wxString wxPGProperty
::GetValueString( int argFlags
) const
978 return GetValueAsString(argFlags
);
981 bool wxPGProperty
::IntToValue( wxVariant
& variant
, int number
, int WXUNUSED(argFlags
) ) const
983 variant
= (long)number
;
987 // Convert semicolon delimited tokens into child values.
988 bool wxPGProperty
::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
990 if ( !GetChildCount() )
993 unsigned int curChild
= 0;
995 unsigned int iMax
= m_children
.size();
997 if ( iMax
> PWC_CHILD_SUMMARY_LIMIT
&&
998 !(argFlags
& wxPG_FULL_VALUE
) )
999 iMax
= PWC_CHILD_SUMMARY_LIMIT
;
1001 bool changed
= false;
1006 // Its best only to add non-empty group items
1007 bool addOnlyIfNotEmpty
= false;
1008 const wxChar delimeter
= wxS(';');
1010 size_t tokenStart
= 0xFFFFFF;
1012 wxVariantList temp_list
;
1013 wxVariant
list(temp_list
);
1015 int propagatedFlags
= argFlags
& (wxPG_REPORT_ERROR
|wxPG_PROGRAMMATIC_VALUE
);
1017 wxLogTrace("propgrid",
1018 wxT(">> %s.StringToValue('%s')"), GetLabel(), text
);
1020 wxString
::const_iterator it
= text
.begin();
1023 if ( it
!= text
.end() )
1030 // How many units we iterate string forward at the end of loop?
1031 // We need to keep track of this or risk going to negative
1032 // with it-- operation.
1033 unsigned int strPosIncrement
= 1;
1035 if ( tokenStart
!= 0xFFFFFF )
1038 if ( a
== delimeter
|| a
== 0 )
1040 token
= text
.substr(tokenStart
,pos
-tokenStart
);
1042 size_t len
= token
.length();
1044 if ( !addOnlyIfNotEmpty
|| len
> 0 )
1046 const wxPGProperty
* child
= Item(curChild
);
1047 wxVariant
variant(child
->GetValue());
1048 wxString childName
= child
->GetBaseName();
1050 wxLogTrace("propgrid",
1051 wxT("token = '%s', child = %s"),
1054 // Add only if editable or setting programmatically
1055 if ( (argFlags
& wxPG_PROGRAMMATIC_VALUE
) ||
1056 !child
->HasFlag(wxPG_PROP_DISABLED
|wxPG_PROP_READONLY
) )
1060 if ( child
->StringToValue(variant
, token
,
1061 propagatedFlags
|wxPG_COMPOSITE_FRAGMENT
) )
1063 // We really need to set the variant's name
1064 // *after* child->StringToValue() has been
1065 // called, since variant's value may be set by
1066 // assigning another variant into it, which
1067 // then usually causes name to be copied (ie.
1068 // usually cleared) as well. wxBoolProperty
1069 // being case in point with its use of
1070 // wxPGVariant_Bool macro as an optimization.
1071 variant
.SetName(childName
);
1072 list
.Append(variant
);
1079 // Empty, becomes unspecified
1081 variant
.SetName(childName
);
1082 list
.Append(variant
);
1088 if ( curChild
>= iMax
)
1092 tokenStart
= 0xFFFFFF;
1097 // Token is not running
1098 if ( a
!= wxS(' ') )
1101 addOnlyIfNotEmpty
= false;
1103 // Is this a group of tokens?
1104 if ( a
== wxS('[') )
1108 if ( it
!= text
.end() ) ++it
;
1110 size_t startPos
= pos
;
1112 // Group item - find end
1113 while ( it
!= text
.end() && depth
> 0 )
1119 if ( a
== wxS(']') )
1121 else if ( a
== wxS('[') )
1125 token
= text
.substr(startPos
,pos
-startPos
-1);
1127 if ( !token
.length() )
1130 const wxPGProperty
* child
= Item(curChild
);
1132 wxVariant oldChildValue
= child
->GetValue();
1133 wxVariant
variant(oldChildValue
);
1135 if ( (argFlags
& wxPG_PROGRAMMATIC_VALUE
) ||
1136 !child
->HasFlag(wxPG_PROP_DISABLED
|wxPG_PROP_READONLY
) )
1138 wxString childName
= child
->GetBaseName();
1140 bool stvRes
= child
->StringToValue( variant
, token
,
1142 if ( stvRes
|| (variant
!= oldChildValue
) )
1144 variant
.SetName(childName
);
1145 list
.Append(variant
);
1156 if ( curChild
>= iMax
)
1159 addOnlyIfNotEmpty
= true;
1161 tokenStart
= 0xFFFFFF;
1167 if ( a
== delimeter
)
1168 strPosIncrement
-= 1;
1176 it
+= strPosIncrement
;
1178 if ( it
!= text
.end() )
1187 pos
+= strPosIncrement
;
1196 bool wxPGProperty
::SetValueFromString( const wxString
& text
, int argFlags
)
1198 wxVariant
variant(m_value
);
1199 bool res
= StringToValue(variant
, text
, argFlags
);
1205 bool wxPGProperty
::SetValueFromInt( long number
, int argFlags
)
1207 wxVariant
variant(m_value
);
1208 bool res
= IntToValue(variant
, number
, argFlags
);
1214 wxSize wxPGProperty
::OnMeasureImage( int WXUNUSED(item
) ) const
1216 if ( m_valueBitmap
)
1217 return wxSize(m_valueBitmap
->GetWidth(),-1);
1222 int wxPGProperty
::GetImageOffset( int imageWidth
) const
1224 int imageOffset
= 0;
1228 // Do not increment offset too much for wide images
1229 if ( imageWidth
<= (wxPG_CUSTOM_IMAGE_WIDTH
+5) )
1230 imageOffset
= imageWidth
+ DEFAULT_IMAGE_OFFSET_INCREMENT
;
1232 imageOffset
= imageWidth
+ 1;
1238 wxPGCellRenderer
* wxPGProperty
::GetCellRenderer( int WXUNUSED(column
) ) const
1240 return wxPGGlobalVars
->m_defaultRenderer
;
1243 void wxPGProperty
::OnCustomPaint( wxDC
& dc
,
1247 wxBitmap
* bmp
= m_valueBitmap
;
1249 wxCHECK_RET( bmp
&& bmp
->Ok(), wxT("invalid bitmap") );
1251 wxCHECK_RET( rect
.x
>= 0, wxT("unexpected measure call") );
1253 dc
.DrawBitmap(*bmp
,rect
.x
,rect
.y
);
1256 const wxPGEditor
* wxPGProperty
::DoGetEditorClass() const
1258 return wxPGEditor_TextCtrl
;
1261 // Default extra property event handling - that is, none at all.
1262 bool wxPGProperty
::OnEvent( wxPropertyGrid
*, wxWindow
*, wxEvent
& )
1268 void wxPGProperty
::SetValue( wxVariant value
, wxVariant
* pList
, int flags
)
1270 // If auto unspecified values are not wanted (via window or property style),
1271 // then get default value instead of wxNullVariant.
1272 if ( value
.IsNull() && (flags
& wxPG_SETVAL_BY_USER
) &&
1273 !UsesAutoUnspecified() )
1275 value
= GetDefaultValue();
1278 if ( !value
.IsNull() )
1280 wxVariant tempListVariant
;
1283 // List variants are reserved a special purpose
1284 // as intermediate containers for child values
1285 // of properties with children.
1286 if ( value
.GetType() == wxPG_VARIANT_TYPE_LIST
)
1289 // However, situation is different for composed string properties
1290 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
1292 tempListVariant
= value
;
1293 pList
= &tempListVariant
;
1297 AdaptListToValue(value
, &newValue
);
1299 //wxLogDebug(wxT(">> %s.SetValue() adapted list value to type '%s'"),GetName().c_str(),value.GetType().c_str());
1302 if ( HasFlag( wxPG_PROP_AGGREGATE
) )
1303 flags
|= wxPG_SETVAL_AGGREGATED
;
1305 if ( pList
&& !pList
->IsNull() )
1307 wxASSERT( pList
->GetType() == wxPG_VARIANT_TYPE_LIST
);
1308 wxASSERT( GetChildCount() );
1309 wxASSERT( !IsCategory() );
1311 wxVariantList
& list
= pList
->GetList();
1312 wxVariantList
::iterator node
;
1315 //wxLogDebug(wxT(">> %s.SetValue() pList parsing"),GetName().c_str());
1317 // Children in list can be in any order, but we will give hint to
1318 // GetPropertyByNameWH(). This optimizes for full list parsing.
1319 for ( node
= list
.begin(); node
!= list
.end(); ++node
)
1321 wxVariant
& childValue
= *((wxVariant
*)*node
);
1322 wxPGProperty
* child
= GetPropertyByNameWH(childValue
.GetName(), i
);
1325 //wxLogDebug(wxT("%i: child = %s, childValue.GetType()=%s"),i,child->GetBaseName().c_str(),childValue.GetType().c_str());
1326 if ( childValue
.GetType() == wxPG_VARIANT_TYPE_LIST
)
1328 if ( child
->HasFlag(wxPG_PROP_AGGREGATE
) && !(flags
& wxPG_SETVAL_AGGREGATED
) )
1330 wxVariant listRefCopy
= childValue
;
1331 child
->SetValue(childValue
, &listRefCopy
, flags
|wxPG_SETVAL_FROM_PARENT
);
1335 wxVariant oldVal
= child
->GetValue();
1336 child
->SetValue(oldVal
, &childValue
, flags
|wxPG_SETVAL_FROM_PARENT
);
1339 else if ( child
->GetValue() != childValue
)
1341 // For aggregate properties, we will trust RefreshChildren()
1342 // to update child values.
1343 if ( !HasFlag(wxPG_PROP_AGGREGATE
) )
1344 child
->SetValue(childValue
, NULL
, flags
|wxPG_SETVAL_FROM_PARENT
);
1345 if ( flags
& wxPG_SETVAL_BY_USER
)
1346 child
->SetFlag(wxPG_PROP_MODIFIED
);
1353 if ( !value
.IsNull() )
1359 if ( flags
& wxPG_SETVAL_BY_USER
)
1360 SetFlag(wxPG_PROP_MODIFIED
);
1362 if ( HasFlag(wxPG_PROP_AGGREGATE
) )
1367 if ( m_commonValue
!= -1 )
1369 wxPropertyGrid
* pg
= GetGrid();
1370 if ( !pg
|| m_commonValue
!= pg
->GetUnspecifiedCommonValue() )
1376 // Set children to unspecified, but only if aggregate or
1377 // value is <composed>
1378 if ( AreChildrenComponents() )
1381 for ( i
=0; i
<GetChildCount(); i
++ )
1382 Item(i
)->SetValue(value
, NULL
, flags
|wxPG_SETVAL_FROM_PARENT
);
1386 if ( !(flags
& wxPG_SETVAL_FROM_PARENT
) )
1387 UpdateParentValues();
1390 // Update editor control.
1391 if ( flags
& wxPG_SETVAL_REFRESH_EDITOR
)
1393 wxPropertyGrid
* pg
= GetGridIfDisplayed();
1396 wxPGProperty
* selected
= pg
->GetSelectedProperty();
1398 // Only refresh the control if this was selected, or
1399 // this was some parent of selected, or vice versa)
1400 if ( selected
&& (selected
== this ||
1401 selected
->IsSomeParent(this) ||
1402 this->IsSomeParent(selected
)) )
1405 pg
->DrawItemAndValueRelated(this);
1411 void wxPGProperty
::SetValueInEvent( wxVariant value
) const
1413 GetGrid()->ValueChangeInEvent(value
);
1416 void wxPGProperty
::SetFlagRecursively( FlagType flag
, bool set
)
1418 ChangeFlag(flag
, set
);
1421 for ( i
= 0; i
< GetChildCount(); i
++ )
1422 Item(i
)->SetFlagRecursively(flag
, set
);
1425 void wxPGProperty
::RefreshEditor()
1430 wxPropertyGrid
* pg
= GetGrid();
1431 if ( pg
&& pg
->GetSelectedProperty() == this )
1432 pg
->RefreshEditor();
1435 wxVariant wxPGProperty
::GetDefaultValue() const
1437 wxVariant defVal
= GetAttribute(wxPG_ATTR_DEFAULT_VALUE
);
1438 if ( !defVal
.IsNull() )
1441 wxVariant value
= GetValue();
1443 if ( !value
.IsNull() )
1445 wxString
valueType(value
.GetType());
1447 if ( valueType
== wxPG_VARIANT_TYPE_LONG
)
1448 return wxPGVariant_Zero
;
1449 if ( valueType
== wxPG_VARIANT_TYPE_STRING
)
1450 return wxPGVariant_EmptyString
;
1451 if ( valueType
== wxPG_VARIANT_TYPE_BOOL
)
1452 return wxPGVariant_False
;
1453 if ( valueType
== wxPG_VARIANT_TYPE_DOUBLE
)
1454 return wxVariant(0.0);
1455 if ( valueType
== wxPG_VARIANT_TYPE_ARRSTRING
)
1456 return wxVariant(wxArrayString());
1457 if ( valueType
== wxS("wxLongLong") )
1458 return WXVARIANT(wxLongLong(0));
1459 if ( valueType
== wxS("wxULongLong") )
1460 return WXVARIANT(wxULongLong(0));
1461 if ( valueType
== wxS("wxColour") )
1462 return WXVARIANT(*wxBLACK
);
1464 if ( valueType
== wxPG_VARIANT_TYPE_DATETIME
)
1465 return wxVariant(wxDateTime
::Now());
1467 if ( valueType
== wxS("wxFont") )
1468 return WXVARIANT(*wxNORMAL_FONT
);
1469 if ( valueType
== wxS("wxPoint") )
1470 return WXVARIANT(wxPoint(0, 0));
1471 if ( valueType
== wxS("wxSize") )
1472 return WXVARIANT(wxSize(0, 0));
1478 void wxPGProperty
::EnsureCells( unsigned int column
)
1480 if ( column
>= m_cells
.size() )
1482 // Fill empty slots with default cells
1483 wxPropertyGrid
* pg
= GetGrid();
1484 wxPGCell defaultCell
;
1486 // Work around possible VC6 bug by using intermediate variables
1487 const wxPGCell
& propDefCell
= pg
->GetPropertyDefaultCell();
1488 const wxPGCell
& catDefCell
= pg
->GetCategoryDefaultCell();
1490 if ( !HasFlag(wxPG_PROP_CATEGORY
) )
1491 defaultCell
= propDefCell
;
1493 defaultCell
= catDefCell
;
1495 // TODO: Replace with resize() call
1496 unsigned int cellCountMax
= column
+1;
1498 for ( unsigned int i
=m_cells
.size(); i
<cellCountMax
; i
++ )
1499 m_cells
.push_back(defaultCell
);
1503 void wxPGProperty
::SetCell( int column
,
1504 const wxPGCell
& cell
)
1506 EnsureCells(column
);
1508 m_cells
[column
] = cell
;
1511 void wxPGProperty
::AdaptiveSetCell( unsigned int firstCol
,
1512 unsigned int lastCol
,
1513 const wxPGCell
& cell
,
1514 const wxPGCell
& srcData
,
1515 wxPGCellData
* unmodCellData
,
1516 FlagType ignoreWithFlags
,
1520 // Sets cell in memory optimizing fashion. That is, if
1521 // current cell data matches unmodCellData, we will
1522 // simply get reference to data from cell. Otherwise,
1523 // cell information from srcData is merged into current.
1526 if ( !(m_flags
& ignoreWithFlags
) && !IsRoot() )
1528 EnsureCells(lastCol
);
1530 for ( unsigned int col
=firstCol
; col
<=lastCol
; col
++ )
1532 if ( m_cells
[col
].GetData() == unmodCellData
)
1534 // Data matches... use cell directly
1535 m_cells
[col
] = cell
;
1539 // Data did not match... merge valid information
1540 m_cells
[col
].MergeFrom(srcData
);
1547 for ( unsigned int i
=0; i
<GetChildCount(); i
++ )
1548 Item(i
)->AdaptiveSetCell( firstCol
,
1558 const wxPGCell
& wxPGProperty
::GetCell( unsigned int column
) const
1560 if ( m_cells
.size() > column
)
1561 return m_cells
[column
];
1563 wxPropertyGrid
* pg
= GetGrid();
1566 return pg
->GetCategoryDefaultCell();
1568 return pg
->GetPropertyDefaultCell();
1571 wxPGCell
& wxPGProperty
::GetOrCreateCell( unsigned int column
)
1573 EnsureCells(column
);
1574 return m_cells
[column
];
1577 void wxPGProperty
::SetBackgroundColour( const wxColour
& colour
,
1580 wxPGProperty
* firstProp
= this;
1581 bool recursively
= flags
& wxPG_RECURSE ?
true : false;
1584 // If category is tried to set recursively, skip it and only
1585 // affect the children.
1588 while ( firstProp
->IsCategory() )
1590 if ( !firstProp
->GetChildCount() )
1592 firstProp
= firstProp
->Item(0);
1596 wxPGCell
& firstCell
= firstProp
->GetCell(0);
1597 wxPGCellData
* firstCellData
= firstCell
.GetData();
1599 wxPGCell
newCell(firstCell
);
1600 newCell
.SetBgCol(colour
);
1602 srcCell
.SetBgCol(colour
);
1605 GetParentState()->GetColumnCount()-1,
1609 recursively ? wxPG_PROP_CATEGORY
: 0,
1613 void wxPGProperty
::SetTextColour( const wxColour
& colour
,
1616 wxPGProperty
* firstProp
= this;
1617 bool recursively
= flags
& wxPG_RECURSE ?
true : false;
1620 // If category is tried to set recursively, skip it and only
1621 // affect the children.
1624 while ( firstProp
->IsCategory() )
1626 if ( !firstProp
->GetChildCount() )
1628 firstProp
= firstProp
->Item(0);
1632 wxPGCell
& firstCell
= firstProp
->GetCell(0);
1633 wxPGCellData
* firstCellData
= firstCell
.GetData();
1635 wxPGCell
newCell(firstCell
);
1636 newCell
.SetFgCol(colour
);
1638 srcCell
.SetFgCol(colour
);
1641 GetParentState()->GetColumnCount()-1,
1645 recursively ? wxPG_PROP_CATEGORY
: 0,
1649 wxPGEditorDialogAdapter
* wxPGProperty
::GetEditorDialog() const
1654 bool wxPGProperty
::DoSetAttribute( const wxString
& WXUNUSED(name
), wxVariant
& WXUNUSED(value
) )
1659 void wxPGProperty
::SetAttribute( const wxString
& name
, wxVariant value
)
1661 if ( DoSetAttribute( name
, value
) )
1663 // Support working without grid, when possible
1664 if ( wxPGGlobalVars
->HasExtraStyle( wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES
) )
1668 m_attributes
.Set( name
, value
);
1671 void wxPGProperty
::SetAttributes( const wxPGAttributeStorage
& attributes
)
1673 wxPGAttributeStorage
::const_iterator it
= attributes
.StartIteration();
1676 while ( attributes
.GetNext(it
, variant
) )
1677 SetAttribute( variant
.GetName(), variant
);
1680 wxVariant wxPGProperty
::DoGetAttribute( const wxString
& WXUNUSED(name
) ) const
1686 wxVariant wxPGProperty
::GetAttribute( const wxString
& name
) const
1688 return m_attributes
.FindValue(name
);
1691 wxString wxPGProperty
::GetAttribute( const wxString
& name
, const wxString
& defVal
) const
1693 wxVariant variant
= m_attributes
.FindValue(name
);
1695 if ( !variant
.IsNull() )
1696 return variant
.GetString();
1701 long wxPGProperty
::GetAttributeAsLong( const wxString
& name
, long defVal
) const
1703 wxVariant variant
= m_attributes
.FindValue(name
);
1705 if ( variant
.IsNull() )
1708 return variant
.GetLong();
1711 double wxPGProperty
::GetAttributeAsDouble( const wxString
& name
, double defVal
) const
1713 wxVariant variant
= m_attributes
.FindValue(name
);
1715 if ( variant
.IsNull() )
1718 return variant
.GetDouble();
1721 wxVariant wxPGProperty
::GetAttributesAsList() const
1723 wxVariantList tempList
;
1724 wxVariant
v( tempList
, wxString
::Format(wxS("@%s@attr"),m_name
.c_str()) );
1726 wxPGAttributeStorage
::const_iterator it
= m_attributes
.StartIteration();
1729 while ( m_attributes
.GetNext(it
, variant
) )
1735 // Slots of utility flags are NULL
1736 const unsigned int gs_propFlagToStringSize
= 14;
1738 static const wxChar
* const gs_propFlagToString
[gs_propFlagToStringSize
] = {
1755 wxString wxPGProperty
::GetFlagsAsString( FlagType flagsMask
) const
1758 int relevantFlags
= m_flags
& flagsMask
& wxPG_STRING_STORED_FLAGS
;
1762 for ( i
=0; i
<gs_propFlagToStringSize
; i
++ )
1764 if ( relevantFlags
& a
)
1766 const wxChar
* fs
= gs_propFlagToString
[i
];
1778 void wxPGProperty
::SetFlagsFromString( const wxString
& str
)
1782 WX_PG_TOKENIZER1_BEGIN(str
, wxS('|'))
1784 for ( i
=0; i
<gs_propFlagToStringSize
; i
++ )
1786 const wxChar
* fs
= gs_propFlagToString
[i
];
1787 if ( fs
&& str
== fs
)
1793 WX_PG_TOKENIZER1_END()
1795 m_flags
= (m_flags
& ~wxPG_STRING_STORED_FLAGS
) | flags
;
1798 wxValidator
* wxPGProperty
::DoGetValidator() const
1803 int wxPGProperty
::InsertChoice( const wxString
& label
, int index
, int value
)
1805 wxPropertyGrid
* pg
= GetGrid();
1806 int sel
= GetChoiceSelection();
1810 if ( index
== wxNOT_FOUND
)
1811 index
= m_choices
.GetCount();
1816 m_choices
.Insert(label
, index
, value
);
1818 if ( sel
!= newSel
)
1819 SetChoiceSelection(newSel
);
1821 if ( this == pg
->GetSelection() )
1822 GetEditorClass()->InsertItem(pg
->GetEditorControl(),label
,index
);
1828 void wxPGProperty
::DeleteChoice( int index
)
1830 wxPropertyGrid
* pg
= GetGrid();
1832 int sel
= GetChoiceSelection();
1835 // Adjust current value
1838 SetValueToUnspecified();
1841 else if ( index
< sel
)
1846 m_choices
.RemoveAt(index
);
1848 if ( sel
!= newSel
)
1849 SetChoiceSelection(newSel
);
1851 if ( this == pg
->GetSelection() )
1852 GetEditorClass()->DeleteItem(pg
->GetEditorControl(), index
);
1855 int wxPGProperty
::GetChoiceSelection() const
1857 wxVariant value
= GetValue();
1858 wxString valueType
= value
.GetType();
1859 int index
= wxNOT_FOUND
;
1861 if ( IsValueUnspecified() || !m_choices
.GetCount() )
1864 if ( valueType
== wxPG_VARIANT_TYPE_LONG
)
1866 index
= value
.GetLong();
1868 else if ( valueType
== wxPG_VARIANT_TYPE_STRING
)
1870 index
= m_choices
.Index(value
.GetString());
1872 else if ( valueType
== wxPG_VARIANT_TYPE_BOOL
)
1874 index
= value
.GetBool()?
1 : 0;
1880 void wxPGProperty
::SetChoiceSelection( int newValue
)
1882 // Changes value of a property with choices, but only
1883 // works if the value type is long or string.
1884 wxString valueType
= GetValue().GetType();
1886 wxCHECK_RET( m_choices
.IsOk(), wxT("invalid choiceinfo") );
1888 if ( valueType
== wxPG_VARIANT_TYPE_STRING
)
1890 SetValue( m_choices
.GetLabel(newValue
) );
1892 else // if ( valueType == wxPG_VARIANT_TYPE_LONG )
1894 SetValue( (long) newValue
);
1898 bool wxPGProperty
::SetChoices( wxPGChoices
& choices
)
1900 m_choices
.Assign(choices
);
1903 // This may be needed to trigger some initialization
1904 // (but don't do it if property is somewhat uninitialized)
1905 wxVariant defVal
= GetDefaultValue();
1906 if ( defVal
.IsNull() )
1916 const wxPGEditor
* wxPGProperty
::GetEditorClass() const
1918 const wxPGEditor
* editor
;
1920 if ( !m_customEditor
)
1922 editor
= DoGetEditorClass();
1925 editor
= m_customEditor
;
1928 // Maybe override editor if common value specified
1929 if ( GetDisplayedCommonValueCount() )
1931 // TextCtrlAndButton -> ComboBoxAndButton
1932 if ( editor
->IsKindOf(CLASSINFO(wxPGTextCtrlAndButtonEditor
)) )
1933 editor
= wxPGEditor_ChoiceAndButton
;
1935 // TextCtrl -> ComboBox
1936 else if ( editor
->IsKindOf(CLASSINFO(wxPGTextCtrlEditor
)) )
1937 editor
= wxPGEditor_ComboBox
;
1943 bool wxPGProperty
::HasVisibleChildren() const
1947 for ( i
=0; i
<GetChildCount(); i
++ )
1949 wxPGProperty
* child
= Item(i
);
1951 if ( !child
->HasFlag(wxPG_PROP_HIDDEN
) )
1958 bool wxPGProperty
::RecreateEditor()
1960 wxPropertyGrid
* pg
= GetGrid();
1963 wxPGProperty
* selected
= pg
->GetSelection();
1964 if ( this == selected
)
1966 pg
->DoSelectProperty(this, wxPG_SEL_FORCE
);
1973 void wxPGProperty
::SetValueImage( wxBitmap
& bmp
)
1975 delete m_valueBitmap
;
1977 if ( &bmp
&& bmp
.Ok() )
1980 wxSize maxSz
= GetGrid()->GetImageSize();
1981 wxSize
imSz(bmp
.GetWidth(),bmp
.GetHeight());
1983 if ( imSz
.y
!= maxSz
.y
)
1985 // Create a memory DC
1986 wxBitmap
* bmpNew
= new wxBitmap(maxSz
.x
,maxSz
.y
,bmp
.GetDepth());
1989 dc
.SelectObject(*bmpNew
);
1992 // FIXME: This is ugly - use image or wait for scaling patch.
1993 double scaleY
= (double)maxSz
.y
/ (double)imSz
.y
;
1995 dc
.SetUserScale(scaleY
, scaleY
);
1997 dc
.DrawBitmap(bmp
, 0, 0);
1999 m_valueBitmap
= bmpNew
;
2003 m_valueBitmap
= new wxBitmap(bmp
);
2006 m_flags
|= wxPG_PROP_CUSTOMIMAGE
;
2010 m_valueBitmap
= NULL
;
2011 m_flags
&= ~(wxPG_PROP_CUSTOMIMAGE
);
2016 wxPGProperty
* wxPGProperty
::GetMainParent() const
2018 const wxPGProperty
* curChild
= this;
2019 const wxPGProperty
* curParent
= m_parent
;
2021 while ( curParent
&& !curParent
->IsCategory() )
2023 curChild
= curParent
;
2024 curParent
= curParent
->m_parent
;
2027 return (wxPGProperty
*) curChild
;
2031 const wxPGProperty
* wxPGProperty
::GetLastVisibleSubItem() const
2034 // Returns last visible sub-item, recursively.
2035 if ( !IsExpanded() || !GetChildCount() )
2038 return Last()->GetLastVisibleSubItem();
2042 bool wxPGProperty
::IsVisible() const
2044 const wxPGProperty
* parent
;
2046 if ( HasFlag(wxPG_PROP_HIDDEN
) )
2049 for ( parent
= GetParent(); parent
!= NULL
; parent
= parent
->GetParent() )
2051 if ( !parent
->IsExpanded() || parent
->HasFlag(wxPG_PROP_HIDDEN
) )
2058 wxPropertyGrid
* wxPGProperty
::GetGridIfDisplayed() const
2060 wxPropertyGridPageState
* state
= GetParentState();
2063 wxPropertyGrid
* propGrid
= state
->GetGrid();
2064 if ( state
== propGrid
->GetState() )
2070 int wxPGProperty
::GetY2( int lh
) const
2072 const wxPGProperty
* parent
;
2073 const wxPGProperty
* child
= this;
2077 for ( parent
= GetParent(); parent
!= NULL
; parent
= child
->GetParent() )
2079 if ( !parent
->IsExpanded() )
2081 y
+= parent
->GetChildrenHeight(lh
, child
->GetIndexInParent());
2086 y
-= lh
; // need to reduce one level
2092 int wxPGProperty
::GetY() const
2094 return GetY2(GetGrid()->GetRowHeight());
2097 // This is used by Insert etc.
2098 void wxPGProperty
::DoAddChild( wxPGProperty
* prop
, int index
,
2101 if ( index
< 0 || (size_t)index
>= m_children
.size() )
2103 if ( correct_mode
) prop
->m_arrIndex
= m_children
.size();
2104 m_children
.push_back( prop
);
2108 m_children
.insert( m_children
.begin()+index
, prop
);
2109 if ( correct_mode
) FixIndicesOfChildren( index
);
2112 prop
->m_parent
= this;
2115 void wxPGProperty
::DoPreAddChild( int index
, wxPGProperty
* prop
)
2117 wxASSERT_MSG( prop
->GetBaseName().length(),
2118 "Property's children must have unique, non-empty "
2119 "names within their scope" );
2121 prop
->m_arrIndex
= index
;
2122 m_children
.insert( m_children
.begin()+index
,
2125 int custImgHeight
= prop
->OnMeasureImage().y
;
2126 if ( custImgHeight
< 0 /*|| custImgHeight > 1*/ )
2127 prop
->m_flags
|= wxPG_PROP_CUSTOMIMAGE
;
2129 prop
->m_parent
= this;
2132 void wxPGProperty
::AddPrivateChild( wxPGProperty
* prop
)
2134 if ( !(m_flags
& wxPG_PROP_PARENTAL_FLAGS
) )
2135 SetParentalType(wxPG_PROP_AGGREGATE
);
2137 wxASSERT_MSG( (m_flags
& wxPG_PROP_PARENTAL_FLAGS
) ==
2138 wxPG_PROP_AGGREGATE
,
2139 "Do not mix up AddPrivateChild() calls with other "
2140 "property adders." );
2142 DoPreAddChild( m_children
.size(), prop
);
2145 #if wxPG_COMPATIBILITY_1_4
2146 void wxPGProperty
::AddChild( wxPGProperty
* prop
)
2148 AddPrivateChild(prop
);
2152 wxPGProperty
* wxPGProperty
::InsertChild( int index
,
2153 wxPGProperty
* childProperty
)
2156 index
= m_children
.size();
2158 if ( m_parentState
)
2160 m_parentState
->DoInsert(this, index
, childProperty
);
2164 if ( !(m_flags
& wxPG_PROP_PARENTAL_FLAGS
) )
2165 SetParentalType(wxPG_PROP_MISC_PARENT
);
2167 wxASSERT_MSG( (m_flags
& wxPG_PROP_PARENTAL_FLAGS
) ==
2168 wxPG_PROP_MISC_PARENT
,
2169 "Do not mix up AddPrivateChild() calls with other "
2170 "property adders." );
2172 DoPreAddChild( index
, childProperty
);
2175 return childProperty
;
2178 void wxPGProperty
::RemoveChild( wxPGProperty
* p
)
2180 wxArrayPGProperty
::iterator it
;
2181 wxArrayPGProperty
& children
= m_children
;
2183 for ( it
=children
.begin(); it
!= children
.end(); it
++ )
2193 void wxPGProperty
::AdaptListToValue( wxVariant
& list
, wxVariant
* value
) const
2195 wxASSERT( GetChildCount() );
2196 wxASSERT( !IsCategory() );
2198 *value
= GetValue();
2200 if ( !list
.GetCount() )
2203 wxASSERT( GetChildCount() >= (unsigned int)list
.GetCount() );
2205 bool allChildrenSpecified
;
2207 // Don't fully update aggregate properties unless all children have
2209 if ( HasFlag(wxPG_PROP_AGGREGATE
) )
2210 allChildrenSpecified
= AreAllChildrenSpecified(&list
);
2212 allChildrenSpecified
= true;
2214 wxVariant childValue
= list
[0];
2218 //wxLogDebug(wxT(">> %s.AdaptListToValue()"),GetBaseName().c_str());
2220 for ( i
=0; i
<GetChildCount(); i
++ )
2222 const wxPGProperty
* child
= Item(i
);
2224 if ( childValue
.GetName() == child
->GetBaseName() )
2226 //wxLogDebug(wxT(" %s(n=%i), %s"),childValue.GetName().c_str(),n,childValue.GetType().c_str());
2228 if ( childValue
.GetType() == wxPG_VARIANT_TYPE_LIST
)
2230 wxVariant
cv2(child
->GetValue());
2231 child
->AdaptListToValue(childValue
, &cv2
);
2235 if ( allChildrenSpecified
)
2237 *value
= ChildChanged(*value
, i
, childValue
);
2241 if ( n
== (unsigned int)list
.GetCount() )
2243 childValue
= list
[n
];
2249 void wxPGProperty
::FixIndicesOfChildren( unsigned int starthere
)
2252 for ( i
=starthere
;i
<GetChildCount();i
++)
2253 Item(i
)->m_arrIndex
= i
;
2257 // Returns (direct) child property with given name (or NULL if not found)
2258 wxPGProperty
* wxPGProperty
::GetPropertyByName( const wxString
& name
) const
2262 for ( i
=0; i
<GetChildCount(); i
++ )
2264 wxPGProperty
* p
= Item(i
);
2265 if ( p
->m_name
== name
)
2269 // Does it have point, then?
2270 int pos
= name
.Find(wxS('.'));
2274 wxPGProperty
* p
= GetPropertyByName(name
. substr(0,pos
));
2276 if ( !p
|| !p
->GetChildCount() )
2279 return p
->GetPropertyByName(name
.substr(pos
+1,name
.length()-pos
-1));
2282 wxPGProperty
* wxPGProperty
::GetPropertyByNameWH( const wxString
& name
, unsigned int hintIndex
) const
2284 unsigned int i
= hintIndex
;
2286 if ( i
>= GetChildCount() )
2289 unsigned int lastIndex
= i
- 1;
2291 if ( lastIndex
>= GetChildCount() )
2292 lastIndex
= GetChildCount() - 1;
2296 wxPGProperty
* p
= Item(i
);
2297 if ( p
->m_name
== name
)
2300 if ( i
== lastIndex
)
2304 if ( i
== GetChildCount() )
2311 int wxPGProperty
::GetChildrenHeight( int lh
, int iMax_
) const
2313 // Returns height of children, recursively, and
2314 // by taking expanded/collapsed status into account.
2316 // iMax is used when finding property y-positions.
2322 iMax_
= GetChildCount();
2324 unsigned int iMax
= iMax_
;
2326 wxASSERT( iMax
<= GetChildCount() );
2328 if ( !IsExpanded() && GetParent() )
2333 wxPGProperty
* pwc
= (wxPGProperty
*) Item(i
);
2335 if ( !pwc
->HasFlag(wxPG_PROP_HIDDEN
) )
2337 if ( !pwc
->IsExpanded() ||
2338 pwc
->GetChildCount() == 0 )
2341 h
+= pwc
->GetChildrenHeight(lh
) + lh
;
2350 wxPGProperty
* wxPGProperty
::GetItemAtY( unsigned int y
,
2352 unsigned int* nextItemY
) const
2354 wxASSERT( nextItemY
);
2356 // Linear search at the moment
2358 // nextItemY = y of next visible property, final value will be written back.
2359 wxPGProperty
* result
= NULL
;
2360 wxPGProperty
* current
= NULL
;
2361 unsigned int iy
= *nextItemY
;
2363 unsigned int iMax
= GetChildCount();
2367 wxPGProperty
* pwc
= Item(i
);
2369 if ( !pwc
->HasFlag(wxPG_PROP_HIDDEN
) )
2380 if ( pwc
->IsExpanded() &&
2381 pwc
->GetChildCount() > 0 )
2383 result
= (wxPGProperty
*) pwc
->GetItemAtY( y
, lh
, &iy
);
2395 if ( !result
&& y
< iy
)
2403 wxLogDebug(wxT("%s::GetItemAtY(%i) -> %s"),this->GetLabel().c_str(),y,current->GetLabel().c_str());
2407 wxLogDebug(wxT("%s::GetItemAtY(%i) -> NULL"),this->GetLabel().c_str(),y);
2411 return (wxPGProperty
*) result
;
2414 void wxPGProperty
::Empty()
2417 if ( !HasFlag(wxPG_PROP_CHILDREN_ARE_COPIES
) )
2419 for ( i
=0; i
<GetChildCount(); i
++ )
2421 delete m_children
[i
];
2428 wxPGProperty
* wxPGProperty
::GetItemAtY( unsigned int y
) const
2430 unsigned int nextItem
;
2431 return GetItemAtY( y
, GetGrid()->GetRowHeight(), &nextItem
);
2434 void wxPGProperty
::DeleteChildren()
2436 wxPropertyGridPageState
* state
= m_parentState
;
2438 while ( GetChildCount() )
2440 wxPGProperty
* child
= Item(GetChildCount()-1);
2441 state
->DoDelete(child
, true);
2445 wxVariant wxPGProperty
::ChildChanged( wxVariant
& WXUNUSED(thisValue
),
2446 int WXUNUSED(childIndex
),
2447 wxVariant
& WXUNUSED(childValue
) ) const
2449 return wxNullVariant
;
2452 bool wxPGProperty
::AreAllChildrenSpecified( wxVariant
* pendingList
) const
2456 const wxVariantList
* pList
= NULL
;
2457 wxVariantList
::const_iterator node
;
2461 pList
= &pendingList
->GetList();
2462 node
= pList
->begin();
2465 for ( i
=0; i
<GetChildCount(); i
++ )
2467 wxPGProperty
* child
= Item(i
);
2468 const wxVariant
* listValue
= NULL
;
2473 const wxString
& childName
= child
->GetBaseName();
2475 for ( ; node
!= pList
->end(); ++node
)
2477 const wxVariant
& item
= *((const wxVariant
*)*node
);
2478 if ( item
.GetName() == childName
)
2488 value
= child
->GetValue();
2490 if ( value
.IsNull() )
2493 // Check recursively
2494 if ( child
->GetChildCount() )
2496 const wxVariant
* childList
= NULL
;
2498 if ( listValue
&& listValue
->GetType() == wxPG_VARIANT_TYPE_LIST
)
2499 childList
= listValue
;
2501 if ( !child
->AreAllChildrenSpecified((wxVariant
*)childList
) )
2509 wxPGProperty
* wxPGProperty
::UpdateParentValues()
2511 wxPGProperty
* parent
= m_parent
;
2512 if ( parent
&& parent
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) &&
2513 !parent
->IsCategory() && !parent
->IsRoot() )
2516 parent
->DoGenerateComposedValue(s
);
2517 parent
->m_value
= s
;
2518 return parent
->UpdateParentValues();
2523 bool wxPGProperty
::IsTextEditable() const
2525 if ( HasFlag(wxPG_PROP_READONLY
) )
2528 if ( HasFlag(wxPG_PROP_NOEDITOR
) &&
2530 wxString(GetEditorClass()->GetClassInfo()->GetClassName()).EndsWith(wxS("Button")))
2537 // Call after fixed sub-properties added/removed after creation.
2538 // if oldSelInd >= 0 and < new max items, then selection is
2539 // moved to it. Note: oldSelInd -2 indicates that this property
2540 // should be selected.
2541 void wxPGProperty
::SubPropsChanged( int oldSelInd
)
2543 wxPropertyGridPageState
* state
= GetParentState();
2544 wxPropertyGrid
* grid
= state
->GetGrid();
2547 // Re-repare children (recursively)
2548 for ( unsigned int i
=0; i
<GetChildCount(); i
++ )
2550 wxPGProperty
* child
= Item(i
);
2551 child
->InitAfterAdded(state
, grid
);
2554 wxPGProperty
* sel
= NULL
;
2555 if ( oldSelInd
>= (int)m_children
.size() )
2556 oldSelInd
= (int)m_children
.size() - 1;
2558 if ( oldSelInd
>= 0 )
2559 sel
= m_children
[oldSelInd
];
2560 else if ( oldSelInd
== -2 )
2564 state
->DoSelectProperty(sel
);
2566 if ( state
== grid
->GetState() )
2568 grid
->GetPanel()->Refresh();
2572 // -----------------------------------------------------------------------
2574 // -----------------------------------------------------------------------
2576 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty
,none
,TextCtrl
)
2577 IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty
, wxPGProperty
)
2580 wxPGRootProperty
::wxPGRootProperty( const wxString
& name
)
2590 wxPGRootProperty
::~wxPGRootProperty()
2595 // -----------------------------------------------------------------------
2596 // wxPropertyCategory
2597 // -----------------------------------------------------------------------
2599 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPropertyCategory
,none
,TextCtrl
)
2600 IMPLEMENT_DYNAMIC_CLASS(wxPropertyCategory
, wxPGProperty
)
2602 void wxPropertyCategory
::Init()
2604 // don't set colour - prepareadditem method should do this
2605 SetParentalType(wxPG_PROP_CATEGORY
);
2606 m_capFgColIndex
= 1;
2610 wxPropertyCategory
::wxPropertyCategory()
2617 wxPropertyCategory
::wxPropertyCategory( const wxString
&label
, const wxString
& name
)
2618 : wxPGProperty(label
,name
)
2624 wxPropertyCategory
::~wxPropertyCategory()
2629 wxString wxPropertyCategory
::ValueToString( wxVariant
& WXUNUSED(value
),
2630 int WXUNUSED(argFlags
) ) const
2632 return wxEmptyString
;
2635 int wxPropertyCategory
::GetTextExtent( const wxWindow
* wnd
, const wxFont
& font
) const
2637 if ( m_textExtent
> 0 )
2638 return m_textExtent
;
2640 ((wxWindow
*)wnd
)->GetTextExtent( m_label
, &x
, &y
, 0, 0, &font
);
2644 void wxPropertyCategory
::CalculateTextExtent( wxWindow
* wnd
, const wxFont
& font
)
2647 wnd
->GetTextExtent( m_label
, &x
, &y
, 0, 0, &font
);
2651 // -----------------------------------------------------------------------
2653 // -----------------------------------------------------------------------
2655 wxPGChoiceEntry
& wxPGChoices
::Add( const wxString
& label
, int value
)
2659 wxPGChoiceEntry
entry(label
, value
);
2660 return m_data
->Insert( -1, entry
);
2663 // -----------------------------------------------------------------------
2665 wxPGChoiceEntry
& wxPGChoices
::Add( const wxString
& label
, const wxBitmap
& bitmap
, int value
)
2669 wxPGChoiceEntry
entry(label
, value
);
2670 entry
.SetBitmap(bitmap
);
2671 return m_data
->Insert( -1, entry
);
2674 // -----------------------------------------------------------------------
2676 wxPGChoiceEntry
& wxPGChoices
::Insert( const wxPGChoiceEntry
& entry
, int index
)
2680 return m_data
->Insert( index
, entry
);
2683 // -----------------------------------------------------------------------
2685 wxPGChoiceEntry
& wxPGChoices
::Insert( const wxString
& label
, int index
, int value
)
2689 wxPGChoiceEntry
entry(label
, value
);
2690 return m_data
->Insert( index
, entry
);
2693 // -----------------------------------------------------------------------
2695 wxPGChoiceEntry
& wxPGChoices
::AddAsSorted( const wxString
& label
, int value
)
2701 while ( index
< GetCount() )
2703 int cmpRes
= GetLabel(index
).Cmp(label
);
2709 wxPGChoiceEntry
entry(label
, value
);
2710 return m_data
->Insert( index
, entry
);
2713 // -----------------------------------------------------------------------
2715 void wxPGChoices
::Add( const wxChar
* const* labels
, const ValArrItem
* values
)
2719 unsigned int itemcount
= 0;
2720 const wxChar
* const* p
= &labels
[0];
2721 while ( *p
) { p
++; itemcount
++; }
2724 for ( i
= 0; i
< itemcount
; i
++ )
2729 wxPGChoiceEntry
entry(labels
[i
], value
);
2730 m_data
->Insert( i
, entry
);
2734 // -----------------------------------------------------------------------
2736 void wxPGChoices
::Add( const wxArrayString
& arr
, const wxArrayInt
& arrint
)
2741 unsigned int itemcount
= arr
.size();
2743 for ( i
= 0; i
< itemcount
; i
++ )
2746 if ( &arrint
&& arrint
.size() )
2748 wxPGChoiceEntry
entry(arr
[i
], value
);
2749 m_data
->Insert( i
, entry
);
2753 // -----------------------------------------------------------------------
2755 void wxPGChoices
::RemoveAt(size_t nIndex
, size_t count
)
2759 wxASSERT( m_data
->GetRefCount() != -1 );
2760 m_data
->m_items
.erase(m_data
->m_items
.begin()+nIndex
,
2761 m_data
->m_items
.begin()+nIndex
+count
);
2764 // -----------------------------------------------------------------------
2766 void wxPGChoices
::Clear()
2768 if ( m_data
!= wxPGChoicesEmptyData
)
2775 // -----------------------------------------------------------------------
2777 int wxPGChoices
::Index( const wxString
& str
) const
2782 for ( i
=0; i
< m_data
->GetCount(); i
++ )
2784 const wxPGChoiceEntry
& entry
= m_data
->Item(i
);
2785 if ( entry
.HasText() && entry
.GetText() == str
)
2792 // -----------------------------------------------------------------------
2794 int wxPGChoices
::Index( int val
) const
2799 for ( i
=0; i
< m_data
->GetCount(); i
++ )
2801 const wxPGChoiceEntry
& entry
= m_data
->Item(i
);
2802 if ( entry
.GetValue() == val
)
2809 // -----------------------------------------------------------------------
2811 wxArrayString wxPGChoices
::GetLabels() const
2816 if ( this && IsOk() )
2817 for ( i
=0; i
<GetCount(); i
++ )
2818 arr
.push_back(GetLabel(i
));
2823 // -----------------------------------------------------------------------
2825 wxArrayInt wxPGChoices
::GetValuesForStrings( const wxArrayString
& strings
) const
2832 for ( i
=0; i
< strings
.size(); i
++ )
2834 int index
= Index(strings
[i
]);
2836 arr
.Add(GetValue(index
));
2838 arr
.Add(wxPG_INVALID_VALUE
);
2845 // -----------------------------------------------------------------------
2847 wxArrayInt wxPGChoices
::GetIndicesForStrings( const wxArrayString
& strings
,
2848 wxArrayString
* unmatched
) const
2855 for ( i
=0; i
< strings
.size(); i
++ )
2857 const wxString
& str
= strings
[i
];
2858 int index
= Index(str
);
2861 else if ( unmatched
)
2862 unmatched
->Add(str
);
2869 // -----------------------------------------------------------------------
2871 void wxPGChoices
::AllocExclusive()
2875 if ( m_data
->GetRefCount() != 1 )
2877 wxPGChoicesData
* data
= new wxPGChoicesData();
2878 data
->CopyDataFrom(m_data
);
2884 // -----------------------------------------------------------------------
2886 void wxPGChoices
::AssignData( wxPGChoicesData
* data
)
2890 if ( data
!= wxPGChoicesEmptyData
)
2897 // -----------------------------------------------------------------------
2899 void wxPGChoices
::Init()
2901 m_data
= wxPGChoicesEmptyData
;
2904 // -----------------------------------------------------------------------
2906 void wxPGChoices
::Free()
2908 if ( m_data
!= wxPGChoicesEmptyData
)
2911 m_data
= wxPGChoicesEmptyData
;
2915 // -----------------------------------------------------------------------
2916 // wxPGAttributeStorage
2917 // -----------------------------------------------------------------------
2919 wxPGAttributeStorage
::wxPGAttributeStorage()
2923 wxPGAttributeStorage
::~wxPGAttributeStorage()
2925 wxPGHashMapS2P
::iterator it
;
2927 for ( it
= m_map
.begin(); it
!= m_map
.end(); ++it
)
2929 wxVariantData
* data
= (wxVariantData
*) it
->second
;
2934 void wxPGAttributeStorage
::Set( const wxString
& name
, const wxVariant
& value
)
2936 wxVariantData
* data
= value
.GetData();
2939 wxPGHashMapS2P
::iterator it
= m_map
.find(name
);
2940 if ( it
!= m_map
.end() )
2942 ((wxVariantData
*)it
->second
)->DecRef();
2946 // If Null variant, just remove from set
2960 #endif // wxUSE_PROPGRID