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 dc
.SetPen(cell
.GetBgCol());
139 dc
.SetBrush(cell
.GetBgCol());
142 if ( !(flags
& DontUseCellFgCol
) )
144 dc
.SetTextForeground(cell
.GetFgCol());
147 // Draw Background, but only if not rendering in control
148 // (as control already has rendered correct background).
149 if ( !(flags
& (Control
|ChoicePopup
)) )
150 dc
.DrawRectangle(rect
);
152 // Use cell font, if provided
153 const wxFont
& font
= cell
.GetFont();
157 const wxBitmap
& bmp
= cell
.GetBitmap();
159 // Do not draw oversized bitmap outside choice popup
160 ((flags
& ChoicePopup
) || bmp
.GetHeight() < rect
.height
)
164 rect
.x
+ wxPG_CONTROL_MARGIN
+ wxCC_CUSTOM_IMAGE_MARGIN1
,
165 rect
.y
+ wxPG_CUSTOM_IMAGE_SPACINGY
,
167 imageWidth
= bmp
.GetWidth();
173 void wxPGCellRenderer::PostDrawCell( wxDC
& dc
,
174 const wxPropertyGrid
* propGrid
,
175 const wxPGCell
& cell
,
176 int WXUNUSED(flags
) ) const
179 const wxFont
& font
= cell
.GetFont();
181 dc
.SetFont(propGrid
->GetFont());
184 // -----------------------------------------------------------------------
185 // wxPGDefaultRenderer
186 // -----------------------------------------------------------------------
188 void wxPGDefaultRenderer::Render( wxDC
& dc
, const wxRect
& rect
,
189 const wxPropertyGrid
* propertyGrid
, wxPGProperty
* property
,
190 int column
, int item
, int flags
) const
192 bool isUnspecified
= property
->IsValueUnspecified();
194 if ( column
== 1 && item
== -1 )
196 int cmnVal
= property
->GetCommonValue();
200 if ( !isUnspecified
)
201 DrawText( dc
, rect
, 0, propertyGrid
->GetCommonValueLabel(cmnVal
) );
206 const wxPGEditor
* editor
= NULL
;
207 const wxPGCell
* cell
= NULL
;
211 int preDrawFlags
= flags
;
213 property
->GetDisplayInfo(column
, item
, flags
, &text
, &cell
);
215 imageWidth
= PreDrawCell( dc
, rect
, *cell
, preDrawFlags
);
219 if ( !isUnspecified
)
221 editor
= property
->GetColumnEditor(column
);
223 // Regular property value
225 wxSize imageSize
= propertyGrid
->GetImageSize(property
, item
);
227 wxPGPaintData paintdata
;
228 paintdata
.m_parent
= propertyGrid
;
229 paintdata
.m_choiceItem
= item
;
231 if ( imageSize
.x
> 0 )
233 wxRect
imageRect(rect
.x
+ wxPG_CONTROL_MARGIN
+ wxCC_CUSTOM_IMAGE_MARGIN1
,
234 rect
.y
+wxPG_CUSTOM_IMAGE_SPACINGY
,
235 wxPG_CUSTOM_IMAGE_WIDTH
,
236 rect
.height
-(wxPG_CUSTOM_IMAGE_SPACINGY
*2));
238 dc
.SetPen( wxPen(propertyGrid
->GetCellTextColour(), 1, wxSOLID
) );
240 paintdata
.m_drawnWidth
= imageSize
.x
;
241 paintdata
.m_drawnHeight
= imageSize
.y
;
243 property
->OnCustomPaint( dc
, imageRect
, paintdata
);
245 imageWidth
= paintdata
.m_drawnWidth
;
248 text
= property
->GetValueAsString();
251 if ( propertyGrid
->GetColumnCount() <= 2 )
253 wxString unitsString
= property
->GetAttribute(wxPGGlobalVars
->m_strUnits
, wxEmptyString
);
254 if ( unitsString
.length() )
255 text
= wxString::Format(wxS("%s %s"), text
.c_str(), unitsString
.c_str() );
259 if ( text
.length() == 0 )
261 // Try to show inline help if no text
262 wxVariant vInlineHelp
= property
->GetAttribute(wxPGGlobalVars
->m_strInlineHelp
);
263 if ( !vInlineHelp
.IsNull() )
265 text
= vInlineHelp
.GetString();
266 dc
.SetTextForeground(propertyGrid
->GetCellDisabledTextColour());
271 int imageOffset
= property
->GetImageOffset(imageWidth
);
273 DrawEditorValue( dc
, rect
, imageOffset
, text
, property
, editor
);
275 // active caption gets nice dotted rectangle
276 if ( property
->IsCategory() /*&& column == 0*/ )
278 if ( flags
& Selected
)
280 if ( imageOffset
> 0 )
282 imageOffset
-= DEFAULT_IMAGE_OFFSET_INCREMENT
;
283 imageOffset
+= wxCC_CUSTOM_IMAGE_MARGIN2
+ 4;
286 DrawCaptionSelectionRect( dc
,
287 rect
.x
+wxPG_XBEFORETEXT
-wxPG_CAPRECTXMARGIN
+imageOffset
,
288 rect
.y
-wxPG_CAPRECTYMARGIN
+1,
289 ((wxPropertyCategory
*)property
)->GetTextExtent(propertyGrid
,
290 propertyGrid
->GetCaptionFont())
291 +(wxPG_CAPRECTXMARGIN
*2),
292 propertyGrid
->GetFontHeight()+(wxPG_CAPRECTYMARGIN
*2) );
296 PostDrawCell(dc
, propertyGrid
, *cell
, preDrawFlags
);
299 wxSize
wxPGDefaultRenderer::GetImageSize( const wxPGProperty
* property
,
303 if ( property
&& column
== 1 )
307 wxBitmap
* bmp
= property
->GetValueImage();
309 if ( bmp
&& bmp
->Ok() )
310 return wxSize(bmp
->GetWidth(),bmp
->GetHeight());
316 // -----------------------------------------------------------------------
318 // -----------------------------------------------------------------------
320 wxPGCellData::wxPGCellData()
323 m_hasValidText
= false;
326 // -----------------------------------------------------------------------
328 // -----------------------------------------------------------------------
335 wxPGCell::wxPGCell( const wxString
& text
,
336 const wxBitmap
& bitmap
,
337 const wxColour
& fgCol
,
338 const wxColour
& bgCol
)
341 wxPGCellData
* data
= new wxPGCellData();
344 data
->m_bitmap
= bitmap
;
345 data
->m_fgCol
= fgCol
;
346 data
->m_bgCol
= bgCol
;
347 data
->m_hasValidText
= true;
350 wxObjectRefData
*wxPGCell::CloneRefData( const wxObjectRefData
*data
) const
352 wxPGCellData
* c
= new wxPGCellData();
353 const wxPGCellData
* o
= (const wxPGCellData
*) data
;
354 c
->m_text
= o
->m_text
;
355 c
->m_bitmap
= o
->m_bitmap
;
356 c
->m_fgCol
= o
->m_fgCol
;
357 c
->m_bgCol
= o
->m_bgCol
;
358 c
->m_hasValidText
= o
->m_hasValidText
;
362 void wxPGCell::SetText( const wxString
& text
)
366 GetData()->SetText(text
);
369 void wxPGCell::SetBitmap( const wxBitmap
& bitmap
)
373 GetData()->SetBitmap(bitmap
);
376 void wxPGCell::SetFgCol( const wxColour
& col
)
380 GetData()->SetFgCol(col
);
383 void wxPGCell::SetFont( const wxFont
& font
)
387 GetData()->SetFont(font
);
390 void wxPGCell::SetBgCol( const wxColour
& col
)
394 GetData()->SetBgCol(col
);
397 void wxPGCell::MergeFrom( const wxPGCell
& srcCell
)
401 wxPGCellData
* data
= GetData();
403 if ( srcCell
.HasText() )
404 data
->SetText(srcCell
.GetText());
406 if ( srcCell
.GetFgCol().IsOk() )
407 data
->SetFgCol(srcCell
.GetFgCol());
409 if ( srcCell
.GetBgCol().IsOk() )
410 data
->SetBgCol(srcCell
.GetBgCol());
412 if ( srcCell
.GetBitmap().IsOk() )
413 data
->SetBitmap(srcCell
.GetBitmap());
416 // -----------------------------------------------------------------------
418 // -----------------------------------------------------------------------
420 IMPLEMENT_ABSTRACT_CLASS(wxPGProperty
, wxObject
)
422 wxString
* wxPGProperty::sm_wxPG_LABEL
= NULL
;
424 void wxPGProperty::Init()
430 m_parentState
= NULL
;
433 m_clientObject
= NULL
;
435 m_customEditor
= NULL
;
439 m_valueBitmap
= NULL
;
441 m_maxLen
= 0; // infinite maximum length
443 m_flags
= wxPG_PROP_PROPERTY
;
451 void wxPGProperty::Init( const wxString
& label
, const wxString
& name
)
453 // We really need to check if &label and &name are NULL pointers
454 // (this can if we are called before property grid has been initalized)
456 if ( (&label
) != NULL
&& label
!= wxPG_LABEL
)
459 if ( (&name
) != NULL
&& name
!= wxPG_LABEL
)
462 DoSetName( m_label
);
467 void wxPGProperty::InitAfterAdded( wxPropertyGridPageState
* pageState
,
468 wxPropertyGrid
* propgrid
)
471 // Called after property has been added to grid or page
472 // (so propgrid can be NULL, too).
474 wxPGProperty
* parent
= m_parent
;
475 bool parentIsRoot
= parent
->IsKindOf(CLASSINFO(wxPGRootProperty
));
477 m_parentState
= pageState
;
479 #if wxPG_COMPATIBILITY_1_4
480 // Make sure deprecated virtual functions are not implemented
481 wxString s
= GetValueAsString( 0xFFFF );
482 wxASSERT_MSG( s
== g_invalidStringContent
,
483 "Implement ValueToString() instead of GetValueAsString()" );
486 if ( !parentIsRoot
&& !parent
->IsCategory() )
488 m_cells
= parent
->m_cells
;
491 // If in hideable adding mode, or if assigned parent is hideable, then
492 // make this one hideable.
494 ( !parentIsRoot
&& parent
->HasFlag(wxPG_PROP_HIDDEN
) ) ||
495 ( propgrid
&& (propgrid
->HasInternalFlag(wxPG_FL_ADDING_HIDEABLES
)) )
497 SetFlag( wxPG_PROP_HIDDEN
);
499 // Set custom image flag.
500 int custImgHeight
= OnMeasureImage().y
;
501 if ( custImgHeight
< 0 )
503 SetFlag(wxPG_PROP_CUSTOMIMAGE
);
506 if ( propgrid
&& (propgrid
->HasFlag(wxPG_LIMITED_EDITING
)) )
507 SetFlag(wxPG_PROP_NOEDITOR
);
509 // Make sure parent has some parental flags
510 if ( !parent
->HasFlag(wxPG_PROP_PARENTAL_FLAGS
) )
511 parent
->SetParentalType(wxPG_PROP_MISC_PARENT
);
515 // This is not a category.
519 unsigned char depth
= 1;
522 depth
= parent
->m_depth
;
523 if ( !parent
->IsCategory() )
527 unsigned char greyDepth
= depth
;
531 wxPropertyCategory
* pc
;
533 if ( parent
->IsCategory() )
534 pc
= (wxPropertyCategory
* ) parent
;
536 // This conditional compile is necessary to
537 // bypass some compiler bug.
538 pc
= pageState
->GetPropertyCategory(parent
);
541 greyDepth
= pc
->GetDepth();
543 greyDepth
= parent
->m_depthBgCol
;
546 m_depthBgCol
= greyDepth
;
550 // This is a category.
553 unsigned char depth
= 1;
556 depth
= parent
->m_depth
+ 1;
559 m_depthBgCol
= depth
;
563 // Has initial children
564 if ( GetChildCount() )
566 // Check parental flags
567 wxASSERT_MSG( ((m_flags
& wxPG_PROP_PARENTAL_FLAGS
) ==
568 wxPG_PROP_AGGREGATE
) ||
569 ((m_flags
& wxPG_PROP_PARENTAL_FLAGS
) ==
570 wxPG_PROP_MISC_PARENT
),
571 "wxPGProperty parental flags set incorrectly at "
574 if ( HasFlag(wxPG_PROP_AGGREGATE
) )
576 // Properties with private children are not expanded by default.
579 else if ( propgrid
&& propgrid
->HasFlag(wxPG_HIDE_MARGIN
) )
581 // ...unless it cannot be expanded by user and therefore must
582 // remain visible at all times
587 // Prepare children recursively
588 for ( unsigned int i
=0; i
<GetChildCount(); i
++ )
590 wxPGProperty
* child
= Item(i
);
591 child
->InitAfterAdded(pageState
, pageState
->GetGrid());
594 if ( propgrid
&& (propgrid
->GetExtraStyle() & wxPG_EX_AUTO_UNSPECIFIED_VALUES
) )
595 SetFlagRecursively(wxPG_PROP_AUTO_UNSPECIFIED
, true);
599 wxPGProperty::wxPGProperty()
606 wxPGProperty::wxPGProperty( const wxString
& label
, const wxString
& name
)
613 wxPGProperty::~wxPGProperty()
615 delete m_clientObject
;
617 Empty(); // this deletes items
619 delete m_valueBitmap
;
624 // This makes it easier for us to detect dangling pointers
629 bool wxPGProperty::IsSomeParent( wxPGProperty
* candidate
) const
631 wxPGProperty
* parent
= m_parent
;
634 if ( parent
== candidate
)
636 parent
= parent
->m_parent
;
641 void wxPGProperty::SetName( const wxString
& newName
)
643 wxPropertyGrid
* pg
= GetGrid();
646 pg
->SetPropertyName(this, newName
);
651 wxString
wxPGProperty::GetName() const
653 wxPGProperty
* parent
= GetParent();
655 if ( !m_name
.length() || !parent
|| parent
->IsCategory() || parent
->IsRoot() )
658 return m_parent
->GetName() + wxS(".") + m_name
;
661 wxPropertyGrid
* wxPGProperty::GetGrid() const
663 if ( !m_parentState
)
665 return m_parentState
->GetGrid();
668 int wxPGProperty::Index( const wxPGProperty
* p
) const
670 for ( unsigned int i
= 0; i
<m_children
.size(); i
++ )
672 if ( p
== m_children
[i
] )
678 bool wxPGProperty::ValidateValue( wxVariant
& WXUNUSED(value
), wxPGValidationInfo
& WXUNUSED(validationInfo
) ) const
683 void wxPGProperty::OnSetValue()
687 void wxPGProperty::RefreshChildren ()
691 void wxPGProperty::OnValidationFailure( wxVariant
& WXUNUSED(pendingValue
) )
695 void wxPGProperty::GetDisplayInfo( unsigned int column
,
699 const wxPGCell
** pCell
)
701 const wxPGCell
* cell
= NULL
;
703 if ( !(flags
& wxPGCellRenderer::ChoicePopup
) )
705 // Not painting listi of choice popups, so get text from property
706 cell
= &GetCell(column
);
707 if ( cell
->HasText() )
709 *pString
= cell
->GetText();
714 *pString
= GetLabel();
715 else if ( column
== 1 )
716 *pString
= GetDisplayedString();
717 else if ( column
== 2 )
718 *pString
= GetAttribute(wxPGGlobalVars
->m_strUnits
, wxEmptyString
);
723 wxASSERT( column
== 1 );
725 if ( choiceIndex
!= wxNOT_FOUND
)
727 const wxPGChoiceEntry
& entry
= m_choices
[choiceIndex
];
728 if ( entry
.GetBitmap().IsOk() ||
729 entry
.GetFgCol().IsOk() ||
730 entry
.GetBgCol().IsOk() )
732 *pString
= m_choices
.GetLabel(choiceIndex
);
737 cell
= &GetCell(column
);
739 wxASSERT_MSG( cell
->GetData(),
740 wxString::Format("Invalid cell for property %s",
741 GetName().c_str()) );
747 wxString wxPGProperty::GetColumnText( unsigned int col, int choiceIndex ) const
750 if ( col != 1 || choiceIndex == wxNOT_FOUND )
752 const wxPGCell& cell = GetCell(col);
753 if ( cell->HasText() )
755 return cell->GetText();
762 return GetDisplayedString();
764 return GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString);
770 return m_choices.GetLabel(choiceIndex);
773 return wxEmptyString;
777 void wxPGProperty::DoGenerateComposedValue( wxString
& text
,
779 const wxVariantList
* valueOverrides
,
780 wxPGHashMapS2S
* childResults
) const
783 int iMax
= m_children
.size();
789 if ( iMax
> PWC_CHILD_SUMMARY_LIMIT
&&
790 !(argFlags
& wxPG_FULL_VALUE
) )
791 iMax
= PWC_CHILD_SUMMARY_LIMIT
;
793 int iMaxMinusOne
= iMax
-1;
795 if ( !IsTextEditable() )
796 argFlags
|= wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
;
798 wxPGProperty
* curChild
= m_children
[0];
800 bool overridesLeft
= false;
801 wxVariant overrideValue
;
802 wxVariantList::const_iterator node
;
804 if ( valueOverrides
)
806 node
= valueOverrides
->begin();
807 if ( node
!= valueOverrides
->end() )
809 overrideValue
= *node
;
810 overridesLeft
= true;
814 for ( i
= 0; i
< iMax
; i
++ )
816 wxVariant childValue
;
818 wxString childLabel
= curChild
->GetLabel();
820 // Check for value override
821 if ( overridesLeft
&& overrideValue
.GetName() == childLabel
)
823 if ( !overrideValue
.IsNull() )
824 childValue
= overrideValue
;
826 childValue
= curChild
->GetValue();
828 if ( node
!= valueOverrides
->end() )
829 overrideValue
= *node
;
831 overridesLeft
= false;
835 childValue
= curChild
->GetValue();
839 if ( !childValue
.IsNull() )
841 if ( overridesLeft
&&
842 curChild
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) &&
843 childValue
.GetType() == wxPG_VARIANT_TYPE_LIST
)
845 wxVariantList
& childList
= childValue
.GetList();
846 DoGenerateComposedValue(s
, argFlags
|wxPG_COMPOSITE_FRAGMENT
,
847 &childList
, childResults
);
851 s
= curChild
->ValueToString(childValue
,
852 argFlags
|wxPG_COMPOSITE_FRAGMENT
);
856 if ( childResults
&& curChild
->GetChildCount() )
857 (*childResults
)[curChild
->GetName()] = s
;
860 if ( (argFlags
& wxPG_UNEDITABLE_COMPOSITE_FRAGMENT
) && !s
.length() )
863 if ( !curChild
->GetChildCount() || skip
)
866 text
+= wxS("[") + s
+ wxS("]");
868 if ( i
< iMaxMinusOne
)
870 if ( text
.length() > PWC_CHILD_SUMMARY_CHAR_LIMIT
&&
871 !(argFlags
& wxPG_EDITABLE_VALUE
) &&
872 !(argFlags
& wxPG_FULL_VALUE
) )
877 if ( !curChild
->GetChildCount() )
883 curChild
= m_children
[i
+1];
887 if ( (unsigned int)i
< m_children
.size() )
889 if ( !text
.EndsWith(wxS("; ")) )
890 text
+= wxS("; ...");
896 wxString
wxPGProperty::ValueToString( wxVariant
& WXUNUSED(value
),
899 wxCHECK_MSG( GetChildCount() > 0,
901 "If user property does not have any children, it must "
902 "override GetValueAsString" );
904 // FIXME: Currently code below only works if value is actually m_value
905 wxASSERT_MSG( argFlags
& wxPG_VALUE_IS_CURRENT
,
906 "Sorry, currently default wxPGProperty::ValueToString() "
907 "implementation only works if value is m_value." );
910 DoGenerateComposedValue(text
, argFlags
);
914 wxString
wxPGProperty::GetValueAsString( int argFlags
) const
916 #if wxPG_COMPATIBILITY_1_4
917 // This is backwards compatibility test
918 // That is, to make sure this function is not overridden
919 // (instead, ValueToString() should be).
920 if ( argFlags
== 0xFFFF )
922 // Do not override! (for backwards compliancy)
923 return g_invalidStringContent
;
927 if ( IsValueUnspecified() )
928 return wxEmptyString
;
930 if ( m_commonValue
== -1 )
932 wxVariant
value(GetValue());
933 return ValueToString(value
, argFlags
|wxPG_VALUE_IS_CURRENT
);
937 // Return common value's string representation
938 wxPropertyGrid
* pg
= GetGrid();
939 const wxPGCommonValue
* cv
= pg
->GetCommonValue(m_commonValue
);
941 if ( argFlags
& wxPG_FULL_VALUE
)
943 return cv
->GetLabel();
945 else if ( argFlags
& wxPG_EDITABLE_VALUE
)
947 return cv
->GetEditableText();
951 return cv
->GetLabel();
955 wxString
wxPGProperty::GetValueString( int argFlags
) const
957 return GetValueAsString(argFlags
);
960 bool wxPGProperty::IntToValue( wxVariant
& variant
, int number
, int WXUNUSED(argFlags
) ) const
962 variant
= (long)number
;
966 // Convert semicolon delimited tokens into child values.
967 bool wxPGProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int argFlags
) const
969 if ( !GetChildCount() )
972 unsigned int curChild
= 0;
974 unsigned int iMax
= m_children
.size();
976 if ( iMax
> PWC_CHILD_SUMMARY_LIMIT
&&
977 !(argFlags
& wxPG_FULL_VALUE
) )
978 iMax
= PWC_CHILD_SUMMARY_LIMIT
;
980 bool changed
= false;
985 // Its best only to add non-empty group items
986 bool addOnlyIfNotEmpty
= false;
987 const wxChar delimeter
= wxS(';');
989 size_t tokenStart
= 0xFFFFFF;
991 wxVariantList temp_list
;
992 wxVariant
list(temp_list
);
994 int propagatedFlags
= argFlags
& (wxPG_REPORT_ERROR
|wxPG_PROGRAMMATIC_VALUE
);
996 wxLogTrace("propgrid",
997 wxT(">> %s.StringToValue('%s')"), GetLabel(), text
);
999 wxString::const_iterator it
= text
.begin();
1002 if ( it
!= text
.end() )
1009 // How many units we iterate string forward at the end of loop?
1010 // We need to keep track of this or risk going to negative
1011 // with it-- operation.
1012 unsigned int strPosIncrement
= 1;
1014 if ( tokenStart
!= 0xFFFFFF )
1017 if ( a
== delimeter
|| a
== 0 )
1019 token
= text
.substr(tokenStart
,pos
-tokenStart
);
1021 size_t len
= token
.length();
1023 if ( !addOnlyIfNotEmpty
|| len
> 0 )
1025 const wxPGProperty
* child
= Item(curChild
);
1026 wxVariant
variant(child
->GetValue());
1027 wxString childName
= child
->GetBaseName();
1029 wxLogTrace("propgrid",
1030 wxT("token = '%s', child = %s"),
1033 // Add only if editable or setting programmatically
1034 if ( (argFlags
& wxPG_PROGRAMMATIC_VALUE
) ||
1035 !child
->HasFlag(wxPG_PROP_DISABLED
|wxPG_PROP_READONLY
) )
1039 if ( child
->StringToValue(variant
, token
,
1040 propagatedFlags
|wxPG_COMPOSITE_FRAGMENT
) )
1042 // We really need to set the variant's name
1043 // *after* child->StringToValue() has been
1044 // called, since variant's value may be set by
1045 // assigning another variant into it, which
1046 // then usually causes name to be copied (ie.
1047 // usually cleared) as well. wxBoolProperty
1048 // being case in point with its use of
1049 // wxPGVariant_Bool macro as an optimization.
1050 variant
.SetName(childName
);
1051 list
.Append(variant
);
1058 // Empty, becomes unspecified
1060 variant
.SetName(childName
);
1061 list
.Append(variant
);
1067 if ( curChild
>= iMax
)
1071 tokenStart
= 0xFFFFFF;
1076 // Token is not running
1077 if ( a
!= wxS(' ') )
1080 addOnlyIfNotEmpty
= false;
1082 // Is this a group of tokens?
1083 if ( a
== wxS('[') )
1087 if ( it
!= text
.end() ) ++it
;
1089 size_t startPos
= pos
;
1091 // Group item - find end
1092 while ( it
!= text
.end() && depth
> 0 )
1098 if ( a
== wxS(']') )
1100 else if ( a
== wxS('[') )
1104 token
= text
.substr(startPos
,pos
-startPos
-1);
1106 if ( !token
.length() )
1109 const wxPGProperty
* child
= Item(curChild
);
1111 wxVariant oldChildValue
= child
->GetValue();
1112 wxVariant
variant(oldChildValue
);
1114 if ( (argFlags
& wxPG_PROGRAMMATIC_VALUE
) ||
1115 !child
->HasFlag(wxPG_PROP_DISABLED
|wxPG_PROP_READONLY
) )
1117 wxString childName
= child
->GetBaseName();
1119 bool stvRes
= child
->StringToValue( variant
, token
,
1121 if ( stvRes
|| (variant
!= oldChildValue
) )
1123 variant
.SetName(childName
);
1124 list
.Append(variant
);
1135 if ( curChild
>= iMax
)
1138 addOnlyIfNotEmpty
= true;
1140 tokenStart
= 0xFFFFFF;
1146 if ( a
== delimeter
)
1147 strPosIncrement
-= 1;
1155 it
+= strPosIncrement
;
1157 if ( it
!= text
.end() )
1166 pos
+= strPosIncrement
;
1175 bool wxPGProperty::SetValueFromString( const wxString
& text
, int argFlags
)
1177 wxVariant
variant(m_value
);
1178 bool res
= StringToValue(variant
, text
, argFlags
);
1184 bool wxPGProperty::SetValueFromInt( long number
, int argFlags
)
1186 wxVariant
variant(m_value
);
1187 bool res
= IntToValue(variant
, number
, argFlags
);
1193 wxSize
wxPGProperty::OnMeasureImage( int WXUNUSED(item
) ) const
1195 if ( m_valueBitmap
)
1196 return wxSize(m_valueBitmap
->GetWidth(),-1);
1201 int wxPGProperty::GetImageOffset( int imageWidth
) const
1203 int imageOffset
= 0;
1207 // Do not increment offset too much for wide images
1208 if ( imageWidth
<= (wxPG_CUSTOM_IMAGE_WIDTH
+5) )
1209 imageOffset
= imageWidth
+ DEFAULT_IMAGE_OFFSET_INCREMENT
;
1211 imageOffset
= imageWidth
+ 1;
1217 wxPGCellRenderer
* wxPGProperty::GetCellRenderer( int WXUNUSED(column
) ) const
1219 return wxPGGlobalVars
->m_defaultRenderer
;
1222 void wxPGProperty::OnCustomPaint( wxDC
& dc
,
1226 wxBitmap
* bmp
= m_valueBitmap
;
1228 wxCHECK_RET( bmp
&& bmp
->Ok(), wxT("invalid bitmap") );
1230 wxCHECK_RET( rect
.x
>= 0, wxT("unexpected measure call") );
1232 dc
.DrawBitmap(*bmp
,rect
.x
,rect
.y
);
1235 const wxPGEditor
* wxPGProperty::DoGetEditorClass() const
1237 return wxPGEditor_TextCtrl
;
1240 // Default extra property event handling - that is, none at all.
1241 bool wxPGProperty::OnEvent( wxPropertyGrid
*, wxWindow
*, wxEvent
& )
1247 void wxPGProperty::SetValue( wxVariant value
, wxVariant
* pList
, int flags
)
1249 // If auto unspecified values are not wanted (via window or property style),
1250 // then get default value instead of wxNullVariant.
1251 if ( value
.IsNull() && (flags
& wxPG_SETVAL_BY_USER
) &&
1252 !UsesAutoUnspecified() )
1254 value
= GetDefaultValue();
1257 if ( !value
.IsNull() )
1259 wxVariant tempListVariant
;
1262 // List variants are reserved a special purpose
1263 // as intermediate containers for child values
1264 // of properties with children.
1265 if ( value
.GetType() == wxPG_VARIANT_TYPE_LIST
)
1268 // However, situation is different for composed string properties
1269 if ( HasFlag(wxPG_PROP_COMPOSED_VALUE
) )
1271 tempListVariant
= value
;
1272 pList
= &tempListVariant
;
1276 AdaptListToValue(value
, &newValue
);
1278 //wxLogDebug(wxT(">> %s.SetValue() adapted list value to type '%s'"),GetName().c_str(),value.GetType().c_str());
1281 if ( HasFlag( wxPG_PROP_AGGREGATE
) )
1282 flags
|= wxPG_SETVAL_AGGREGATED
;
1284 if ( pList
&& !pList
->IsNull() )
1286 wxASSERT( pList
->GetType() == wxPG_VARIANT_TYPE_LIST
);
1287 wxASSERT( GetChildCount() );
1288 wxASSERT( !IsCategory() );
1290 wxVariantList
& list
= pList
->GetList();
1291 wxVariantList::iterator node
;
1294 //wxLogDebug(wxT(">> %s.SetValue() pList parsing"),GetName().c_str());
1296 // Children in list can be in any order, but we will give hint to
1297 // GetPropertyByNameWH(). This optimizes for full list parsing.
1298 for ( node
= list
.begin(); node
!= list
.end(); ++node
)
1300 wxVariant
& childValue
= *((wxVariant
*)*node
);
1301 wxPGProperty
* child
= GetPropertyByNameWH(childValue
.GetName(), i
);
1304 //wxLogDebug(wxT("%i: child = %s, childValue.GetType()=%s"),i,child->GetBaseName().c_str(),childValue.GetType().c_str());
1305 if ( childValue
.GetType() == wxPG_VARIANT_TYPE_LIST
)
1307 if ( child
->HasFlag(wxPG_PROP_AGGREGATE
) && !(flags
& wxPG_SETVAL_AGGREGATED
) )
1309 wxVariant listRefCopy
= childValue
;
1310 child
->SetValue(childValue
, &listRefCopy
, flags
|wxPG_SETVAL_FROM_PARENT
);
1314 wxVariant oldVal
= child
->GetValue();
1315 child
->SetValue(oldVal
, &childValue
, flags
|wxPG_SETVAL_FROM_PARENT
);
1318 else if ( child
->GetValue() != childValue
)
1320 // For aggregate properties, we will trust RefreshChildren()
1321 // to update child values.
1322 if ( !HasFlag(wxPG_PROP_AGGREGATE
) )
1323 child
->SetValue(childValue
, NULL
, flags
|wxPG_SETVAL_FROM_PARENT
);
1324 if ( flags
& wxPG_SETVAL_BY_USER
)
1325 child
->SetFlag(wxPG_PROP_MODIFIED
);
1332 if ( !value
.IsNull() )
1338 if ( flags
& wxPG_SETVAL_BY_USER
)
1339 SetFlag(wxPG_PROP_MODIFIED
);
1341 if ( HasFlag(wxPG_PROP_AGGREGATE
) )
1346 if ( m_commonValue
!= -1 )
1348 wxPropertyGrid
* pg
= GetGrid();
1349 if ( !pg
|| m_commonValue
!= pg
->GetUnspecifiedCommonValue() )
1355 // Set children to unspecified, but only if aggregate or
1356 // value is <composed>
1357 if ( AreChildrenComponents() )
1360 for ( i
=0; i
<GetChildCount(); i
++ )
1361 Item(i
)->SetValue(value
, NULL
, flags
|wxPG_SETVAL_FROM_PARENT
);
1365 if ( !(flags
& wxPG_SETVAL_FROM_PARENT
) )
1366 UpdateParentValues();
1369 // Update editor control
1372 // We need to check for these, otherwise GetGrid() may fail.
1373 if ( flags
& wxPG_SETVAL_REFRESH_EDITOR
)
1376 wxPropertyGrid
* pg
= GetGridIfDisplayed();
1378 pg
->DrawItemAndValueRelated(this);
1383 void wxPGProperty::SetValueInEvent( wxVariant value
) const
1385 GetGrid()->ValueChangeInEvent(value
);
1388 void wxPGProperty::SetFlagRecursively( FlagType flag
, bool set
)
1390 ChangeFlag(flag
, set
);
1393 for ( i
= 0; i
< GetChildCount(); i
++ )
1394 Item(i
)->SetFlagRecursively(flag
, set
);
1397 void wxPGProperty::RefreshEditor()
1402 wxPropertyGrid
* pg
= GetGrid();
1403 if ( pg
&& pg
->GetSelectedProperty() == this )
1404 pg
->RefreshEditor();
1407 wxVariant
wxPGProperty::GetDefaultValue() const
1409 wxVariant defVal
= GetAttribute(wxPG_ATTR_DEFAULT_VALUE
);
1410 if ( !defVal
.IsNull() )
1413 wxVariant value
= GetValue();
1415 if ( !value
.IsNull() )
1417 wxString
valueType(value
.GetType());
1419 if ( valueType
== wxPG_VARIANT_TYPE_LONG
)
1420 return wxPGVariant_Zero
;
1421 if ( valueType
== wxPG_VARIANT_TYPE_STRING
)
1422 return wxPGVariant_EmptyString
;
1423 if ( valueType
== wxPG_VARIANT_TYPE_BOOL
)
1424 return wxPGVariant_False
;
1425 if ( valueType
== wxPG_VARIANT_TYPE_DOUBLE
)
1426 return wxVariant(0.0);
1427 if ( valueType
== wxPG_VARIANT_TYPE_ARRSTRING
)
1428 return wxVariant(wxArrayString());
1429 if ( valueType
== wxS("wxLongLong") )
1430 return WXVARIANT(wxLongLong(0));
1431 if ( valueType
== wxS("wxULongLong") )
1432 return WXVARIANT(wxULongLong(0));
1433 if ( valueType
== wxS("wxColour") )
1434 return WXVARIANT(*wxBLACK
);
1436 if ( valueType
== wxPG_VARIANT_TYPE_DATETIME
)
1437 return wxVariant(wxDateTime::Now());
1439 if ( valueType
== wxS("wxFont") )
1440 return WXVARIANT(*wxNORMAL_FONT
);
1441 if ( valueType
== wxS("wxPoint") )
1442 return WXVARIANT(wxPoint(0, 0));
1443 if ( valueType
== wxS("wxSize") )
1444 return WXVARIANT(wxSize(0, 0));
1450 void wxPGProperty::EnsureCells( unsigned int column
)
1452 if ( column
>= m_cells
.size() )
1454 // Fill empty slots with default cells
1455 wxPropertyGrid
* pg
= GetGrid();
1456 wxPGCell defaultCell
;
1458 // Work around possible VC6 bug by using intermediate variables
1459 const wxPGCell
& propDefCell
= pg
->GetPropertyDefaultCell();
1460 const wxPGCell
& catDefCell
= pg
->GetCategoryDefaultCell();
1462 if ( !HasFlag(wxPG_PROP_CATEGORY
) )
1463 defaultCell
= propDefCell
;
1465 defaultCell
= catDefCell
;
1467 // TODO: Replace with resize() call
1468 unsigned int cellCountMax
= column
+1;
1470 for ( unsigned int i
=m_cells
.size(); i
<cellCountMax
; i
++ )
1471 m_cells
.push_back(defaultCell
);
1475 void wxPGProperty::SetCell( int column
,
1476 const wxPGCell
& cell
)
1478 EnsureCells(column
);
1480 m_cells
[column
] = cell
;
1483 void wxPGProperty::AdaptiveSetCell( unsigned int firstCol
,
1484 unsigned int lastCol
,
1485 const wxPGCell
& cell
,
1486 const wxPGCell
& srcData
,
1487 wxPGCellData
* unmodCellData
,
1488 FlagType ignoreWithFlags
,
1492 // Sets cell in memory optimizing fashion. That is, if
1493 // current cell data matches unmodCellData, we will
1494 // simply get reference to data from cell. Otherwise,
1495 // cell information from srcData is merged into current.
1498 if ( !(m_flags
& ignoreWithFlags
) && !IsRoot() )
1500 EnsureCells(lastCol
);
1502 for ( unsigned int col
=firstCol
; col
<=lastCol
; col
++ )
1504 if ( m_cells
[col
].GetData() == unmodCellData
)
1506 // Data matches... use cell directly
1507 m_cells
[col
] = cell
;
1511 // Data did not match... merge valid information
1512 m_cells
[col
].MergeFrom(srcData
);
1519 for ( unsigned int i
=0; i
<GetChildCount(); i
++ )
1520 Item(i
)->AdaptiveSetCell( firstCol
,
1530 const wxPGCell
& wxPGProperty::GetCell( unsigned int column
) const
1532 if ( m_cells
.size() > column
)
1533 return m_cells
[column
];
1535 wxPropertyGrid
* pg
= GetGrid();
1538 return pg
->GetCategoryDefaultCell();
1540 return pg
->GetPropertyDefaultCell();
1543 wxPGCell
& wxPGProperty::GetOrCreateCell( unsigned int column
)
1545 EnsureCells(column
);
1546 return m_cells
[column
];
1549 void wxPGProperty::SetBackgroundColour( const wxColour
& colour
,
1552 wxPGProperty
* firstProp
= this;
1555 // If category is tried to set recursively, skip it and only
1556 // affect the children.
1559 while ( firstProp
->IsCategory() )
1561 if ( !firstProp
->GetChildCount() )
1563 firstProp
= firstProp
->Item(0);
1567 wxPGCell
& firstCell
= firstProp
->GetCell(0);
1568 wxPGCellData
* firstCellData
= firstCell
.GetData();
1570 wxPGCell
newCell(firstCell
);
1571 newCell
.SetBgCol(colour
);
1573 srcCell
.SetBgCol(colour
);
1576 GetParentState()->GetColumnCount()-1,
1580 recursively
? wxPG_PROP_CATEGORY
: 0,
1584 void wxPGProperty::SetTextColour( const wxColour
& colour
,
1587 wxPGProperty
* firstProp
= this;
1590 // If category is tried to set recursively, skip it and only
1591 // affect the children.
1594 while ( firstProp
->IsCategory() )
1596 if ( !firstProp
->GetChildCount() )
1598 firstProp
= firstProp
->Item(0);
1602 wxPGCell
& firstCell
= firstProp
->GetCell(0);
1603 wxPGCellData
* firstCellData
= firstCell
.GetData();
1605 wxPGCell
newCell(firstCell
);
1606 newCell
.SetFgCol(colour
);
1608 srcCell
.SetFgCol(colour
);
1611 GetParentState()->GetColumnCount()-1,
1615 recursively
? wxPG_PROP_CATEGORY
: 0,
1619 wxPGEditorDialogAdapter
* wxPGProperty::GetEditorDialog() const
1624 bool wxPGProperty::DoSetAttribute( const wxString
& WXUNUSED(name
), wxVariant
& WXUNUSED(value
) )
1629 void wxPGProperty::SetAttribute( const wxString
& name
, wxVariant value
)
1631 if ( DoSetAttribute( name
, value
) )
1633 // Support working without grid, when possible
1634 if ( wxPGGlobalVars
->HasExtraStyle( wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES
) )
1638 m_attributes
.Set( name
, value
);
1641 void wxPGProperty::SetAttributes( const wxPGAttributeStorage
& attributes
)
1643 wxPGAttributeStorage::const_iterator it
= attributes
.StartIteration();
1646 while ( attributes
.GetNext(it
, variant
) )
1647 SetAttribute( variant
.GetName(), variant
);
1650 wxVariant
wxPGProperty::DoGetAttribute( const wxString
& WXUNUSED(name
) ) const
1656 wxVariant
wxPGProperty::GetAttribute( const wxString
& name
) const
1658 return m_attributes
.FindValue(name
);
1661 wxString
wxPGProperty::GetAttribute( const wxString
& name
, const wxString
& defVal
) const
1663 wxVariant variant
= m_attributes
.FindValue(name
);
1665 if ( !variant
.IsNull() )
1666 return variant
.GetString();
1671 long wxPGProperty::GetAttributeAsLong( const wxString
& name
, long defVal
) const
1673 wxVariant variant
= m_attributes
.FindValue(name
);
1675 if ( variant
.IsNull() )
1678 return variant
.GetLong();
1681 double wxPGProperty::GetAttributeAsDouble( const wxString
& name
, double defVal
) const
1683 wxVariant variant
= m_attributes
.FindValue(name
);
1685 if ( variant
.IsNull() )
1688 return variant
.GetDouble();
1691 wxVariant
wxPGProperty::GetAttributesAsList() const
1693 wxVariantList tempList
;
1694 wxVariant
v( tempList
, wxString::Format(wxS("@%s@attr"),m_name
.c_str()) );
1696 wxPGAttributeStorage::const_iterator it
= m_attributes
.StartIteration();
1699 while ( m_attributes
.GetNext(it
, variant
) )
1705 // Slots of utility flags are NULL
1706 const unsigned int gs_propFlagToStringSize
= 14;
1708 static const wxChar
* gs_propFlagToString
[gs_propFlagToStringSize
] = {
1725 wxString
wxPGProperty::GetFlagsAsString( FlagType flagsMask
) const
1728 int relevantFlags
= m_flags
& flagsMask
& wxPG_STRING_STORED_FLAGS
;
1732 for ( i
=0; i
<gs_propFlagToStringSize
; i
++ )
1734 if ( relevantFlags
& a
)
1736 const wxChar
* fs
= gs_propFlagToString
[i
];
1748 void wxPGProperty::SetFlagsFromString( const wxString
& str
)
1752 WX_PG_TOKENIZER1_BEGIN(str
, wxS('|'))
1754 for ( i
=0; i
<gs_propFlagToStringSize
; i
++ )
1756 const wxChar
* fs
= gs_propFlagToString
[i
];
1757 if ( fs
&& str
== fs
)
1763 WX_PG_TOKENIZER1_END()
1765 m_flags
= (m_flags
& ~wxPG_STRING_STORED_FLAGS
) | flags
;
1768 wxValidator
* wxPGProperty::DoGetValidator() const
1773 int wxPGProperty::InsertChoice( const wxString
& label
, int index
, int value
)
1775 wxPropertyGrid
* pg
= GetGrid();
1776 int sel
= GetChoiceSelection();
1780 if ( index
== wxNOT_FOUND
)
1781 index
= m_choices
.GetCount();
1786 m_choices
.Insert(label
, index
, value
);
1788 if ( sel
!= newSel
)
1789 SetChoiceSelection(newSel
);
1791 if ( this == pg
->GetSelection() )
1792 GetEditorClass()->InsertItem(pg
->GetEditorControl(),label
,index
);
1798 void wxPGProperty::DeleteChoice( int index
)
1800 wxPropertyGrid
* pg
= GetGrid();
1802 int sel
= GetChoiceSelection();
1805 // Adjust current value
1808 SetValueToUnspecified();
1811 else if ( index
< sel
)
1816 m_choices
.RemoveAt(index
);
1818 if ( sel
!= newSel
)
1819 SetChoiceSelection(newSel
);
1821 if ( this == pg
->GetSelection() )
1822 GetEditorClass()->DeleteItem(pg
->GetEditorControl(), index
);
1825 int wxPGProperty::GetChoiceSelection() const
1827 wxVariant value
= GetValue();
1828 wxString valueType
= value
.GetType();
1829 int index
= wxNOT_FOUND
;
1831 if ( IsValueUnspecified() || !m_choices
.GetCount() )
1834 if ( valueType
== wxPG_VARIANT_TYPE_LONG
)
1836 index
= value
.GetLong();
1838 else if ( valueType
== wxPG_VARIANT_TYPE_STRING
)
1840 index
= m_choices
.Index(value
.GetString());
1842 else if ( valueType
== wxPG_VARIANT_TYPE_BOOL
)
1844 index
= value
.GetBool()? 1 : 0;
1850 void wxPGProperty::SetChoiceSelection( int newValue
)
1852 // Changes value of a property with choices, but only
1853 // works if the value type is long or string.
1854 wxString valueType
= GetValue().GetType();
1856 wxCHECK_RET( m_choices
.IsOk(), wxT("invalid choiceinfo") );
1858 if ( valueType
== wxPG_VARIANT_TYPE_STRING
)
1860 SetValue( m_choices
.GetLabel(newValue
) );
1862 else // if ( valueType == wxPG_VARIANT_TYPE_LONG )
1864 SetValue( (long) newValue
);
1868 bool wxPGProperty::SetChoices( wxPGChoices
& choices
)
1870 m_choices
.Assign(choices
);
1873 // This may be needed to trigger some initialization
1874 // (but don't do it if property is somewhat uninitialized)
1875 wxVariant defVal
= GetDefaultValue();
1876 if ( defVal
.IsNull() )
1886 const wxPGEditor
* wxPGProperty::GetEditorClass() const
1888 const wxPGEditor
* editor
;
1890 if ( !m_customEditor
)
1892 editor
= DoGetEditorClass();
1895 editor
= m_customEditor
;
1898 // Maybe override editor if common value specified
1899 if ( GetDisplayedCommonValueCount() )
1901 // TextCtrlAndButton -> ComboBoxAndButton
1902 if ( editor
->IsKindOf(CLASSINFO(wxPGTextCtrlAndButtonEditor
)) )
1903 editor
= wxPGEditor_ChoiceAndButton
;
1905 // TextCtrl -> ComboBox
1906 else if ( editor
->IsKindOf(CLASSINFO(wxPGTextCtrlEditor
)) )
1907 editor
= wxPGEditor_ComboBox
;
1913 bool wxPGProperty::HasVisibleChildren() const
1917 for ( i
=0; i
<GetChildCount(); i
++ )
1919 wxPGProperty
* child
= Item(i
);
1921 if ( !child
->HasFlag(wxPG_PROP_HIDDEN
) )
1928 bool wxPGProperty::RecreateEditor()
1930 wxPropertyGrid
* pg
= GetGrid();
1933 wxPGProperty
* selected
= pg
->GetSelection();
1934 if ( this == selected
)
1936 pg
->DoSelectProperty(this, wxPG_SEL_FORCE
);
1943 void wxPGProperty::SetValueImage( wxBitmap
& bmp
)
1945 delete m_valueBitmap
;
1947 if ( &bmp
&& bmp
.Ok() )
1950 wxSize maxSz
= GetGrid()->GetImageSize();
1951 wxSize
imSz(bmp
.GetWidth(),bmp
.GetHeight());
1953 if ( imSz
.y
!= maxSz
.y
)
1955 // Create a memory DC
1956 wxBitmap
* bmpNew
= new wxBitmap(maxSz
.x
,maxSz
.y
,bmp
.GetDepth());
1959 dc
.SelectObject(*bmpNew
);
1962 // FIXME: This is ugly - use image or wait for scaling patch.
1963 double scaleY
= (double)maxSz
.y
/ (double)imSz
.y
;
1965 dc
.SetUserScale(scaleY
, scaleY
);
1967 dc
.DrawBitmap(bmp
, 0, 0);
1969 m_valueBitmap
= bmpNew
;
1973 m_valueBitmap
= new wxBitmap(bmp
);
1976 m_flags
|= wxPG_PROP_CUSTOMIMAGE
;
1980 m_valueBitmap
= NULL
;
1981 m_flags
&= ~(wxPG_PROP_CUSTOMIMAGE
);
1986 wxPGProperty
* wxPGProperty::GetMainParent() const
1988 const wxPGProperty
* curChild
= this;
1989 const wxPGProperty
* curParent
= m_parent
;
1991 while ( curParent
&& !curParent
->IsCategory() )
1993 curChild
= curParent
;
1994 curParent
= curParent
->m_parent
;
1997 return (wxPGProperty
*) curChild
;
2001 const wxPGProperty
* wxPGProperty::GetLastVisibleSubItem() const
2004 // Returns last visible sub-item, recursively.
2005 if ( !IsExpanded() || !GetChildCount() )
2008 return Last()->GetLastVisibleSubItem();
2012 bool wxPGProperty::IsVisible() const
2014 const wxPGProperty
* parent
;
2016 if ( HasFlag(wxPG_PROP_HIDDEN
) )
2019 for ( parent
= GetParent(); parent
!= NULL
; parent
= parent
->GetParent() )
2021 if ( !parent
->IsExpanded() || parent
->HasFlag(wxPG_PROP_HIDDEN
) )
2028 wxPropertyGrid
* wxPGProperty::GetGridIfDisplayed() const
2030 wxPropertyGridPageState
* state
= GetParentState();
2033 wxPropertyGrid
* propGrid
= state
->GetGrid();
2034 if ( state
== propGrid
->GetState() )
2040 int wxPGProperty::GetY2( int lh
) const
2042 const wxPGProperty
* parent
;
2043 const wxPGProperty
* child
= this;
2047 for ( parent
= GetParent(); parent
!= NULL
; parent
= child
->GetParent() )
2049 if ( !parent
->IsExpanded() )
2051 y
+= parent
->GetChildrenHeight(lh
, child
->GetIndexInParent());
2056 y
-= lh
; // need to reduce one level
2062 int wxPGProperty::GetY() const
2064 return GetY2(GetGrid()->GetRowHeight());
2067 // This is used by Insert etc.
2068 void wxPGProperty::DoAddChild( wxPGProperty
* prop
, int index
,
2071 if ( index
< 0 || (size_t)index
>= m_children
.size() )
2073 if ( correct_mode
) prop
->m_arrIndex
= m_children
.size();
2074 m_children
.push_back( prop
);
2078 m_children
.insert( m_children
.begin()+index
, prop
);
2079 if ( correct_mode
) FixIndicesOfChildren( index
);
2082 prop
->m_parent
= this;
2085 void wxPGProperty::DoPreAddChild( int index
, wxPGProperty
* prop
)
2087 wxASSERT_MSG( prop
->GetBaseName().length(),
2088 "Property's children must have unique, non-empty "
2089 "names within their scope" );
2091 prop
->m_arrIndex
= index
;
2092 m_children
.insert( m_children
.begin()+index
,
2095 int custImgHeight
= prop
->OnMeasureImage().y
;
2096 if ( custImgHeight
< 0 /*|| custImgHeight > 1*/ )
2097 prop
->m_flags
|= wxPG_PROP_CUSTOMIMAGE
;
2099 prop
->m_parent
= this;
2102 void wxPGProperty::AddPrivateChild( wxPGProperty
* prop
)
2104 if ( !(m_flags
& wxPG_PROP_PARENTAL_FLAGS
) )
2105 SetParentalType(wxPG_PROP_AGGREGATE
);
2107 wxASSERT_MSG( (m_flags
& wxPG_PROP_PARENTAL_FLAGS
) ==
2108 wxPG_PROP_AGGREGATE
,
2109 "Do not mix up AddPrivateChild() calls with other "
2110 "property adders." );
2112 DoPreAddChild( m_children
.size(), prop
);
2115 #if wxPG_COMPATIBILITY_1_4
2116 void wxPGProperty::AddChild( wxPGProperty
* prop
)
2118 AddPrivateChild(prop
);
2122 wxPGProperty
* wxPGProperty::InsertChild( int index
,
2123 wxPGProperty
* childProperty
)
2126 index
= m_children
.size();
2128 if ( m_parentState
)
2130 m_parentState
->DoInsert(this, index
, childProperty
);
2134 if ( !(m_flags
& wxPG_PROP_PARENTAL_FLAGS
) )
2135 SetParentalType(wxPG_PROP_MISC_PARENT
);
2137 wxASSERT_MSG( (m_flags
& wxPG_PROP_PARENTAL_FLAGS
) ==
2138 wxPG_PROP_MISC_PARENT
,
2139 "Do not mix up AddPrivateChild() calls with other "
2140 "property adders." );
2142 DoPreAddChild( index
, childProperty
);
2145 return childProperty
;
2148 void wxPGProperty::RemoveChild( wxPGProperty
* p
)
2150 wxArrayPGProperty::iterator it
;
2151 wxArrayPGProperty
& children
= m_children
;
2153 for ( it
=children
.begin(); it
!= children
.end(); it
++ )
2163 void wxPGProperty::AdaptListToValue( wxVariant
& list
, wxVariant
* value
) const
2165 wxASSERT( GetChildCount() );
2166 wxASSERT( !IsCategory() );
2168 *value
= GetValue();
2170 if ( !list
.GetCount() )
2173 wxASSERT( GetChildCount() >= (unsigned int)list
.GetCount() );
2175 bool allChildrenSpecified
;
2177 // Don't fully update aggregate properties unless all children have
2179 if ( HasFlag(wxPG_PROP_AGGREGATE
) )
2180 allChildrenSpecified
= AreAllChildrenSpecified(&list
);
2182 allChildrenSpecified
= true;
2184 wxVariant childValue
= list
[0];
2188 //wxLogDebug(wxT(">> %s.AdaptListToValue()"),GetBaseName().c_str());
2190 for ( i
=0; i
<GetChildCount(); i
++ )
2192 const wxPGProperty
* child
= Item(i
);
2194 if ( childValue
.GetName() == child
->GetBaseName() )
2196 //wxLogDebug(wxT(" %s(n=%i), %s"),childValue.GetName().c_str(),n,childValue.GetType().c_str());
2198 if ( childValue
.GetType() == wxPG_VARIANT_TYPE_LIST
)
2200 wxVariant
cv2(child
->GetValue());
2201 child
->AdaptListToValue(childValue
, &cv2
);
2205 if ( allChildrenSpecified
)
2207 *value
= ChildChanged(*value
, i
, childValue
);
2211 if ( n
== (unsigned int)list
.GetCount() )
2213 childValue
= list
[n
];
2219 void wxPGProperty::FixIndicesOfChildren( unsigned int starthere
)
2222 for ( i
=starthere
;i
<GetChildCount();i
++)
2223 Item(i
)->m_arrIndex
= i
;
2227 // Returns (direct) child property with given name (or NULL if not found)
2228 wxPGProperty
* wxPGProperty::GetPropertyByName( const wxString
& name
) const
2232 for ( i
=0; i
<GetChildCount(); i
++ )
2234 wxPGProperty
* p
= Item(i
);
2235 if ( p
->m_name
== name
)
2239 // Does it have point, then?
2240 int pos
= name
.Find(wxS('.'));
2244 wxPGProperty
* p
= GetPropertyByName(name
. substr(0,pos
));
2246 if ( !p
|| !p
->GetChildCount() )
2249 return p
->GetPropertyByName(name
.substr(pos
+1,name
.length()-pos
-1));
2252 wxPGProperty
* wxPGProperty::GetPropertyByNameWH( const wxString
& name
, unsigned int hintIndex
) const
2254 unsigned int i
= hintIndex
;
2256 if ( i
>= GetChildCount() )
2259 unsigned int lastIndex
= i
- 1;
2261 if ( lastIndex
>= GetChildCount() )
2262 lastIndex
= GetChildCount() - 1;
2266 wxPGProperty
* p
= Item(i
);
2267 if ( p
->m_name
== name
)
2270 if ( i
== lastIndex
)
2274 if ( i
== GetChildCount() )
2281 int wxPGProperty::GetChildrenHeight( int lh
, int iMax_
) const
2283 // Returns height of children, recursively, and
2284 // by taking expanded/collapsed status into account.
2286 // iMax is used when finding property y-positions.
2292 iMax_
= GetChildCount();
2294 unsigned int iMax
= iMax_
;
2296 wxASSERT( iMax
<= GetChildCount() );
2298 if ( !IsExpanded() && GetParent() )
2303 wxPGProperty
* pwc
= (wxPGProperty
*) Item(i
);
2305 if ( !pwc
->HasFlag(wxPG_PROP_HIDDEN
) )
2307 if ( !pwc
->IsExpanded() ||
2308 pwc
->GetChildCount() == 0 )
2311 h
+= pwc
->GetChildrenHeight(lh
) + lh
;
2320 wxPGProperty
* wxPGProperty::GetItemAtY( unsigned int y
,
2322 unsigned int* nextItemY
) const
2324 wxASSERT( nextItemY
);
2326 // Linear search at the moment
2328 // nextItemY = y of next visible property, final value will be written back.
2329 wxPGProperty
* result
= NULL
;
2330 wxPGProperty
* current
= NULL
;
2331 unsigned int iy
= *nextItemY
;
2333 unsigned int iMax
= GetChildCount();
2337 wxPGProperty
* pwc
= Item(i
);
2339 if ( !pwc
->HasFlag(wxPG_PROP_HIDDEN
) )
2350 if ( pwc
->IsExpanded() &&
2351 pwc
->GetChildCount() > 0 )
2353 result
= (wxPGProperty
*) pwc
->GetItemAtY( y
, lh
, &iy
);
2365 if ( !result
&& y
< iy
)
2373 wxLogDebug(wxT("%s::GetItemAtY(%i) -> %s"),this->GetLabel().c_str(),y,current->GetLabel().c_str());
2377 wxLogDebug(wxT("%s::GetItemAtY(%i) -> NULL"),this->GetLabel().c_str(),y);
2381 return (wxPGProperty
*) result
;
2384 void wxPGProperty::Empty()
2387 if ( !HasFlag(wxPG_PROP_CHILDREN_ARE_COPIES
) )
2389 for ( i
=0; i
<GetChildCount(); i
++ )
2391 delete m_children
[i
];
2398 wxPGProperty
* wxPGProperty::GetItemAtY( unsigned int y
) const
2400 unsigned int nextItem
;
2401 return GetItemAtY( y
, GetGrid()->GetRowHeight(), &nextItem
);
2404 void wxPGProperty::DeleteChildren()
2406 wxPropertyGridPageState
* state
= m_parentState
;
2408 while ( GetChildCount() )
2410 wxPGProperty
* child
= Item(GetChildCount()-1);
2411 state
->DoDelete(child
, true);
2415 wxVariant
wxPGProperty::ChildChanged( wxVariant
& WXUNUSED(thisValue
),
2416 int WXUNUSED(childIndex
),
2417 wxVariant
& WXUNUSED(childValue
) ) const
2419 return wxNullVariant
;
2422 bool wxPGProperty::AreAllChildrenSpecified( wxVariant
* pendingList
) const
2426 const wxVariantList
* pList
= NULL
;
2427 wxVariantList::const_iterator node
;
2431 pList
= &pendingList
->GetList();
2432 node
= pList
->begin();
2435 for ( i
=0; i
<GetChildCount(); i
++ )
2437 wxPGProperty
* child
= Item(i
);
2438 const wxVariant
* listValue
= NULL
;
2443 const wxString
& childName
= child
->GetBaseName();
2445 for ( ; node
!= pList
->end(); ++node
)
2447 const wxVariant
& item
= *((const wxVariant
*)*node
);
2448 if ( item
.GetName() == childName
)
2458 value
= child
->GetValue();
2460 if ( value
.IsNull() )
2463 // Check recursively
2464 if ( child
->GetChildCount() )
2466 const wxVariant
* childList
= NULL
;
2468 if ( listValue
&& listValue
->GetType() == wxPG_VARIANT_TYPE_LIST
)
2469 childList
= listValue
;
2471 if ( !child
->AreAllChildrenSpecified((wxVariant
*)childList
) )
2479 wxPGProperty
* wxPGProperty::UpdateParentValues()
2481 wxPGProperty
* parent
= m_parent
;
2482 if ( parent
&& parent
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) &&
2483 !parent
->IsCategory() && !parent
->IsRoot() )
2486 parent
->DoGenerateComposedValue(s
);
2487 parent
->m_value
= s
;
2488 return parent
->UpdateParentValues();
2493 bool wxPGProperty::IsTextEditable() const
2495 if ( HasFlag(wxPG_PROP_READONLY
) )
2498 if ( HasFlag(wxPG_PROP_NOEDITOR
) &&
2500 wxString(GetEditorClass()->GetClassInfo()->GetClassName()).EndsWith(wxS("Button")))
2507 // Call after fixed sub-properties added/removed after creation.
2508 // if oldSelInd >= 0 and < new max items, then selection is
2509 // moved to it. Note: oldSelInd -2 indicates that this property
2510 // should be selected.
2511 void wxPGProperty::SubPropsChanged( int oldSelInd
)
2513 wxPropertyGridPageState
* state
= GetParentState();
2514 wxPropertyGrid
* grid
= state
->GetGrid();
2517 // Re-repare children (recursively)
2518 for ( unsigned int i
=0; i
<GetChildCount(); i
++ )
2520 wxPGProperty
* child
= Item(i
);
2521 child
->InitAfterAdded(state
, grid
);
2524 wxPGProperty
* sel
= NULL
;
2525 if ( oldSelInd
>= (int)m_children
.size() )
2526 oldSelInd
= (int)m_children
.size() - 1;
2528 if ( oldSelInd
>= 0 )
2529 sel
= m_children
[oldSelInd
];
2530 else if ( oldSelInd
== -2 )
2534 state
->DoSelectProperty(sel
);
2536 if ( state
== grid
->GetState() )
2538 grid
->GetPanel()->Refresh();
2542 // -----------------------------------------------------------------------
2544 // -----------------------------------------------------------------------
2546 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty
,none
,TextCtrl
)
2547 IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty
, wxPGProperty
)
2550 wxPGRootProperty::wxPGRootProperty( const wxString
& name
)
2560 wxPGRootProperty::~wxPGRootProperty()
2565 // -----------------------------------------------------------------------
2566 // wxPropertyCategory
2567 // -----------------------------------------------------------------------
2569 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPropertyCategory
,none
,TextCtrl
)
2570 IMPLEMENT_DYNAMIC_CLASS(wxPropertyCategory
, wxPGProperty
)
2572 void wxPropertyCategory::Init()
2574 // don't set colour - prepareadditem method should do this
2575 SetParentalType(wxPG_PROP_CATEGORY
);
2576 m_capFgColIndex
= 1;
2580 wxPropertyCategory::wxPropertyCategory()
2587 wxPropertyCategory::wxPropertyCategory( const wxString
&label
, const wxString
& name
)
2588 : wxPGProperty(label
,name
)
2594 wxPropertyCategory::~wxPropertyCategory()
2599 wxString
wxPropertyCategory::ValueToString( wxVariant
& WXUNUSED(value
),
2600 int WXUNUSED(argFlags
) ) const
2602 return wxEmptyString
;
2605 int wxPropertyCategory::GetTextExtent( const wxWindow
* wnd
, const wxFont
& font
) const
2607 if ( m_textExtent
> 0 )
2608 return m_textExtent
;
2610 ((wxWindow
*)wnd
)->GetTextExtent( m_label
, &x
, &y
, 0, 0, &font
);
2614 void wxPropertyCategory::CalculateTextExtent( wxWindow
* wnd
, const wxFont
& font
)
2617 wnd
->GetTextExtent( m_label
, &x
, &y
, 0, 0, &font
);
2621 // -----------------------------------------------------------------------
2623 // -----------------------------------------------------------------------
2625 wxPGChoiceEntry
& wxPGChoices::Add( const wxString
& label
, int value
)
2629 wxPGChoiceEntry
entry(label
, value
);
2630 return m_data
->Insert( -1, entry
);
2633 // -----------------------------------------------------------------------
2635 wxPGChoiceEntry
& wxPGChoices::Add( const wxString
& label
, const wxBitmap
& bitmap
, int value
)
2639 wxPGChoiceEntry
entry(label
, value
);
2640 entry
.SetBitmap(bitmap
);
2641 return m_data
->Insert( -1, entry
);
2644 // -----------------------------------------------------------------------
2646 wxPGChoiceEntry
& wxPGChoices::Insert( const wxPGChoiceEntry
& entry
, int index
)
2650 return m_data
->Insert( index
, entry
);
2653 // -----------------------------------------------------------------------
2655 wxPGChoiceEntry
& wxPGChoices::Insert( const wxString
& label
, int index
, int value
)
2659 wxPGChoiceEntry
entry(label
, value
);
2660 return m_data
->Insert( index
, entry
);
2663 // -----------------------------------------------------------------------
2665 wxPGChoiceEntry
& wxPGChoices::AddAsSorted( const wxString
& label
, int value
)
2671 while ( index
< GetCount() )
2673 int cmpRes
= GetLabel(index
).Cmp(label
);
2679 wxPGChoiceEntry
entry(label
, value
);
2680 return m_data
->Insert( index
, entry
);
2683 // -----------------------------------------------------------------------
2685 void wxPGChoices::Add( const wxChar
** labels
, const ValArrItem
* values
)
2689 unsigned int itemcount
= 0;
2690 const wxChar
** p
= &labels
[0];
2691 while ( *p
) { p
++; itemcount
++; }
2694 for ( i
= 0; i
< itemcount
; i
++ )
2699 wxPGChoiceEntry
entry(labels
[i
], value
);
2700 m_data
->Insert( i
, entry
);
2704 // -----------------------------------------------------------------------
2706 void wxPGChoices::Add( const wxArrayString
& arr
, const wxArrayInt
& arrint
)
2711 unsigned int itemcount
= arr
.size();
2713 for ( i
= 0; i
< itemcount
; i
++ )
2716 if ( &arrint
&& arrint
.size() )
2718 wxPGChoiceEntry
entry(arr
[i
], value
);
2719 m_data
->Insert( i
, entry
);
2723 // -----------------------------------------------------------------------
2725 void wxPGChoices::RemoveAt(size_t nIndex
, size_t count
)
2729 wxASSERT( m_data
->GetRefCount() != -1 );
2730 m_data
->m_items
.erase(m_data
->m_items
.begin()+nIndex
,
2731 m_data
->m_items
.begin()+nIndex
+count
);
2734 // -----------------------------------------------------------------------
2736 void wxPGChoices::Clear()
2738 if ( m_data
!= wxPGChoicesEmptyData
)
2745 // -----------------------------------------------------------------------
2747 int wxPGChoices::Index( const wxString
& str
) const
2752 for ( i
=0; i
< m_data
->GetCount(); i
++ )
2754 const wxPGChoiceEntry
& entry
= m_data
->Item(i
);
2755 if ( entry
.HasText() && entry
.GetText() == str
)
2762 // -----------------------------------------------------------------------
2764 int wxPGChoices::Index( int val
) const
2769 for ( i
=0; i
< m_data
->GetCount(); i
++ )
2771 const wxPGChoiceEntry
& entry
= m_data
->Item(i
);
2772 if ( entry
.GetValue() == val
)
2779 // -----------------------------------------------------------------------
2781 wxArrayString
wxPGChoices::GetLabels() const
2786 if ( this && IsOk() )
2787 for ( i
=0; i
<GetCount(); i
++ )
2788 arr
.push_back(GetLabel(i
));
2793 // -----------------------------------------------------------------------
2795 wxArrayInt
wxPGChoices::GetValuesForStrings( const wxArrayString
& strings
) const
2802 for ( i
=0; i
< strings
.size(); i
++ )
2804 int index
= Index(strings
[i
]);
2806 arr
.Add(GetValue(index
));
2808 arr
.Add(wxPG_INVALID_VALUE
);
2815 // -----------------------------------------------------------------------
2817 wxArrayInt
wxPGChoices::GetIndicesForStrings( const wxArrayString
& strings
,
2818 wxArrayString
* unmatched
) const
2825 for ( i
=0; i
< strings
.size(); i
++ )
2827 const wxString
& str
= strings
[i
];
2828 int index
= Index(str
);
2831 else if ( unmatched
)
2832 unmatched
->Add(str
);
2839 // -----------------------------------------------------------------------
2841 void wxPGChoices::AllocExclusive()
2845 if ( m_data
->GetRefCount() != 1 )
2847 wxPGChoicesData
* data
= new wxPGChoicesData();
2848 data
->CopyDataFrom(m_data
);
2854 // -----------------------------------------------------------------------
2856 void wxPGChoices::AssignData( wxPGChoicesData
* data
)
2860 if ( data
!= wxPGChoicesEmptyData
)
2867 // -----------------------------------------------------------------------
2869 void wxPGChoices::Init()
2871 m_data
= wxPGChoicesEmptyData
;
2874 // -----------------------------------------------------------------------
2876 void wxPGChoices::Free()
2878 if ( m_data
!= wxPGChoicesEmptyData
)
2881 m_data
= wxPGChoicesEmptyData
;
2885 // -----------------------------------------------------------------------
2886 // wxPGAttributeStorage
2887 // -----------------------------------------------------------------------
2889 wxPGAttributeStorage::wxPGAttributeStorage()
2893 wxPGAttributeStorage::~wxPGAttributeStorage()
2895 wxPGHashMapS2P::iterator it
;
2897 for ( it
= m_map
.begin(); it
!= m_map
.end(); ++it
)
2899 wxVariantData
* data
= (wxVariantData
*) it
->second
;
2904 void wxPGAttributeStorage::Set( const wxString
& name
, const wxVariant
& value
)
2906 wxVariantData
* data
= value
.GetData();
2909 wxPGHashMapS2P::iterator it
= m_map
.find(name
);
2910 if ( it
!= m_map
.end() )
2912 ((wxVariantData
*)it
->second
)->DecRef();
2916 // If Null variant, just remove from set
2930 #endif // wxUSE_PROPGRID