X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6a3a64f6ff1b53f10046d7ea33c8f67994db68a4..beb2638a997914bd12c55e81589adebd90af9ed2:/src/propgrid/property.cpp diff --git a/src/propgrid/property.cpp b/src/propgrid/property.cpp index 32db12d245..d670542dfa 100644 --- a/src/propgrid/property.cpp +++ b/src/propgrid/property.cpp @@ -4,7 +4,7 @@ // Author: Jaakko Salli // Modified by: // Created: 2008-08-23 -// RCS-ID: $Id: +// RCS-ID: $Id$ // Copyright: (c) Jaakko Salli // Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// @@ -16,6 +16,8 @@ #pragma hdrstop #endif +#if wxUSE_PROPGRID + #ifndef WX_PRECOMP #include "wx/defs.h" #include "wx/object.h" @@ -27,29 +29,13 @@ #include "wx/panel.h" #include "wx/dc.h" #include "wx/dcmemory.h" - #include "wx/button.h" #include "wx/pen.h" #include "wx/brush.h" - #include "wx/cursor.h" - #include "wx/dialog.h" #include "wx/settings.h" - #include "wx/msgdlg.h" - #include "wx/choice.h" - #include "wx/stattext.h" - #include "wx/scrolwin.h" - #include "wx/dirdlg.h" - #include "wx/layout.h" - #include "wx/sizer.h" - #include "wx/textdlg.h" - #include "wx/filedlg.h" - #include "wx/statusbr.h" #include "wx/intl.h" - #include "wx/frame.h" #endif -#include - -#include +#include "wx/propgrid/propgrid.h" #define PWC_CHILD_SUMMARY_LIMIT 16 // Maximum number of children summarized in a parent property's @@ -57,6 +43,12 @@ #define PWC_CHILD_SUMMARY_CHAR_LIMIT 64 // Character limit of summary field when not editing +#if wxPG_COMPATIBILITY_1_4 + +// Used to establish backwards compatiblity +const char* g_invalidStringContent = "@__TOTALLY_INVALID_STRING__@"; + +#endif // ----------------------------------------------------------------------- @@ -102,8 +94,6 @@ wxSize wxPGCellRenderer::GetImageSize( const wxPGProperty* WXUNUSED(property), void wxPGCellRenderer::DrawText( wxDC& dc, const wxRect& rect, int xOffset, const wxString& text ) const { - if ( xOffset ) - xOffset += wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2; dc.DrawText( text, rect.x+xOffset+wxPG_XBEFORETEXT, rect.y+((rect.height-dc.GetCharHeight())/2) ); @@ -114,9 +104,6 @@ void wxPGCellRenderer::DrawEditorValue( wxDC& dc, const wxRect& rect, wxPGProperty* property, const wxPGEditor* editor ) const { - if ( xOffset ) - xOffset += wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2; - int yOffset = ((rect.height-dc.GetCharHeight())/2); if ( editor ) @@ -143,38 +130,39 @@ void wxPGCellRenderer::DrawCaptionSelectionRect( wxDC& dc, int x, int y, int w, int wxPGCellRenderer::PreDrawCell( wxDC& dc, const wxRect& rect, const wxPGCell& cell, int flags ) const { - int imageOffset = 0; + int imageWidth = 0; - if ( !(flags & Selected) ) + // If possible, use cell colours + if ( !(flags & DontUseCellBgCol) ) { - // Draw using wxPGCell information, if available - wxColour fgCol = cell.GetFgCol(); - if ( fgCol.Ok() ) - dc.SetTextForeground(fgCol); + dc.SetPen(cell.GetBgCol()); + dc.SetBrush(cell.GetBgCol()); + } - wxColour bgCol = cell.GetBgCol(); - if ( bgCol.Ok() ) - { - dc.SetPen(bgCol); - dc.SetBrush(bgCol); - dc.DrawRectangle(rect); - } + if ( !(flags & DontUseCellFgCol) ) + { + dc.SetTextForeground(cell.GetFgCol()); } + // Draw Background, but only if not rendering in control + // (as control already has rendered correct background). + if ( !(flags & (Control|ChoicePopup)) ) + dc.DrawRectangle(rect); + const wxBitmap& bmp = cell.GetBitmap(); if ( bmp.Ok() && - // In control, do not draw oversized bitmap - (!(flags & Control) || bmp.GetHeight() < rect.height ) + // Do not draw oversized bitmap outside choice popup + ((flags & ChoicePopup) || bmp.GetHeight() < rect.height ) ) { dc.DrawBitmap( bmp, rect.x + wxPG_CONTROL_MARGIN + wxCC_CUSTOM_IMAGE_MARGIN1, rect.y + wxPG_CUSTOM_IMAGE_SPACINGY, true ); - imageOffset = bmp.GetWidth(); + imageWidth = bmp.GetWidth(); } - return imageOffset; + return imageWidth; } // ----------------------------------------------------------------------- @@ -200,46 +188,17 @@ void wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect, } const wxPGEditor* editor = NULL; - const wxPGCell* cell = property->GetCell(column); + const wxPGCell* cell = NULL; wxString text; - int imageOffset = 0; - - // Use choice cell? - if ( column == 1 && (flags & Control) ) - { - const wxPGCell* ccell = property->GetCurrentChoice(); - if ( ccell && - ( ccell->GetBitmap().IsOk() || ccell->GetFgCol().IsOk() || ccell->GetBgCol().IsOk() ) - ) - cell = ccell; - } + int imageWidth = 0; + int preDrawFlags = flags; - if ( cell ) - { - int preDrawFlags = flags; + property->GetDisplayInfo(column, item, flags, &text, &cell); - if ( propertyGrid->GetInternalFlags() & wxPG_FL_CELL_OVERRIDES_SEL ) - preDrawFlags = preDrawFlags & ~(Selected); + imageWidth = PreDrawCell( dc, rect, *cell, preDrawFlags ); - imageOffset = PreDrawCell( dc, rect, *cell, preDrawFlags ); - text = cell->GetText(); - if ( text == wxS("@!") ) - { - if ( column == 0 ) - text = property->GetLabel(); - else if ( column == 1 ) - text = property->GetValueString(); - else - text = wxEmptyString; - } - } - else if ( column == 0 ) - { - // Caption - DrawText( dc, rect, 0, property->GetLabel() ); - } - else if ( column == 1 ) + if ( column == 1 ) { if ( !isUnspecified ) { @@ -260,30 +219,17 @@ void wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect, wxPG_CUSTOM_IMAGE_WIDTH, rect.height-(wxPG_CUSTOM_IMAGE_SPACINGY*2)); - /*if ( imageSize.x == wxPG_FULL_CUSTOM_PAINT_WIDTH ) - { - imageRect.width = m_width - imageRect.x; - }*/ - dc.SetPen( wxPen(propertyGrid->GetCellTextColour(), 1, wxSOLID) ); paintdata.m_drawnWidth = imageSize.x; paintdata.m_drawnHeight = imageSize.y; - if ( !isUnspecified ) - { - property->OnCustomPaint( dc, imageRect, paintdata ); - } - else - { - dc.SetBrush(*wxWHITE_BRUSH); - dc.DrawRectangle(imageRect); - } + property->OnCustomPaint( dc, imageRect, paintdata ); - imageOffset = paintdata.m_drawnWidth; + imageWidth = paintdata.m_drawnWidth; } - text = property->GetValueString(); + text = property->GetValueAsString(); // Add units string? if ( propertyGrid->GetColumnCount() <= 2 ) @@ -305,12 +251,8 @@ void wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect, } } } - else if ( column == 2 ) - { - // Add units string? - if ( !text.length() ) - text = property->GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString); - } + + int imageOffset = property->GetImageOffset(imageWidth); DrawEditorValue( dc, rect, imageOffset, text, property, editor ); @@ -319,8 +261,11 @@ void wxPGDefaultRenderer::Render( wxDC& dc, const wxRect& rect, { if ( flags & Selected ) { - if ( imageOffset > 0 ) - imageOffset += wxCC_CUSTOM_IMAGE_MARGIN2 + 4; + if ( imageWidth > 0 ) + { + imageOffset -= DEFAULT_IMAGE_OFFSET_INCREMENT; + imageWidth += wxCC_CUSTOM_IMAGE_MARGIN2 + 4; + } DrawCaptionSelectionRect( dc, rect.x+wxPG_XBEFORETEXT-wxPG_CAPRECTXMARGIN+imageOffset, @@ -350,11 +295,22 @@ wxSize wxPGDefaultRenderer::GetImageSize( const wxPGProperty* property, return wxSize(0,0); } +// ----------------------------------------------------------------------- +// wxPGCellData +// ----------------------------------------------------------------------- + +wxPGCellData::wxPGCellData() + : wxObjectRefData() +{ + m_hasValidText = false; +} + // ----------------------------------------------------------------------- // wxPGCell // ----------------------------------------------------------------------- wxPGCell::wxPGCell() + : wxObject() { } @@ -362,9 +318,74 @@ wxPGCell::wxPGCell( const wxString& text, const wxBitmap& bitmap, const wxColour& fgCol, const wxColour& bgCol ) - : m_bitmap(bitmap), m_fgCol(fgCol), m_bgCol(bgCol) + : wxObject() +{ + wxPGCellData* data = new wxPGCellData(); + m_refData = data; + data->m_text = text; + data->m_bitmap = bitmap; + data->m_fgCol = fgCol; + data->m_bgCol = bgCol; + data->m_hasValidText = true; +} + +wxObjectRefData *wxPGCell::CloneRefData( const wxObjectRefData *data ) const +{ + wxPGCellData* c = new wxPGCellData(); + const wxPGCellData* o = (const wxPGCellData*) data; + c->m_text = o->m_text; + c->m_bitmap = o->m_bitmap; + c->m_fgCol = o->m_fgCol; + c->m_bgCol = o->m_bgCol; + c->m_hasValidText = o->m_hasValidText; + return c; +} + +void wxPGCell::SetText( const wxString& text ) +{ + AllocExclusive(); + + GetData()->SetText(text); +} + +void wxPGCell::SetBitmap( const wxBitmap& bitmap ) +{ + AllocExclusive(); + + GetData()->SetBitmap(bitmap); +} + +void wxPGCell::SetFgCol( const wxColour& col ) +{ + AllocExclusive(); + + GetData()->SetFgCol(col); +} + +void wxPGCell::SetBgCol( const wxColour& col ) { - m_text = text; + AllocExclusive(); + + GetData()->SetBgCol(col); +} + +void wxPGCell::MergeFrom( const wxPGCell& srcCell ) +{ + AllocExclusive(); + + wxPGCellData* data = GetData(); + + if ( srcCell.HasText() ) + data->SetText(srcCell.GetText()); + + if ( srcCell.GetFgCol().IsOk() ) + data->SetFgCol(srcCell.GetFgCol()); + + if ( srcCell.GetBgCol().IsOk() ) + data->SetBgCol(srcCell.GetBgCol()); + + if ( srcCell.GetBitmap().IsOk() ) + data->SetBitmap(srcCell.GetBitmap()); } // ----------------------------------------------------------------------- @@ -381,24 +402,22 @@ void wxPGProperty::Init() m_arrIndex = 0xFFFF; m_parent = NULL; - m_parentState = (wxPropertyGridPageState*) NULL; + m_parentState = NULL; m_clientData = NULL; m_clientObject = NULL; - m_customEditor = (wxPGEditor*) NULL; + m_customEditor = NULL; #if wxUSE_VALIDATORS - m_validator = (wxValidator*) NULL; + m_validator = NULL; #endif - m_valueBitmap = (wxBitmap*) NULL; + m_valueBitmap = NULL; m_maxLen = 0; // infinite maximum length m_flags = wxPG_PROP_PROPERTY; m_depth = 1; - m_bgColIndex = 0; - m_fgColIndex = 0; SetExpanded(true); } @@ -420,6 +439,138 @@ void wxPGProperty::Init( const wxString& label, const wxString& name ) Init(); } +void wxPGProperty::InitAfterAdded( wxPropertyGridPageState* pageState, + wxPropertyGrid* propgrid ) +{ + // + // Called after property has been added to grid or page + // (so propgrid can be NULL, too). + + wxPGProperty* parent = m_parent; + bool parentIsRoot = parent->IsKindOf(CLASSINFO(wxPGRootProperty)); + + m_parentState = pageState; + +#if wxPG_COMPATIBILITY_1_4 + // Make sure deprecated virtual functions are not implemented + wxString s = GetValueAsString( 0xFFFF ); + wxASSERT_MSG( s == g_invalidStringContent, + "Implement ValueToString() instead of GetValueAsString()" ); +#endif + + if ( !parentIsRoot && !parent->IsCategory() ) + { + m_cells = parent->m_cells; + } + + // If in hideable adding mode, or if assigned parent is hideable, then + // make this one hideable. + if ( + ( !parentIsRoot && parent->HasFlag(wxPG_PROP_HIDDEN) ) || + ( propgrid && (propgrid->HasInternalFlag(wxPG_FL_ADDING_HIDEABLES)) ) + ) + SetFlag( wxPG_PROP_HIDDEN ); + + // Set custom image flag. + int custImgHeight = OnMeasureImage().y; + if ( custImgHeight < 0 ) + { + SetFlag(wxPG_PROP_CUSTOMIMAGE); + } + + if ( propgrid && (propgrid->HasFlag(wxPG_LIMITED_EDITING)) ) + SetFlag(wxPG_PROP_NOEDITOR); + + // Make sure parent has some parental flags + if ( !parent->HasFlag(wxPG_PROP_PARENTAL_FLAGS) ) + parent->SetParentalType(wxPG_PROP_MISC_PARENT); + + if ( !IsCategory() ) + { + // This is not a category. + + // Depth. + // + unsigned char depth = 1; + if ( !parentIsRoot ) + { + depth = parent->m_depth; + if ( !parent->IsCategory() ) + depth++; + } + m_depth = depth; + unsigned char greyDepth = depth; + + if ( !parentIsRoot ) + { + wxPropertyCategory* pc; + + if ( parent->IsCategory() ) + pc = (wxPropertyCategory* ) parent; + else + // This conditional compile is necessary to + // bypass some compiler bug. + pc = pageState->GetPropertyCategory(parent); + + if ( pc ) + greyDepth = pc->GetDepth(); + else + greyDepth = parent->m_depthBgCol; + } + + m_depthBgCol = greyDepth; + } + else + { + // This is a category. + + // depth + unsigned char depth = 1; + if ( !parentIsRoot ) + { + depth = parent->m_depth + 1; + } + m_depth = depth; + m_depthBgCol = depth; + } + + // + // Has initial children + if ( GetChildCount() ) + { + // Check parental flags + wxASSERT_MSG( ((m_flags & wxPG_PROP_PARENTAL_FLAGS) == + wxPG_PROP_AGGREGATE) || + ((m_flags & wxPG_PROP_PARENTAL_FLAGS) == + wxPG_PROP_MISC_PARENT), + "wxPGProperty parental flags set incorrectly at " + "this time" ); + + if ( HasFlag(wxPG_PROP_AGGREGATE) ) + { + // Properties with private children are not expanded by default. + SetExpanded(false); + } + else if ( propgrid && propgrid->HasFlag(wxPG_HIDE_MARGIN) ) + { + // ...unless it cannot be expanded by user and therefore must + // remain visible at all times + SetExpanded(true); + } + + // + // Prepare children recursively + for ( unsigned int i=0; iInitAfterAdded(pageState, pageState->GetGrid()); + } + + if ( propgrid && (propgrid->GetExtraStyle() & wxPG_EX_AUTO_UNSPECIFIED_VALUES) ) + SetFlagRecursively(wxPG_PROP_AUTO_UNSPECIFIED, true); + } +} + wxPGProperty::wxPGProperty() : wxObject() { @@ -445,11 +596,6 @@ wxPGProperty::~wxPGProperty() delete m_validator; #endif - unsigned int i; - - for ( i=0; iGetGrid(); } - -void wxPGProperty::UpdateControl( wxWindow* primary ) +int wxPGProperty::Index( const wxPGProperty* p ) const { - if ( primary ) - GetEditorClass()->UpdateControl(this, primary); + for ( unsigned int i = 0; iHasText() ) + { + *pString = cell->GetText(); + } + else + { + if ( column == 0 ) + *pString = GetLabel(); + else if ( column == 1 ) + *pString = GetDisplayedString(); + else if ( column == 2 ) + *pString = GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString); + } + } + else + { + wxASSERT( column == 1 ); + + if ( choiceIndex != wxNOT_FOUND ) + { + const wxPGChoiceEntry& entry = m_choices[choiceIndex]; + if ( entry.GetBitmap().IsOk() || + entry.GetFgCol().IsOk() || + entry.GetBgCol().IsOk() ) + cell = &entry; + *pString = m_choices.GetLabel(choiceIndex); + } + } + + if ( !cell ) + cell = &GetCell(column); + + wxASSERT_MSG( cell->GetData(), + wxString::Format("Invalid cell for property %s", + GetName().c_str()) ); + + *pCell = cell; +} + +/* +wxString wxPGProperty::GetColumnText( unsigned int col, int choiceIndex ) const { - wxPGCell* cell = GetCell(col); - if ( cell ) + + if ( col != 1 || choiceIndex == wxNOT_FOUND ) { - return cell->GetText(); + const wxPGCell& cell = GetCell(col); + if ( cell->HasText() ) + { + return cell->GetText(); + } + else + { + if ( col == 0 ) + return GetLabel(); + else if ( col == 1 ) + return GetDisplayedString(); + else if ( col == 2 ) + return GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString); + } } else { - if ( col == 0 ) - return GetLabel(); - else if ( col == 1 ) - return GetDisplayedString(); - else if ( col == 2 ) - return GetAttribute(wxPGGlobalVars->m_strUnits, wxEmptyString); + // Use choice + return m_choices.GetLabel(choiceIndex); } return wxEmptyString; } +*/ -void wxPGProperty::GenerateComposedValue( wxString& text, int argFlags ) const +void wxPGProperty::DoGenerateComposedValue( wxString& text, + int argFlags, + const wxVariantList* valueOverrides, + wxPGHashMapS2S* childResults ) const { int i; - int iMax = m_children.GetCount(); + int iMax = m_children.size(); text.clear(); if ( iMax == 0 ) @@ -543,13 +761,66 @@ void wxPGProperty::GenerateComposedValue( wxString& text, int argFlags ) const if ( !IsTextEditable() ) argFlags |= wxPG_UNEDITABLE_COMPOSITE_FRAGMENT; - wxPGProperty* curChild = (wxPGProperty*) m_children.Item(0); + wxPGProperty* curChild = m_children[0]; + + bool overridesLeft = false; + wxVariant overrideValue; + wxVariantList::const_iterator node; + + if ( valueOverrides ) + { + node = valueOverrides->begin(); + if ( node != valueOverrides->end() ) + { + overrideValue = *node; + overridesLeft = true; + } + } for ( i = 0; i < iMax; i++ ) { + wxVariant childValue; + + wxString childLabel = curChild->GetLabel(); + + // Check for value override + if ( overridesLeft && overrideValue.GetName() == childLabel ) + { + if ( !overrideValue.IsNull() ) + childValue = overrideValue; + else + childValue = curChild->GetValue(); + ++node; + if ( node != valueOverrides->end() ) + overrideValue = *node; + else + overridesLeft = false; + } + else + { + childValue = curChild->GetValue(); + } + wxString s; - if ( !curChild->IsValueUnspecified() ) - s = curChild->GetValueString(argFlags|wxPG_COMPOSITE_FRAGMENT); + if ( !childValue.IsNull() ) + { + if ( overridesLeft && + curChild->HasFlag(wxPG_PROP_COMPOSED_VALUE) && + childValue.GetType() == wxPG_VARIANT_TYPE_LIST ) + { + wxVariantList& childList = childValue.GetList(); + DoGenerateComposedValue(s, argFlags|wxPG_COMPOSITE_FRAGMENT, + &childList, childResults); + } + else + { + s = curChild->ValueToString(childValue, + argFlags|wxPG_COMPOSITE_FRAGMENT); + } + } + + if ( childResults && curChild->GetChildCount() ) + (*childResults)[curChild->GetName()] = s; bool skip = false; if ( (argFlags & wxPG_UNEDITABLE_COMPOSITE_FRAGMENT) && !s.length() ) @@ -575,37 +846,58 @@ void wxPGProperty::GenerateComposedValue( wxString& text, int argFlags ) const text += wxS(" "); } - curChild = (wxPGProperty*) m_children.Item(i+1); + curChild = m_children[i+1]; } } - // Remove superfluous semicolon and space - wxString rest; - if ( text.EndsWith(wxS("; "), &rest) ) - text = rest; - - if ( (unsigned int)i < m_children.GetCount() ) - text += wxS("; ..."); + if ( (unsigned int)i < m_children.size() ) + { + if ( !text.EndsWith(wxS("; ")) ) + text += wxS("; ..."); + else + text += wxS("..."); + } } -wxString wxPGProperty::GetValueAsString( int argFlags ) const +wxString wxPGProperty::ValueToString( wxVariant& WXUNUSED(value), + int argFlags ) const { wxCHECK_MSG( GetChildCount() > 0, wxString(), - wxT("If user property does not have any children, it must override GetValueAsString") ); + "If user property does not have any children, it must " + "override GetValueAsString" ); + + // FIXME: Currently code below only works if value is actually m_value + wxASSERT_MSG( argFlags & wxPG_VALUE_IS_CURRENT, + "Sorry, currently default wxPGProperty::ValueToString() " + "implementation only works if value is m_value." ); wxString text; - GenerateComposedValue(text, argFlags); + DoGenerateComposedValue(text, argFlags); return text; } -wxString wxPGProperty::GetValueString( int argFlags ) const +wxString wxPGProperty::GetValueAsString( int argFlags ) const { +#if wxPG_COMPATIBILITY_1_4 + // This is backwards compatibility test + // That is, to make sure this function is not overridden + // (instead, ValueToString() should be). + if ( argFlags == 0xFFFF ) + { + // Do not override! (for backwards compliancy) + return g_invalidStringContent; + } +#endif + if ( IsValueUnspecified() ) return wxEmptyString; if ( m_commonValue == -1 ) - return GetValueAsString(argFlags); + { + wxVariant value(GetValue()); + return ValueToString(value, argFlags|wxPG_VALUE_IS_CURRENT); + } // // Return common value's string representation @@ -626,6 +918,11 @@ wxString wxPGProperty::GetValueString( int argFlags ) const } } +wxString wxPGProperty::GetValueString( int argFlags ) const +{ + return GetValueAsString(argFlags); +} + bool wxPGProperty::IntToValue( wxVariant& variant, int number, int WXUNUSED(argFlags) ) const { variant = (long)number; @@ -640,7 +937,7 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int unsigned int curChild = 0; - unsigned int iMax = m_children.GetCount(); + unsigned int iMax = m_children.size(); if ( iMax > PWC_CHILD_SUMMARY_LIMIT && !(argFlags & wxPG_FULL_VALUE) ) @@ -660,7 +957,7 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int wxVariantList temp_list; wxVariant list(temp_list); - int propagatedFlags = argFlags & wxPG_REPORT_ERROR; + int propagatedFlags = argFlags & (wxPG_REPORT_ERROR|wxPG_PROGRAMMATIC_VALUE); #ifdef __WXDEBUG__ bool debug_print = false; @@ -681,6 +978,11 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int for ( ;; ) { + // How many units we iterate string forward at the end of loop? + // We need to keep track of this or risk going to negative + // with it-- operation. + unsigned int strPosIncrement = 1; + if ( tokenStart != 0xFFFFFF ) { // Token is running @@ -693,43 +995,47 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int if ( !addOnlyIfNotEmpty || len > 0 ) { const wxPGProperty* child = Item(curChild); + wxVariant variant(child->GetValue()); + wxString childName = child->GetBaseName(); + #ifdef __WXDEBUG__ if ( debug_print ) - wxLogDebug(wxT("token = '%s', child = %s"),token.c_str(),child->GetLabel().c_str()); + wxLogDebug(wxT("token = '%s', child = %s"), + token.c_str(), childName.c_str()); #endif - if ( len > 0 ) + // Add only if editable or setting programmatically + if ( (argFlags & wxPG_PROGRAMMATIC_VALUE) || + !child->HasFlag(wxPG_PROP_DISABLED|wxPG_PROP_READONLY) ) { - bool wasUnspecified = child->IsValueUnspecified(); - - wxVariant variant(child->GetValueRef()); - if ( child->StringToValue(variant, token, propagatedFlags|wxPG_COMPOSITE_FRAGMENT) ) + if ( len > 0 ) { - // Use label instead of name, as name can be empty string, but - // label in practice never is. - variant.SetName(child->GetLabel()); - - // Clear unspecified flag only if OnSetValue() didn't - // affect it. - if ( child->IsValueUnspecified() && - (wasUnspecified || !UsesAutoUnspecified()) ) + if ( child->StringToValue(variant, token, + propagatedFlags|wxPG_COMPOSITE_FRAGMENT) ) { - variant = child->GetDefaultValue(); + // We really need to set the variant's name + // *after* child->StringToValue() has been + // called, since variant's value may be set by + // assigning another variant into it, which + // then usually causes name to be copied (ie. + // usually cleared) as well. wxBoolProperty + // being case in point with its use of + // wxPGVariant_Bool macro as an optimization. + variant.SetName(childName); + list.Append(variant); + + changed = true; } - + } + else + { + // Empty, becomes unspecified + variant.MakeNull(); + variant.SetName(childName); list.Append(variant); - changed = true; } } - else - { - // Empty, becomes unspecified - wxVariant variant2; - variant2.SetName(child->GetLabel()); - list.Append(variant2); - changed = true; - } curChild++; if ( curChild >= iMax ) @@ -752,7 +1058,7 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int { int depth = 1; - if ( it != text.end() ) it++; + if ( it != text.end() ) ++it; pos++; size_t startPos = pos; @@ -760,7 +1066,7 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int while ( it != text.end() && depth > 0 ) { a = *it; - it++; + ++it; pos++; if ( a == wxS(']') ) @@ -776,22 +1082,27 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int const wxPGProperty* child = Item(curChild); - wxVariant variant(child->GetValueRef()); - if ( child->StringToValue( variant, token, propagatedFlags ) ) - { - // Use label instead of name, as name can be empty string, but - // label in practice never is. - variant.SetName(child->GetLabel()); - list.Append(variant); - changed = true; - } - else + wxVariant oldChildValue = child->GetValue(); + wxVariant variant(oldChildValue); + + if ( (argFlags & wxPG_PROGRAMMATIC_VALUE) || + !child->HasFlag(wxPG_PROP_DISABLED|wxPG_PROP_READONLY) ) { - // Failed, becomes unspecified - wxVariant variant2; - variant2.SetName(child->GetLabel()); - list.Append(variant2); - changed = true; + wxString childName = child->GetBaseName(); + + bool stvRes = child->StringToValue( variant, token, + propagatedFlags ); + if ( stvRes || (variant != oldChildValue) ) + { + variant.SetName(childName); + list.Append(variant); + + changed = true; + } + else + { + // No changes... + } } curChild++; @@ -807,10 +1118,7 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int tokenStart = pos; if ( a == delimeter ) - { - pos--; - it--; - } + strPosIncrement -= 1; } } } @@ -818,7 +1126,8 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int if ( a == 0 ) break; - it++; + it += strPosIncrement; + if ( it != text.end() ) { a = *it; @@ -827,7 +1136,8 @@ bool wxPGProperty::StringToValue( wxVariant& variant, const wxString& text, int { a = 0; } - pos++; + + pos += strPosIncrement; } if ( changed ) @@ -862,6 +1172,22 @@ wxSize wxPGProperty::OnMeasureImage( int WXUNUSED(item) ) const return wxSize(0,0); } +int wxPGProperty::GetImageOffset( int imageWidth ) const +{ + int imageOffset = 0; + + if ( imageWidth ) + { + // Do not increment offset too much for wide images + if ( imageWidth <= (wxPG_CUSTOM_IMAGE_WIDTH+5) ) + imageOffset = imageWidth + DEFAULT_IMAGE_OFFSET_INCREMENT; + else + imageOffset = imageWidth + 1; + } + + return imageOffset; +} + wxPGCellRenderer* wxPGProperty::GetCellRenderer( int WXUNUSED(column) ) const { return wxPGGlobalVars->m_defaultRenderer; @@ -882,7 +1208,7 @@ void wxPGProperty::OnCustomPaint( wxDC& dc, const wxPGEditor* wxPGProperty::DoGetEditorClass() const { - return wxPG_EDITOR(TextCtrl); + return wxPGEditor_TextCtrl; } // Default extra property event handling - that is, none at all. @@ -894,14 +1220,32 @@ bool wxPGProperty::OnEvent( wxPropertyGrid*, wxWindow*, wxEvent& ) void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags ) { + // If auto unspecified values are not wanted (via window or property style), + // then get default value instead of wxNullVariant. + if ( value.IsNull() && (flags & wxPG_SETVAL_BY_USER) && + !UsesAutoUnspecified() ) + { + value = GetDefaultValue(); + } + if ( !value.IsNull() ) { + wxVariant tempListVariant; + SetCommonValue(-1); // List variants are reserved a special purpose // as intermediate containers for child values // of properties with children. - if ( wxPGIsVariantType(value, list) ) + if ( value.GetType() == wxPG_VARIANT_TYPE_LIST ) { + // + // However, situation is different for composed string properties + if ( HasFlag(wxPG_PROP_COMPOSED_VALUE) ) + { + tempListVariant = value; + pList = &tempListVariant; + } + wxVariant newValue; AdaptListToValue(value, &newValue); value = newValue; @@ -913,7 +1257,7 @@ void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags ) if ( pList && !pList->IsNull() ) { - wxASSERT( wxPGIsVariantType(*pList, list) ); + wxASSERT( pList->GetType() == wxPG_VARIANT_TYPE_LIST ); wxASSERT( GetChildCount() ); wxASSERT( !IsCategory() ); @@ -924,15 +1268,15 @@ void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags ) //wxLogDebug(wxT(">> %s.SetValue() pList parsing"),GetName().c_str()); // Children in list can be in any order, but we will give hint to - // GetPropertyByLabelWH(). This optimizes for full list parsing. - for ( node = list.begin(); node != list.end(); node++ ) + // GetPropertyByNameWH(). This optimizes for full list parsing. + for ( node = list.begin(); node != list.end(); ++node ) { wxVariant& childValue = *((wxVariant*)*node); - wxPGProperty* child = GetPropertyByLabelWH(childValue.GetName(), i); + wxPGProperty* child = GetPropertyByNameWH(childValue.GetName(), i); if ( child ) { - //wxLogDebug(wxT("%i: child = %s, childValue.GetType()=%s"),i,child->GetLabel().c_str(),childValue.GetType().c_str()); - if ( wxPGIsVariantType(childValue, list) ) + //wxLogDebug(wxT("%i: child = %s, childValue.GetType()=%s"),i,child->GetBaseName().c_str(),childValue.GetType().c_str()); + if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST ) { if ( child->HasFlag(wxPG_PROP_AGGREGATE) && !(flags & wxPG_SETVAL_AGGREGATED) ) { @@ -945,16 +1289,14 @@ void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags ) child->SetValue(oldVal, &childValue, flags|wxPG_SETVAL_FROM_PARENT); } } - else if ( !wxPG_VARIANT_EQ(child->GetValue(), childValue) ) - // This flag is not normally set when setting value programmatically. - // However, this loop is usually only executed when called from - // DoPropertyChanged, which should set this flag. + else if ( child->GetValue() != childValue ) { // For aggregate properties, we will trust RefreshChildren() // to update child values. if ( !HasFlag(wxPG_PROP_AGGREGATE) ) child->SetValue(childValue, NULL, flags|wxPG_SETVAL_FROM_PARENT); - child->SetFlag(wxPG_PROP_MODIFIED); + if ( flags & wxPG_SETVAL_BY_USER ) + child->SetFlag(wxPG_PROP_MODIFIED); } } i++; @@ -963,14 +1305,11 @@ void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags ) if ( !value.IsNull() ) { - wxPGVariantAssign(m_value, value); + m_value = value; OnSetValue(); - - if ( !(flags & wxPG_SETVAL_FROM_PARENT) ) - UpdateParentValues(); } - if ( pList ) + if ( flags & wxPG_SETVAL_BY_USER ) SetFlag(wxPG_PROP_MODIFIED); if ( HasFlag(wxPG_PROP_AGGREGATE) ) @@ -997,13 +1336,21 @@ void wxPGProperty::SetValue( wxVariant value, wxVariant* pList, int flags ) } } + if ( !(flags & wxPG_SETVAL_FROM_PARENT) ) + UpdateParentValues(); + // // Update editor control // // We need to check for these, otherwise GetGrid() may fail. if ( flags & wxPG_SETVAL_REFRESH_EDITOR ) + { RefreshEditor(); + wxPropertyGrid* pg = GetGridIfDisplayed(); + if ( pg ) + pg->DrawItemAndValueRelated(this); + } } @@ -1026,18 +1373,13 @@ void wxPGProperty::SetFlagRecursively( FlagType flag, bool set ) void wxPGProperty::RefreshEditor() { - if ( m_parent && GetParentState() ) - { - wxPropertyGrid* pg = GetParentState()->GetGrid(); - if ( pg->GetSelectedProperty() == this ) - { - wxWindow* editor = pg->GetEditorControl(); - if ( editor ) - GetEditorClass()->UpdateControl( this, editor ); - } - } -} + if ( !m_parent ) + return; + wxPropertyGrid* pg = GetGrid(); + if ( pg && pg->GetSelectedProperty() == this ) + pg->RefreshEditor(); +} wxVariant wxPGProperty::GetDefaultValue() const { @@ -1049,144 +1391,202 @@ wxVariant wxPGProperty::GetDefaultValue() const if ( !value.IsNull() ) { - wxPGVariantDataClassInfo classInfo = wxPGVariantDataGetClassInfo(value.GetData()); - if ( wxPGIsVariantClassInfo(classInfo, long) ) + wxString valueType(value.GetType()); + + if ( valueType == wxPG_VARIANT_TYPE_LONG ) return wxPGVariant_Zero; - if ( wxPGIsVariantClassInfo(classInfo, string) ) + if ( valueType == wxPG_VARIANT_TYPE_STRING ) return wxPGVariant_EmptyString; - if ( wxPGIsVariantClassInfo(classInfo, bool) ) + if ( valueType == wxPG_VARIANT_TYPE_BOOL ) return wxPGVariant_False; - if ( wxPGIsVariantClassInfo(classInfo, double) ) + if ( valueType == wxPG_VARIANT_TYPE_DOUBLE ) return wxVariant(0.0); - - wxPGVariantData* pgvdata = wxDynamicCastVariantData(m_value.GetData(), wxPGVariantData); - if ( pgvdata ) - return pgvdata->GetDefaultValue(); - - if ( wxPGIsVariantClassInfo(classInfo, arrstring) ) + if ( valueType == wxPG_VARIANT_TYPE_ARRSTRING ) return wxVariant(wxArrayString()); - if ( wxPGIsVariantClassInfo(classInfo, wxColour) ) - return WXVARIANT(*wxRED); + if ( valueType == wxS("wxLongLong") ) + return WXVARIANT(wxLongLong(0)); + if ( valueType == wxS("wxULongLong") ) + return WXVARIANT(wxULongLong(0)); + if ( valueType == wxS("wxColour") ) + return WXVARIANT(*wxBLACK); #if wxUSE_DATETIME - if ( wxPGIsVariantClassInfo(classInfo, datetime) ) + if ( valueType == wxPG_VARIANT_TYPE_DATETIME ) return wxVariant(wxDateTime::Now()); #endif - - wxFAIL_MSG( - wxString::Format(wxT("Inorder for value to have default value, it must be added to") - wxT("wxPGProperty::GetDefaultValue or it's variantdata must inherit") - wxT("from wxPGVariantData (unrecognized type was '%s')"),m_value.GetType().c_str()) - ); + if ( valueType == wxS("wxFont") ) + return WXVARIANT(*wxNORMAL_FONT); + if ( valueType == wxS("wxPoint") ) + return WXVARIANT(wxPoint(0, 0)); + if ( valueType == wxS("wxSize") ) + return WXVARIANT(wxSize(0, 0)); } return wxVariant(); } -void wxPGProperty::SetCell( int column, wxPGCell* cellObj ) +void wxPGProperty::EnsureCells( unsigned int column ) { - if ( column >= (int)m_cells.size() ) - m_cells.SetCount(column+1, NULL); + if ( column >= m_cells.size() ) + { + // Fill empty slots with default cells + wxPropertyGrid* pg = GetGrid(); + wxPGCell defaultCell; + + if ( !HasFlag(wxPG_PROP_CATEGORY) ) + defaultCell = pg->GetPropertyDefaultCell(); + else + defaultCell = pg->GetCategoryDefaultCell(); + + // TODO: Replace with resize() call + unsigned int cellCountMax = column+1; - delete (wxPGCell*) m_cells[column]; - m_cells[column] = cellObj; + for ( unsigned int i=m_cells.size(); iGetLabel(newValue) ); + for ( unsigned int i=0; iAdaptiveSetCell( firstCol, + lastCol, + cell, + srcData, + unmodCellData, + ignoreWithFlags, + recursively ); } } - -wxString wxPGProperty::GetChoiceString( unsigned int index ) +const wxPGCell& wxPGProperty::GetCell( unsigned int column ) const { - wxPGChoiceInfo ci; - GetChoiceInfo(&ci); - wxASSERT(ci.m_choices); - return ci.m_choices->GetLabel(index); -} + if ( m_cells.size() > column ) + return m_cells[column]; -int wxPGProperty::InsertChoice( const wxString& label, int index, int value ) -{ wxPropertyGrid* pg = GetGrid(); - wxPGChoiceInfo ci; - ci.m_choices = (wxPGChoices*) NULL; - int sel = GetChoiceInfo(&ci); - - if ( ci.m_choices ) - { - int newSel = sel; + if ( IsCategory() ) + return pg->GetCategoryDefaultCell(); - if ( index < 0 ) - index = ci.m_choices->GetCount(); + return pg->GetPropertyDefaultCell(); +} - if ( index <= sel ) - newSel++; +wxPGCell& wxPGProperty::GetCell( unsigned int column ) +{ + EnsureCells(column); + return m_cells[column]; +} - ci.m_choices->Insert(label, index, value); +void wxPGProperty::SetBackgroundColour( const wxColour& colour, + bool recursively ) +{ + wxPGProperty* firstProp = this; - if ( sel != newSel ) - SetChoiceSelection(newSel, ci); + // + // If category is tried to set recursively, skip it and only + // affect the children. + if ( recursively ) + { + while ( firstProp->IsCategory() ) + { + if ( !firstProp->GetChildCount() ) + return; + firstProp = firstProp->Item(0); + } + } - if ( this == pg->GetSelection() ) - GetEditorClass()->InsertItem(pg->GetEditorControl(),label,index); + wxPGCell& firstCell = firstProp->GetCell(0); + wxPGCellData* firstCellData = firstCell.GetData(); - return index; - } + wxPGCell newCell(firstCell); + newCell.SetBgCol(colour); + wxPGCell srcCell; + srcCell.SetBgCol(colour); - return -1; + AdaptiveSetCell( 0, + GetParentState()->GetColumnCount()-1, + newCell, + srcCell, + firstCellData, + recursively ? wxPG_PROP_CATEGORY : 0, + recursively ); } - -void wxPGProperty::DeleteChoice( int index ) +void wxPGProperty::SetTextColour( const wxColour& colour, + bool recursively ) { - wxPropertyGrid* pg = GetGrid(); + wxPGProperty* firstProp = this; - wxPGChoiceInfo ci; - ci.m_choices = (wxPGChoices*) NULL; - int sel = GetChoiceInfo(&ci); - - if ( ci.m_choices ) + // + // If category is tried to set recursively, skip it and only + // affect the children. + if ( recursively ) { - int newSel = sel; - - // Adjust current value - if ( sel == index ) + while ( firstProp->IsCategory() ) { - SetValueToUnspecified(); - newSel = 0; - } - else if ( index < sel ) - { - newSel--; + if ( !firstProp->GetChildCount() ) + return; + firstProp = firstProp->Item(0); } + } - ci.m_choices->RemoveAt(index); + wxPGCell& firstCell = firstProp->GetCell(0); + wxPGCellData* firstCellData = firstCell.GetData(); - if ( sel != newSel ) - SetChoiceSelection(newSel, ci); + wxPGCell newCell(firstCell); + newCell.SetFgCol(colour); + wxPGCell srcCell; + srcCell.SetFgCol(colour); - if ( this == pg->GetSelection() ) - GetEditorClass()->DeleteItem(pg->GetEditorControl(), index); - } -} - -int wxPGProperty::GetChoiceInfo( wxPGChoiceInfo* WXUNUSED(info) ) -{ - return -1; + AdaptiveSetCell( 0, + GetParentState()->GetColumnCount()-1, + newCell, + srcCell, + firstCellData, + recursively ? wxPG_PROP_CATEGORY : 0, + recursively ); } wxPGEditorDialogAdapter* wxPGProperty::GetEditorDialog() const @@ -1338,66 +1738,119 @@ void wxPGProperty::SetFlagsFromString( const wxString& str ) wxValidator* wxPGProperty::DoGetValidator() const { - return (wxValidator*) NULL; + return NULL; } -wxPGChoices& wxPGProperty::GetChoices() +int wxPGProperty::InsertChoice( const wxString& label, int index, int value ) { - wxPGChoiceInfo choiceInfo; - choiceInfo.m_choices = NULL; - GetChoiceInfo(&choiceInfo); - return *choiceInfo.m_choices; + wxPropertyGrid* pg = GetGrid(); + int sel = GetChoiceSelection(); + + int newSel = sel; + + if ( index == wxNOT_FOUND ) + index = m_choices.GetCount(); + + if ( index <= sel ) + newSel++; + + m_choices.Insert(label, index, value); + + if ( sel != newSel ) + SetChoiceSelection(newSel); + + if ( this == pg->GetSelection() ) + GetEditorClass()->InsertItem(pg->GetEditorControl(),label,index); + + return index; } -const wxPGChoices& wxPGProperty::GetChoices() const + +void wxPGProperty::DeleteChoice( int index ) { - return (const wxPGChoices&) ((wxPGProperty*)this)->GetChoices(); + wxPropertyGrid* pg = GetGrid(); + + int sel = GetChoiceSelection(); + int newSel = sel; + + // Adjust current value + if ( sel == index ) + { + SetValueToUnspecified(); + newSel = 0; + } + else if ( index < sel ) + { + newSel--; + } + + m_choices.RemoveAt(index); + + if ( sel != newSel ) + SetChoiceSelection(newSel); + + if ( this == pg->GetSelection() ) + GetEditorClass()->DeleteItem(pg->GetEditorControl(), index); } -unsigned int wxPGProperty::GetChoiceCount() const +int wxPGProperty::GetChoiceSelection() const { - const wxPGChoices& choices = GetChoices(); - if ( &choices && choices.IsOk() ) - return choices.GetCount(); - return 0; + wxVariant value = GetValue(); + wxString valueType = value.GetType(); + int index = wxNOT_FOUND; + + if ( IsValueUnspecified() || !m_choices.GetCount() ) + return wxNOT_FOUND; + + if ( valueType == wxPG_VARIANT_TYPE_LONG ) + { + index = value.GetLong(); + } + else if ( valueType == wxPG_VARIANT_TYPE_STRING ) + { + index = m_choices.Index(value.GetString()); + } + else if ( valueType == wxPG_VARIANT_TYPE_BOOL ) + { + index = value.GetBool()? 1 : 0; + } + + return index; } -const wxPGChoiceEntry* wxPGProperty::GetCurrentChoice() const +void wxPGProperty::SetChoiceSelection( int newValue ) { - wxPGChoiceInfo ci; - ci.m_choices = (wxPGChoices*) NULL; - int index = ((wxPGProperty*)this)->GetChoiceInfo(&ci); - if ( index == -1 || !ci.m_choices || index >= (int)ci.m_choices->GetCount() ) - return NULL; + // Changes value of a property with choices, but only + // works if the value type is long or string. + wxString valueType = GetValue().GetType(); - return &(*ci.m_choices)[index]; + wxCHECK_RET( m_choices.IsOk(), wxT("invalid choiceinfo") ); + + if ( valueType == wxPG_VARIANT_TYPE_STRING ) + { + SetValue( m_choices.GetLabel(newValue) ); + } + else // if ( valueType == wxPG_VARIANT_TYPE_LONG ) + { + SetValue( (long) newValue ); + } } bool wxPGProperty::SetChoices( wxPGChoices& choices ) { - wxPGChoiceInfo ci; - ci.m_choices = (wxPGChoices*) NULL; + m_choices.Assign(choices); - // Unref existing - GetChoiceInfo(&ci); - if ( ci.m_choices ) { - ci.m_choices->Assign(choices); - - //if ( m_parent ) - { - // This may be needed to trigger some initialization - // (but don't do it if property is somewhat uninitialized) - wxVariant defVal = GetDefaultValue(); - if ( defVal.IsNull() ) - return false; - - SetValue(defVal); + // This may be needed to trigger some initialization + // (but don't do it if property is somewhat uninitialized) + wxVariant defVal = GetDefaultValue(); + if ( defVal.IsNull() ) + return false; - return true; - } + SetValue(defVal); } - return false; + + return true; } @@ -1418,28 +1871,16 @@ const wxPGEditor* wxPGProperty::GetEditorClass() const { // TextCtrlAndButton -> ComboBoxAndButton if ( editor->IsKindOf(CLASSINFO(wxPGTextCtrlAndButtonEditor)) ) - editor = wxPG_EDITOR(ChoiceAndButton); + editor = wxPGEditor_ChoiceAndButton; // TextCtrl -> ComboBox else if ( editor->IsKindOf(CLASSINFO(wxPGTextCtrlEditor)) ) - editor = wxPG_EDITOR(ComboBox); + editor = wxPGEditor_ComboBox; } return editor; } - -// Privatizes set of choices -void wxPGProperty::SetChoicesExclusive() -{ - wxPGChoiceInfo ci; - ci.m_choices = (wxPGChoices*) NULL; - - GetChoiceInfo(&ci); - if ( ci.m_choices ) - ci.m_choices->SetExclusive(); -} - bool wxPGProperty::HasVisibleChildren() const { unsigned int i; @@ -1455,12 +1896,6 @@ bool wxPGProperty::HasVisibleChildren() const return false; } -bool wxPGProperty::PrepareValueForDialogEditing( wxPropertyGrid* propGrid ) -{ - return propGrid->EditorValidate(); -} - - bool wxPGProperty::RecreateEditor() { wxPropertyGrid* pg = GetGrid(); @@ -1486,7 +1921,7 @@ void wxPGProperty::SetValueImage( wxBitmap& bmp ) wxSize maxSz = GetGrid()->GetImageSize(); wxSize imSz(bmp.GetWidth(),bmp.GetHeight()); - if ( imSz.x != maxSz.x || imSz.y != maxSz.y ) + if ( imSz.y != maxSz.y ) { // Create a memory DC wxBitmap* bmpNew = new wxBitmap(maxSz.x,maxSz.y,bmp.GetDepth()); @@ -1496,12 +1931,11 @@ void wxPGProperty::SetValueImage( wxBitmap& bmp ) // Scale // FIXME: This is ugly - use image or wait for scaling patch. - double scaleX = (double)maxSz.x / (double)imSz.x; double scaleY = (double)maxSz.y / (double)imSz.y; - dc.SetUserScale(scaleX,scaleY); + dc.SetUserScale(scaleY, scaleY); - dc.DrawBitmap( bmp, 0, 0 ); + dc.DrawBitmap(bmp, 0, 0); m_valueBitmap = bmpNew; } @@ -1565,6 +1999,8 @@ bool wxPGProperty::IsVisible() const wxPropertyGrid* wxPGProperty::GetGridIfDisplayed() const { wxPropertyGridPageState* state = GetParentState(); + if ( !state ) + return NULL; wxPropertyGrid* propGrid = state->GetGrid(); if ( state == propGrid->GetState() ) return propGrid; @@ -1599,48 +2035,33 @@ int wxPGProperty::GetY() const return GetY2(GetGrid()->GetRowHeight()); } - -wxPGProperty* wxPGPropArgCls::GetPtr( wxPropertyGridInterface* methods ) const -{ - if ( !m_isName ) - { - wxASSERT_MSG( m_ptr.property, wxT("invalid property ptr") ); - return m_ptr.property; - } - else if ( m_isName == 1 ) - return methods->GetPropertyByNameA(*m_ptr.name); - else if ( m_isName == 2 ) - return methods->GetPropertyByNameA(m_ptr.rawname); - // 3 is like 1, but ptr is freed in dtor - only needed by wxPython bindings. - else if ( m_isName == 3 ) - return methods->GetPropertyByNameA(*m_ptr.name); - - wxASSERT( m_isName <= 3 ); - return NULL; -} - // This is used by Insert etc. -void wxPGProperty::AddChild2( wxPGProperty* prop, int index, bool correct_mode ) +void wxPGProperty::DoAddChild( wxPGProperty* prop, int index, + bool correct_mode ) { - if ( index < 0 || (size_t)index >= m_children.GetCount() ) + if ( index < 0 || (size_t)index >= m_children.size() ) { - if ( correct_mode ) prop->m_arrIndex = m_children.GetCount(); - m_children.Add( prop ); + if ( correct_mode ) prop->m_arrIndex = m_children.size(); + m_children.push_back( prop ); } else { - m_children.Insert( prop, index ); - if ( correct_mode ) FixIndexesOfChildren( index ); + m_children.insert( m_children.begin()+index, prop); + if ( correct_mode ) FixIndicesOfChildren( index ); } prop->m_parent = this; } -// This is used by properties that have fixed sub-properties -void wxPGProperty::AddChild( wxPGProperty* prop ) +void wxPGProperty::DoPreAddChild( int index, wxPGProperty* prop ) { - prop->m_arrIndex = m_children.GetCount(); - m_children.Add( prop ); + wxASSERT_MSG( prop->GetBaseName().length(), + "Property's children must have unique, non-empty " + "names within their scope" ); + + prop->m_arrIndex = index; + m_children.insert( m_children.begin()+index, + prop ); int custImgHeight = prop->OnMeasureImage().y; if ( custImgHeight < 0 /*|| custImgHeight > 1*/ ) @@ -1649,6 +2070,66 @@ void wxPGProperty::AddChild( wxPGProperty* prop ) prop->m_parent = this; } +void wxPGProperty::AddPrivateChild( wxPGProperty* prop ) +{ + if ( !(m_flags & wxPG_PROP_PARENTAL_FLAGS) ) + SetParentalType(wxPG_PROP_AGGREGATE); + + wxASSERT_MSG( (m_flags & wxPG_PROP_PARENTAL_FLAGS) == + wxPG_PROP_AGGREGATE, + "Do not mix up AddPrivateChild() calls with other " + "property adders." ); + + DoPreAddChild( m_children.size(), prop ); +} + +#if wxPG_COMPATIBILITY_1_4 +void wxPGProperty::AddChild( wxPGProperty* prop ) +{ + AddPrivateChild(prop); +} +#endif + +wxPGProperty* wxPGProperty::InsertChild( int index, + wxPGProperty* childProperty ) +{ + if ( index < 0 ) + index = m_children.size(); + + if ( m_parentState ) + { + m_parentState->DoInsert(this, index, childProperty); + } + else + { + if ( !(m_flags & wxPG_PROP_PARENTAL_FLAGS) ) + SetParentalType(wxPG_PROP_MISC_PARENT); + + wxASSERT_MSG( (m_flags & wxPG_PROP_PARENTAL_FLAGS) == + wxPG_PROP_MISC_PARENT, + "Do not mix up AddPrivateChild() calls with other " + "property adders." ); + + DoPreAddChild( index, childProperty ); + } + + return childProperty; +} + +void wxPGProperty::RemoveChild( wxPGProperty* p ) +{ + wxArrayPGProperty::iterator it; + wxArrayPGProperty& children = m_children; + + for ( it=children.begin(); it != children.end(); it++ ) + { + if ( *it == p ) + { + m_children.erase(it); + break; + } + } +} void wxPGProperty::AdaptListToValue( wxVariant& list, wxVariant* value ) const { @@ -1675,17 +2156,17 @@ void wxPGProperty::AdaptListToValue( wxVariant& list, wxVariant* value ) const unsigned int i; unsigned int n = 0; - //wxLogDebug(wxT(">> %s.AdaptListToValue()"),GetLabel().c_str()); + //wxLogDebug(wxT(">> %s.AdaptListToValue()"),GetBaseName().c_str()); for ( i=0; iGetLabel() ) + if ( childValue.GetName() == child->GetBaseName() ) { //wxLogDebug(wxT(" %s(n=%i), %s"),childValue.GetName().c_str(),n,childValue.GetType().c_str()); - if ( wxPGIsVariantType(childValue, list) ) + if ( childValue.GetType() == wxPG_VARIANT_TYPE_LIST ) { wxVariant cv2(child->GetValue()); child->AdaptListToValue(childValue, &cv2); @@ -1703,7 +2184,7 @@ void wxPGProperty::AdaptListToValue( wxVariant& list, wxVariant* value ) const } -void wxPGProperty::FixIndexesOfChildren( size_t starthere ) +void wxPGProperty::FixIndicesOfChildren( unsigned int starthere ) { size_t i; for ( i=starthere;iGetPropertyByName(name.substr(pos+1,name.length()-pos-1)); } -wxPGProperty* wxPGProperty::GetPropertyByLabelWH( const wxString& label, unsigned int hintIndex ) const +wxPGProperty* wxPGProperty::GetPropertyByNameWH( const wxString& name, unsigned int hintIndex ) const { unsigned int i = hintIndex; @@ -1751,7 +2232,7 @@ wxPGProperty* wxPGProperty::GetPropertyByLabelWH( const wxString& label, unsigne for (;;) { wxPGProperty* p = Item(i); - if ( p->m_label == label ) + if ( p->m_name == name ) return p; if ( i == lastIndex ) @@ -1869,12 +2350,22 @@ void wxPGProperty::Empty() { for ( i=0; iDoDelete(child, true); + } } void wxPGProperty::ChildChanged( wxVariant& WXUNUSED(thisValue), @@ -1896,8 +2387,6 @@ bool wxPGProperty::AreAllChildrenSpecified( wxVariant* pendingList ) const node = pList->begin(); } - // Children in list can be in any order, but we will give hint to - // GetPropertyByLabelWH(). This optimizes for full list parsing. for ( i=0; iGetLabel(); + const wxString& childName = child->GetBaseName(); - for ( ; node != pList->end(); node++ ) + for ( ; node != pList->end(); ++node ) { const wxVariant& item = *((const wxVariant*)*node); - if ( item.GetName() == childLabel ) + if ( item.GetName() == childName ) { listValue = &item; value = item; @@ -1931,7 +2420,7 @@ bool wxPGProperty::AreAllChildrenSpecified( wxVariant* pendingList ) const { const wxVariant* childList = NULL; - if ( listValue && wxPGIsVariantType(*listValue, list) ) + if ( listValue && listValue->GetType() == wxPG_VARIANT_TYPE_LIST ) childList = listValue; if ( !child->AreAllChildrenSpecified((wxVariant*)childList) ) @@ -1949,7 +2438,7 @@ wxPGProperty* wxPGProperty::UpdateParentValues() !parent->IsCategory() && !parent->IsRoot() ) { wxString s; - parent->GenerateComposedValue(s, 0); + parent->DoGenerateComposedValue(s); parent->m_value = s; return parent->UpdateParentValues(); } @@ -1970,74 +2459,6 @@ bool wxPGProperty::IsTextEditable() const return true; } -// Call for after sub-properties added with AddChild -void wxPGProperty::PrepareSubProperties() -{ - wxPropertyGridPageState* state = GetParentState(); - - wxASSERT(state); - - if ( !GetChildCount() ) - return; - - wxByte depth = m_depth + 1; - wxByte depthBgCol = m_depthBgCol; - - FlagType inheritFlags = m_flags & wxPG_INHERITED_PROPFLAGS; - - wxByte bgColIndex = m_bgColIndex; - wxByte fgColIndex = m_fgColIndex; - - // - // Set some values to the children - // - size_t i = 0; - wxPGProperty* nparent = this; - - while ( i < nparent->GetChildCount() ) - { - wxPGProperty* np = nparent->Item(i); - - np->m_parentState = state; - np->m_flags |= inheritFlags; // Hideable also if parent. - np->m_depth = depth; - np->m_depthBgCol = depthBgCol; - np->m_bgColIndex = bgColIndex; - np->m_fgColIndex = fgColIndex; - - // Also handle children of children - if ( np->GetChildCount() > 0 ) - { - nparent = np; - i = 0; - - // Init - nparent->SetParentalType(wxPG_PROP_AGGREGATE); - nparent->SetExpanded(false); - depth++; - } - else - { - // Next sibling - i++; - } - - // After reaching last sibling, go back to processing - // siblings of the parent - while ( i >= nparent->GetChildCount() ) - { - // Exit the loop when top parent hit - if ( nparent == this ) - break; - - depth--; - - i = nparent->GetArrIndex() + 1; - nparent = nparent->GetParent(); - } - } -} - // Call after fixed sub-properties added/removed after creation. // if oldSelInd >= 0 and < new max items, then selection is // moved to it. Note: oldSelInd -2 indicates that this property @@ -2047,14 +2468,20 @@ void wxPGProperty::SubPropsChanged( int oldSelInd ) wxPropertyGridPageState* state = GetParentState(); wxPropertyGrid* grid = state->GetGrid(); - PrepareSubProperties(); + // + // Re-repare children (recursively) + for ( unsigned int i=0; iInitAfterAdded(state, grid); + } - wxPGProperty* sel = (wxPGProperty*) NULL; - if ( oldSelInd >= (int)m_children.GetCount() ) - oldSelInd = (int)m_children.GetCount() - 1; + wxPGProperty* sel = NULL; + if ( oldSelInd >= (int)m_children.size() ) + oldSelInd = (int)m_children.size() - 1; if ( oldSelInd >= 0 ) - sel = (wxPGProperty*) m_children[oldSelInd]; + sel = m_children[oldSelInd]; else if ( oldSelInd == -2 ) sel = this; @@ -2075,11 +2502,14 @@ WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxPGRootProperty,none,TextCtrl) IMPLEMENT_DYNAMIC_CLASS(wxPGRootProperty, wxPGProperty) -wxPGRootProperty::wxPGRootProperty() +wxPGRootProperty::wxPGRootProperty( const wxString& name ) : wxPGProperty() { #ifdef __WXDEBUG__ - m_name = wxS(""); + m_name = name; + m_label = m_name; +#else + wxUnusedVar(name); #endif SetParentalType(0); m_depth = 0; @@ -2125,7 +2555,8 @@ wxPropertyCategory::~wxPropertyCategory() } -wxString wxPropertyCategory::GetValueAsString( int ) const +wxString wxPropertyCategory::ValueToString( wxVariant& WXUNUSED(value), + int WXUNUSED(argFlags) ) const { return wxEmptyString; } @@ -2146,6 +2577,270 @@ void wxPropertyCategory::CalculateTextExtent( wxWindow* wnd, const wxFont& font m_textExtent = x; } +// ----------------------------------------------------------------------- +// wxPGChoices +// ----------------------------------------------------------------------- + +wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, int value ) +{ + AllocExclusive(); + + wxPGChoiceEntry entry(label, value); + return m_data->Insert( -1, entry ); +} + +// ----------------------------------------------------------------------- + +wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, const wxBitmap& bitmap, int value ) +{ + AllocExclusive(); + + wxPGChoiceEntry entry(label, value); + entry.SetBitmap(bitmap); + return m_data->Insert( -1, entry ); +} + +// ----------------------------------------------------------------------- + +wxPGChoiceEntry& wxPGChoices::Insert( const wxPGChoiceEntry& entry, int index ) +{ + AllocExclusive(); + + return m_data->Insert( index, entry ); +} + +// ----------------------------------------------------------------------- + +wxPGChoiceEntry& wxPGChoices::Insert( const wxString& label, int index, int value ) +{ + AllocExclusive(); + + wxPGChoiceEntry entry(label, value); + return m_data->Insert( index, entry ); +} + +// ----------------------------------------------------------------------- + +wxPGChoiceEntry& wxPGChoices::AddAsSorted( const wxString& label, int value ) +{ + AllocExclusive(); + + size_t index = 0; + + while ( index < GetCount() ) + { + int cmpRes = GetLabel(index).Cmp(label); + if ( cmpRes > 0 ) + break; + index++; + } + + wxPGChoiceEntry entry(label, value); + return m_data->Insert( index, entry ); +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::Add( const wxChar** labels, const ValArrItem* values ) +{ + AllocExclusive(); + + unsigned int itemcount = 0; + const wxChar** p = &labels[0]; + while ( *p ) { p++; itemcount++; } + + unsigned int i; + for ( i = 0; i < itemcount; i++ ) + { + int value = i; + if ( values ) + value = values[i]; + wxPGChoiceEntry entry(labels[i], value); + m_data->Insert( i, entry ); + } +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::Add( const wxArrayString& arr, const wxArrayInt& arrint ) +{ + AllocExclusive(); + + unsigned int i; + unsigned int itemcount = arr.size(); + + for ( i = 0; i < itemcount; i++ ) + { + int value = i; + if ( &arrint && arrint.size() ) + value = arrint[i]; + wxPGChoiceEntry entry(arr[i], value); + m_data->Insert( i, entry ); + } +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::RemoveAt(size_t nIndex, size_t count) +{ + AllocExclusive(); + + wxASSERT( m_data->m_refCount != 0xFFFFFFF ); + m_data->m_items.erase(m_data->m_items.begin()+nIndex, + m_data->m_items.begin()+nIndex+count); +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::Clear() +{ + if ( m_data != wxPGChoicesEmptyData ) + { + AllocExclusive(); + m_data->Clear(); + } +} + +// ----------------------------------------------------------------------- + +int wxPGChoices::Index( const wxString& str ) const +{ + if ( IsOk() ) + { + unsigned int i; + for ( i=0; i< m_data->GetCount(); i++ ) + { + const wxPGChoiceEntry& entry = m_data->Item(i); + if ( entry.HasText() && entry.GetText() == str ) + return i; + } + } + return -1; +} + +// ----------------------------------------------------------------------- + +int wxPGChoices::Index( int val ) const +{ + if ( IsOk() ) + { + unsigned int i; + for ( i=0; i< m_data->GetCount(); i++ ) + { + const wxPGChoiceEntry& entry = m_data->Item(i); + if ( entry.GetValue() == val ) + return i; + } + } + return -1; +} + +// ----------------------------------------------------------------------- + +wxArrayString wxPGChoices::GetLabels() const +{ + wxArrayString arr; + unsigned int i; + + if ( this && IsOk() ) + for ( i=0; i= 0 ) + arr.Add(GetValue(index)); + else + arr.Add(wxPG_INVALID_VALUE); + } + } + + return arr; +} + +// ----------------------------------------------------------------------- + +wxArrayInt wxPGChoices::GetIndicesForStrings( const wxArrayString& strings, + wxArrayString* unmatched ) const +{ + wxArrayInt arr; + + if ( IsOk() ) + { + unsigned int i; + for ( i=0; i< strings.size(); i++ ) + { + const wxString& str = strings[i]; + int index = Index(str); + if ( index >= 0 ) + arr.Add(index); + else if ( unmatched ) + unmatched->Add(str); + } + } + + return arr; +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::AllocExclusive() +{ + EnsureData(); + + if ( m_data->m_refCount != 1 ) + { + wxPGChoicesData* data = new wxPGChoicesData(); + data->CopyDataFrom(m_data); + Free(); + m_data = data; + } +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::AssignData( wxPGChoicesData* data ) +{ + Free(); + + if ( data != wxPGChoicesEmptyData ) + { + m_data = data; + data->m_refCount++; + } +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::Init() +{ + m_data = wxPGChoicesEmptyData; +} + +// ----------------------------------------------------------------------- + +void wxPGChoices::Free() +{ + if ( m_data != wxPGChoicesEmptyData ) + { + m_data->DecRef(); + m_data = wxPGChoicesEmptyData; + } +} + // ----------------------------------------------------------------------- // wxPGAttributeStorage // ----------------------------------------------------------------------- @@ -2158,7 +2853,7 @@ wxPGAttributeStorage::~wxPGAttributeStorage() { wxPGHashMapS2P::iterator it; - for ( it = m_map.begin(); it != m_map.end(); it++ ) + for ( it = m_map.begin(); it != m_map.end(); ++it ) { wxVariantData* data = (wxVariantData*) it->second; data->DecRef(); @@ -2172,11 +2867,23 @@ void wxPGAttributeStorage::Set( const wxString& name, const wxVariant& value ) // Free old, if any wxPGHashMapS2P::iterator it = m_map.find(name); if ( it != m_map.end() ) + { ((wxVariantData*)it->second)->DecRef(); + if ( !data ) + { + // If Null variant, just remove from set + m_map.erase(it); + return; + } + } + if ( data ) + { data->IncRef(); - m_map[name] = data; + m_map[name] = data; + } } +#endif // wxUSE_PROPGRID