]> git.saurik.com Git - wxWidgets.git/blobdiff - src/propgrid/props.cpp
Also reset DatePicker property editor's global pointer (fixes #11787)
[wxWidgets.git] / src / propgrid / props.cpp
index ddf4d7ec05f60038dee20f6eb27354120014e81f..cdb43bffdfb24a1da6f7a5d424cfe4f5272b70e6 100644 (file)
@@ -6,7 +6,7 @@
 // Created:     2005-05-14
 // RCS-ID:      $Id$
 // Copyright:   (c) Jaakko Salli
-// Licence:     wxWindows license
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 // For compilers that support precompilation, includes "wx/wx.h".
@@ -31,6 +31,7 @@
     #include "wx/dcclient.h"
     #include "wx/dcmemory.h"
     #include "wx/button.h"
+    #include "wx/bmpbuttn.h"
     #include "wx/pen.h"
     #include "wx/brush.h"
     #include "wx/cursor.h"
@@ -79,22 +80,30 @@ void wxStringProperty::OnSetValue()
     if ( HasFlag(wxPG_PROP_COMPOSED_VALUE) )
     {
         wxString s;
-        GenerateComposedValue(s, 0);
+        DoGenerateComposedValue(s);
         m_value = s;
     }
 }
 
 wxStringProperty::~wxStringProperty() { }
 
-wxString wxStringProperty::GetValueAsString( int argFlags ) const
+wxString wxStringProperty::ValueToString( wxVariant& value,
+                                          int argFlags ) const
 {
-    wxString s = m_value.GetString();
+    wxString s = value.GetString();
 
     if ( GetChildCount() && HasFlag(wxPG_PROP_COMPOSED_VALUE) )
     {
         // Value stored in m_value is non-editable, non-full value
         if ( (argFlags & wxPG_FULL_VALUE) || (argFlags & wxPG_EDITABLE_VALUE) )
-            GenerateComposedValue(s, argFlags);
+        {
+            // Calling this under incorrect conditions will fail
+            wxASSERT_MSG( argFlags & wxPG_VALUE_IS_CURRENT,
+                          "Sorry, currently default wxPGProperty::ValueToString() "
+                          "implementation only works if value is m_value." );
+
+            DoGenerateComposedValue(s, argFlags);
+        }
 
         return s;
     }
@@ -126,7 +135,7 @@ bool wxStringProperty::DoSetAttribute( const wxString& name, wxVariant& value )
     if ( name == wxPG_STRING_PASSWORD )
     {
         m_flags &= ~(wxPG_PROP_PASSWORD);
-        if ( wxPGVariantToInt(value) ) m_flags |= wxPG_PROP_PASSWORD;
+        if ( value.GetLong() ) m_flags |= wxPG_PROP_PASSWORD;
         RecreateEditor();
         return false;
     }
@@ -154,17 +163,17 @@ wxIntProperty::wxIntProperty( const wxString& label, const wxString& name,
 
 wxIntProperty::~wxIntProperty() { }
 
-wxString wxIntProperty::GetValueAsString( int ) const
+wxString wxIntProperty::ValueToString( wxVariant& value,
+                                       int WXUNUSED(argFlags) ) const
 {
-    if ( m_value.GetType() == wxPG_VARIANT_TYPE_LONG )
+    if ( value.GetType() == wxPG_VARIANT_TYPE_LONG )
     {
-        return wxString::Format(wxS("%li"),m_value.GetLong());
+        return wxString::Format(wxS("%li"),value.GetLong());
     }
-    else if ( m_value.GetType() == wxLongLong_VariantType )
+    else if ( value.GetType() == wxPG_VARIANT_TYPE_LONGLONG )
     {
-           wxLongLong ll;
-        ll << m_value;
-           return ll.ToString();
+        wxLongLong ll = value.GetLongLong();
+        return ll.ToString();
     }
 
     return wxEmptyString;
@@ -191,7 +200,7 @@ bool wxIntProperty::StringToValue( wxVariant& variant, const wxString& text, int
 
         int firstNonZeroPos = 0;
 
-        for ( ; i != iMax; i++ )
+        for ( ; i != iMax; ++i )
         {
             wxChar c = *i;
             if ( c != wxS('0') && c != wxS(' ') )
@@ -212,10 +221,9 @@ bool wxIntProperty::StringToValue( wxVariant& variant, const wxString& text, int
         {
             bool doChangeValue = isPrevLong;
 
-            if ( !isPrevLong && variantType == wxLongLong_VariantType )
+            if ( !isPrevLong && variantType == wxPG_VARIANT_TYPE_LONGLONG )
             {
-                wxLongLong oldValue;
-                oldValue << variant;
+                wxLongLong oldValue = variant.GetLongLong();
                 if ( oldValue.GetValue() != value64 )
                     doChangeValue = true;
             }
@@ -223,7 +231,7 @@ bool wxIntProperty::StringToValue( wxVariant& variant, const wxString& text, int
             if ( doChangeValue )
             {
                 wxLongLong ll(value64);
-                variant << ll;
+                variant = ll;
                 return true;
             }
         }
@@ -253,11 +261,22 @@ bool wxIntProperty::IntToValue( wxVariant& variant, int value, int WXUNUSED(argF
     return false;
 }
 
-bool wxIntProperty::DoValidation( const wxPGProperty* property, wxLongLong_t& value, wxPGValidationInfo* pValidationInfo, int mode )
-{
-    // Check for min/max
-    wxLongLong_t min = wxINT64_MIN;
-    wxLongLong_t max = wxINT64_MAX;
+//
+// Common validation code to be called in ValidateValue()
+// implementations.
+//
+// Note that 'value' is reference on purpose, so we can write
+// back to it when mode is wxPG_PROPERTY_VALIDATION_SATURATE.
+//
+template<typename T>
+bool NumericValidation( const wxPGProperty* property,
+                        T& value,
+                        wxPGValidationInfo* pValidationInfo,
+                        int mode,
+                        const wxString& strFmt )
+{
+    T min = (T) wxINT64_MIN;
+    T max = (T) wxINT64_MAX;
     wxVariant variant;
     bool minOk = false;
     bool maxOk = false;
@@ -265,14 +284,14 @@ bool wxIntProperty::DoValidation( const wxPGProperty* property, wxLongLong_t& va
     variant = property->GetAttribute(wxPGGlobalVars->m_strMin);
     if ( !variant.IsNull() )
     {
-        wxPGVariantToLongLong(variant, &min);
+        variant.Convert(&min);
         minOk = true;
     }
 
     variant = property->GetAttribute(wxPGGlobalVars->m_strMax);
     if ( !variant.IsNull() )
     {
-        wxPGVariantToLongLong(variant, &max);
+        variant.Convert(&max);
         maxOk = true;
     }
 
@@ -281,9 +300,20 @@ bool wxIntProperty::DoValidation( const wxPGProperty* property, wxLongLong_t& va
         if ( value < min )
         {
             if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE )
-                pValidationInfo->SetFailureMessage(
-                    wxString::Format(_("Value must be %lld or higher"),min)
-                    );
+            {
+                wxString msg;
+                wxString smin = wxString::Format(strFmt, min);
+                wxString smax = wxString::Format(strFmt, max);
+                if ( !maxOk )
+                    msg = wxString::Format(
+                                _("Value must be %s or higher."),
+                                smin.c_str());
+                else
+                    msg = wxString::Format(
+                                _("Value must be between %s and %s."),
+                                smin.c_str(), smax.c_str());
+                pValidationInfo->SetFailureMessage(msg);
+            }
             else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE )
                 value = min;
             else
@@ -297,9 +327,20 @@ bool wxIntProperty::DoValidation( const wxPGProperty* property, wxLongLong_t& va
         if ( value > max )
         {
             if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE )
-                pValidationInfo->SetFailureMessage(
-                    wxString::Format(_("Value must be %lld or higher"),min)
-                    );
+            {
+                wxString msg;
+                wxString smin = wxString::Format(strFmt, min);
+                wxString smax = wxString::Format(strFmt, max);
+                if ( !minOk )
+                    msg = wxString::Format(
+                                _("Value must be %s or less."),
+                                smax.c_str());
+                else
+                    msg = wxString::Format(
+                                _("Value must be between %s and %s."),
+                                smin.c_str(), smax.c_str());
+                pValidationInfo->SetFailureMessage(msg);
+            }
             else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE )
                 value = max;
             else
@@ -310,12 +351,24 @@ bool wxIntProperty::DoValidation( const wxPGProperty* property, wxLongLong_t& va
     return true;
 }
 
-bool wxIntProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& validationInfo ) const
+bool wxIntProperty::DoValidation( const wxPGProperty* property,
+                                  wxLongLong_t& value,
+                                  wxPGValidationInfo* pValidationInfo,
+                                  int mode )
 {
-    wxLongLong_t ll;
-    if ( wxPGVariantToLongLong(value, &ll) )
-        return DoValidation(this, ll, &validationInfo, wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE);
-    return true;
+    return NumericValidation<wxLongLong_t>(property,
+                                           value,
+                                           pValidationInfo,
+                                           mode,
+                                           wxS("%lld"));
+}
+
+bool wxIntProperty::ValidateValue( wxVariant& value,
+                                   wxPGValidationInfo& validationInfo ) const
+{
+    wxLongLong_t ll = value.GetLongLong().GetValue();
+    return DoValidation(this, ll, &validationInfo,
+                        wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE);
 }
 
 wxValidator* wxIntProperty::GetClassValidator()
@@ -345,21 +398,21 @@ wxValidator* wxIntProperty::DoGetValidator() const
 
 #define wxPG_UINT_TEMPLATE_MAX 8
 
-static const wxChar* gs_uintTemplates32[wxPG_UINT_TEMPLATE_MAX] = {
+static const wxChar* const gs_uintTemplates32[wxPG_UINT_TEMPLATE_MAX] = {
     wxT("%x"),wxT("0x%x"),wxT("$%x"),
     wxT("%X"),wxT("0x%X"),wxT("$%X"),
     wxT("%u"),wxT("%o")
 };
 
-static const wxChar* gs_uintTemplates64[wxPG_UINT_TEMPLATE_MAX] = {
-    wxT("%") wxLongLongFmtSpec wxT("x"),
-    wxT("0x%") wxLongLongFmtSpec wxT("x"),
-    wxT("$%") wxLongLongFmtSpec wxT("x"),
-    wxT("%") wxLongLongFmtSpec wxT("X"),
-    wxT("0x%") wxLongLongFmtSpec wxT("X"),
-    wxT("$%") wxLongLongFmtSpec wxT("X"),
-    wxT("%") wxLongLongFmtSpec wxT("u"),
-    wxT("%") wxLongLongFmtSpec wxT("o")
+static const char* const gs_uintTemplates64[wxPG_UINT_TEMPLATE_MAX] = {
+    "%" wxLongLongFmtSpec "x",
+    "0x%" wxLongLongFmtSpec "x",
+    "$%" wxLongLongFmtSpec "x",
+    "%" wxLongLongFmtSpec "X",
+    "0x%" wxLongLongFmtSpec "X",
+    "$%" wxLongLongFmtSpec "X",
+    "%" wxLongLongFmtSpec "u",
+    "%" wxLongLongFmtSpec "o"
 };
 
 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxUIntProperty,wxPGProperty,
@@ -388,19 +441,20 @@ wxUIntProperty::wxUIntProperty( const wxString& label, const wxString& name,
 
 wxUIntProperty::~wxUIntProperty() { }
 
-wxString wxUIntProperty::GetValueAsString( int ) const
+wxString wxUIntProperty::ValueToString( wxVariant& value,
+                                        int WXUNUSED(argFlags) ) const
 {
     size_t index = m_base + m_prefix;
     if ( index >= wxPG_UINT_TEMPLATE_MAX )
         index = wxPG_BASE_DEC;
 
-    if ( m_value.GetType() == wxPG_VARIANT_TYPE_LONG )
+    if ( value.GetType() == wxPG_VARIANT_TYPE_LONG )
     {
-        return wxString::Format(gs_uintTemplates32[index], (unsigned long)m_value.GetLong());
+        return wxString::Format(gs_uintTemplates32[index],
+                                (unsigned long)value.GetLong());
     }
 
-    wxULongLong ull;
-    ull << m_value;
+    wxULongLong ull = value.GetULongLong();
 
     return wxString::Format(gs_uintTemplates64[index], ull.GetValue());
 }
@@ -429,18 +483,16 @@ bool wxUIntProperty::StringToValue( wxVariant& variant, const wxString& text, in
         {
             bool doChangeValue = isPrevLong;
 
-            if ( !isPrevLong && variantType == wxULongLong_VariantType )
+            if ( !isPrevLong && variantType == wxPG_VARIANT_TYPE_ULONGLONG )
             {
-                wxULongLong oldValue;
-                oldValue << variant;
+                wxULongLong oldValue = variant.GetULongLong();
                 if ( oldValue.GetValue() != value64 )
                     doChangeValue = true;
             }
 
             if ( doChangeValue )
             {
-                wxULongLong ull(value64);
-                variant << ull;
+                variant = wxULongLong(value64);
                 return true;
             }
         }
@@ -468,50 +520,15 @@ bool wxUIntProperty::IntToValue( wxVariant& variant, int number, int WXUNUSED(ar
     return false;
 }
 
-#ifdef ULLONG_MAX
-  #define wxUINT64_MAX ULLONG_MAX
-  #define wxUINT64_MIN wxULL(0)
-#else
-  #define wxUINT64_MAX wxULL(0xFFFFFFFFFFFFFFFF)
-  #define wxUINT64_MIN wxULL(0)
-#endif
-
 bool wxUIntProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& validationInfo ) const
 {
-    // Check for min/max
-    wxULongLong_t ll;
-    if ( wxPGVariantToULongLong(value, &ll) )
-    {
-        wxULongLong_t min = wxUINT64_MIN;
-        wxULongLong_t max = wxUINT64_MAX;
-        wxVariant variant;
-
-        variant = GetAttribute(wxPGGlobalVars->m_strMin);
-        if ( !variant.IsNull() )
-        {
-            wxPGVariantToULongLong(variant, &min);
-            if ( ll < min )
-            {
-                validationInfo.SetFailureMessage(
-                    wxString::Format(_("Value must be %llu or higher"),min)
-                    );
-                return false;
-            }
-        }
-        variant = GetAttribute(wxPGGlobalVars->m_strMax);
-        if ( !variant.IsNull() )
-        {
-            wxPGVariantToULongLong(variant, &max);
-            if ( ll > max )
-            {
-                validationInfo.SetFailureMessage(
-                    wxString::Format(_("Value must be %llu or less"),max)
-                    );
-                return false;
-            }
-        }
-    }
-    return true;
+    wxULongLong_t uul = value.GetULongLong().GetValue();
+    return
+    NumericValidation<wxULongLong_t>(this,
+                                     uul,
+                                     &validationInfo,
+                                     wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE,
+                                     wxS("%llu"));
 }
 
 bool wxUIntProperty::DoSetAttribute( const wxString& name, wxVariant& value )
@@ -596,7 +613,7 @@ void wxPropertyGrid::DoubleToString(wxString& target,
         wxString::const_iterator i = target.end() - 1;
         size_t new_len = target.length() - 1;
 
-        for ( ; i != target.begin(); i-- )
+        for ( ; i != target.begin(); --i )
         {
             if ( *i != wxS('0') )
                 break;
@@ -612,16 +629,17 @@ void wxPropertyGrid::DoubleToString(wxString& target,
     }
 }
 
-wxString wxFloatProperty::GetValueAsString( int argFlags ) const
+wxString wxFloatProperty::ValueToString( wxVariant& value,
+                                         int argFlags ) const
 {
     wxString text;
-    if ( !m_value.IsNull() )
+    if ( !value.IsNull() )
     {
         wxPropertyGrid::DoubleToString(text,
-                                       m_value,
+                                       value,
                                        m_precision,
                                        !(argFlags & wxPG_FULL_VALUE),
-                                       (wxString*) NULL);
+                                       NULL);
     }
     return text;
 }
@@ -652,70 +670,25 @@ bool wxFloatProperty::StringToValue( wxVariant& variant, const wxString& text, i
     return false;
 }
 
-bool wxFloatProperty::DoValidation( const wxPGProperty* property, double& value, wxPGValidationInfo* pValidationInfo, int mode )
+bool wxFloatProperty::DoValidation( const wxPGProperty* property,
+                                    double& value,
+                                    wxPGValidationInfo* pValidationInfo,
+                                    int mode )
 {
-    // Check for min/max
-    double min = (double)wxINT64_MIN;
-    double max = (double)wxINT64_MAX;
-    wxVariant variant;
-    bool minOk = false;
-    bool maxOk = false;
-
-    variant = property->GetAttribute(wxPGGlobalVars->m_strMin);
-    if ( !variant.IsNull() )
-    {
-        wxPGVariantToDouble(variant, &min);
-        minOk = true;
-    }
-
-    variant = property->GetAttribute(wxPGGlobalVars->m_strMax);
-    if ( !variant.IsNull() )
-    {
-        wxPGVariantToDouble(variant, &max);
-        maxOk = true;
-    }
-
-    if ( minOk )
-    {
-        if ( value < min )
-        {
-            if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE )
-                pValidationInfo->SetFailureMessage(
-                    wxString::Format(_("Value must be %f or higher"),min)
-                    );
-            else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE )
-                value = min;
-            else
-                value = max - (min - value);
-            return false;
-        }
-    }
-
-    if ( maxOk )
-    {
-        wxPGVariantToDouble(variant, &max);
-        if ( value > max )
-        {
-            if ( mode == wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE )
-                pValidationInfo->SetFailureMessage(
-                    wxString::Format(_("Value must be %f or less"),max)
-                    );
-            else if ( mode == wxPG_PROPERTY_VALIDATION_SATURATE )
-                value = max;
-            else
-                value = min + (value - max);
-            return false;
-        }
-    }
-    return true;
+    return NumericValidation<double>(property,
+                                     value,
+                                     pValidationInfo,
+                                     mode,
+                                     wxS("%g"));
 }
 
-bool wxFloatProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& validationInfo ) const
+bool
+wxFloatProperty::ValidateValue( wxVariant& value,
+                                wxPGValidationInfo& validationInfo ) const
 {
-    double fpv;
-    if ( wxPGVariantToDouble(value, &fpv) )
-        return DoValidation(this, fpv, &validationInfo, wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE);
-    return true;
+    double fpv = value.GetDouble();
+    return DoValidation(this, fpv, &validationInfo,
+                        wxPG_PROPERTY_VALIDATION_ERROR_MESSAGE);
 }
 
 bool wxFloatProperty::DoSetAttribute( const wxString& name, wxVariant& value )
@@ -766,15 +739,16 @@ wxBoolProperty::wxBoolProperty( const wxString& label, const wxString& name, boo
 
 wxBoolProperty::~wxBoolProperty() { }
 
-wxString wxBoolProperty::GetValueAsString( int argFlags ) const
+wxString wxBoolProperty::ValueToString( wxVariant& value,
+                                        int argFlags ) const
 {
-    bool value = m_value.GetBool();
+    bool boolValue = value.GetBool();
 
     // As a fragment of composite string value,
     // make it a little more readable.
     if ( argFlags & wxPG_COMPOSITE_FRAGMENT )
     {
-        if ( value )
+        if ( boolValue )
         {
             return m_label;
         }
@@ -795,12 +769,12 @@ wxString wxBoolProperty::GetValueAsString( int argFlags ) const
 
     if ( !(argFlags & wxPG_FULL_VALUE) )
     {
-        return wxPGGlobalVars->m_boolChoices[value?1:0].GetText();
+        return wxPGGlobalVars->m_boolChoices[boolValue?1:0].GetText();
     }
 
     wxString text;
 
-    if (value) text = wxS("true");
+    if ( boolValue ) text = wxS("true");
     else text = wxS("false");
 
     return text;
@@ -845,8 +819,7 @@ bool wxBoolProperty::DoSetAttribute( const wxString& name, wxVariant& value )
 #if wxPG_INCLUDE_CHECKBOX
     if ( name == wxPG_BOOL_USE_CHECKBOX )
     {
-        int ival = wxPGVariantToInt(value);
-        if ( ival )
+        if ( value.GetLong() )
             m_flags |= wxPG_PROP_USE_CHECKBOX;
         else
             m_flags &= ~(wxPG_PROP_USE_CHECKBOX);
@@ -855,8 +828,7 @@ bool wxBoolProperty::DoSetAttribute( const wxString& name, wxVariant& value )
 #endif
     if ( name == wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING )
     {
-        int ival = wxPGVariantToInt(value);
-        if ( ival )
+        if ( value.GetLong() )
             m_flags |= wxPG_PROP_USE_DCC;
         else
             m_flags &= ~(wxPG_PROP_USE_DCC);
@@ -866,35 +838,108 @@ bool wxBoolProperty::DoSetAttribute( const wxString& name, wxVariant& value )
 }
 
 // -----------------------------------------------------------------------
-// wxBaseEnumProperty
+// wxEnumProperty
 // -----------------------------------------------------------------------
 
-int wxBaseEnumProperty::ms_nextIndex = -2;
+IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty, wxPGProperty)
+
+WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty,long,Choice)
+
+wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name, const wxChar* const* labels,
+    const long* values, int value ) : wxPGProperty(label,name)
+{
+    SetIndex(0);
+
+    if ( labels )
+    {
+        m_choices.Add(labels,values);
+
+        if ( GetItemCount() )
+            SetValue( (long)value );
+    }
+}
 
-wxBaseEnumProperty::wxBaseEnumProperty( const wxString& label, const wxString& name )
+wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name, const wxChar* const* labels,
+    const long* values, wxPGChoices* choicesCache, int value )
+    : wxPGProperty(label,name)
+{
+    SetIndex(0);
+
+    wxASSERT( choicesCache );
+
+    if ( choicesCache->IsOk() )
+    {
+        m_choices.Assign( *choicesCache );
+        m_value = wxPGVariant_Zero;
+    }
+    else if ( labels )
+    {
+        m_choices.Add(labels,values);
+
+        if ( GetItemCount() )
+            SetValue( (long)value );
+    }
+}
+
+wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name,
+    const wxArrayString& labels, const wxArrayInt& values, int value )
+    : wxPGProperty(label,name)
+{
+    SetIndex(0);
+
+    if ( &labels && labels.size() )
+    {
+        m_choices.Set(labels, values);
+
+        if ( GetItemCount() )
+            SetValue( (long)value );
+    }
+}
+
+wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name,
+    wxPGChoices& choices, int value )
     : wxPGProperty(label,name)
 {
-    m_value = wxPGVariant_Zero;
+    m_choices.Assign( choices );
+
+    if ( GetItemCount() )
+        SetValue( (long)value );
 }
 
-/** If has values array, then returns number at index with value -
-    otherwise just returns the value.
-*/
-int wxBaseEnumProperty::GetIndexForValue( int value ) const
+int wxEnumProperty::GetIndexForValue( int value ) const
 {
+    if ( !m_choices.IsOk() )
+        return -1;
+
+    int intVal = m_choices.Index(value);
+    if ( intVal >= 0 )
+        return intVal;
+
     return value;
 }
 
-void wxBaseEnumProperty::OnSetValue()
+wxEnumProperty::~wxEnumProperty ()
+{
+}
+
+int wxEnumProperty::ms_nextIndex = -2;
+
+void wxEnumProperty::OnSetValue()
 {
     wxString variantType = m_value.GetType();
 
     if ( variantType == wxPG_VARIANT_TYPE_LONG )
+    {
         ValueFromInt_( m_value, m_value.GetLong(), wxPG_FULL_VALUE );
+    }
     else if ( variantType == wxPG_VARIANT_TYPE_STRING )
+    {
         ValueFromString_( m_value, m_value.GetString(), 0 );
+    }
     else
-        wxASSERT( false );
+    {
+        wxFAIL;
+    }
 
     if ( ms_nextIndex != -2 )
     {
@@ -903,7 +948,7 @@ void wxBaseEnumProperty::OnSetValue()
     }
 }
 
-bool wxBaseEnumProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& WXUNUSED(validationInfo) ) const
+bool wxEnumProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& WXUNUSED(validationInfo) ) const
 {
     // Make sure string value is in the list,
     // unless property has string as preferred value type
@@ -915,52 +960,43 @@ bool wxBaseEnumProperty::ValidateValue( wxVariant& value, wxPGValidationInfo& WX
     return true;
 }
 
-wxString wxBaseEnumProperty::GetValueAsString( int ) const
+wxString wxEnumProperty::ValueToString( wxVariant& value,
+                                            int WXUNUSED(argFlags) ) const
 {
-    if ( m_value.GetType() == wxPG_VARIANT_TYPE_STRING )
-        return m_value.GetString();
+    if ( value.GetType() == wxPG_VARIANT_TYPE_STRING )
+        return value.GetString();
 
-    if ( m_index >= 0 )
-    {
-        int unusedVal;
-        const wxString* pstr = GetEntry( m_index, &unusedVal );
+    int index = m_choices.Index(value.GetLong());
+    if ( index < 0 )
+        return wxEmptyString;
 
-        if ( pstr )
-            return *pstr;
-    }
-    return wxEmptyString;
+    return m_choices.GetLabel(index);
 }
 
-bool wxBaseEnumProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
+bool wxEnumProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
 {
     return ValueFromString_( variant, text, argFlags );
 }
 
-bool wxBaseEnumProperty::IntToValue( wxVariant& variant, int intVal, int argFlags ) const
+bool wxEnumProperty::IntToValue( wxVariant& variant, int intVal, int argFlags ) const
 {
     return ValueFromInt_( variant, intVal, argFlags );
 }
 
-bool wxBaseEnumProperty::ValueFromString_( wxVariant& value, const wxString& text, int argFlags ) const
+bool wxEnumProperty::ValueFromString_( wxVariant& value, const wxString& text, int argFlags ) const
 {
-    size_t i = 0;
-    const wxString* entryLabel;
-    int entryValue;
     int useIndex = -1;
     long useValue = 0;
 
-    entryLabel = GetEntry(i, &entryValue);
-    while ( entryLabel )
+    for ( unsigned int i=0; i<m_choices.GetCount(); i++ )
     {
-        if ( text.CmpNoCase(*entryLabel) == 0 )
+        const wxString& entryLabel = m_choices.GetLabel(i);
+        if ( text.CmpNoCase(entryLabel) == 0 )
         {
             useIndex = (int)i;
-            useValue = (long)entryValue;
+            useValue = m_choices.GetValue(i);
             break;
         }
-
-        i++;
-        entryLabel = GetEntry(i, &entryValue);
     }
 
     bool asText = false;
@@ -969,9 +1005,7 @@ bool wxBaseEnumProperty::ValueFromString_( wxVariant& value, const wxString& tex
 
     // If text not any of the choices, store as text instead
     // (but only if we are wxEditEnumProperty)
-    if ( useIndex == -1 &&
-         (value.GetType() != wxPG_VARIANT_TYPE_STRING || (m_value.GetString() != text)) &&
-         isEdit )
+    if ( useIndex == -1 && isEdit )
     {
         asText = true;
     }
@@ -983,7 +1017,7 @@ bool wxBaseEnumProperty::ValueFromString_( wxVariant& value, const wxString& tex
         setAsNextIndex = -1;
         value = text;
     }
-    else if ( m_index != useIndex )
+    else if ( useIndex != GetIndex() )
     {
         if ( useIndex != -1 )
         {
@@ -1012,7 +1046,7 @@ bool wxBaseEnumProperty::ValueFromString_( wxVariant& value, const wxString& tex
     return false;
 }
 
-bool wxBaseEnumProperty::ValueFromInt_( wxVariant& variant, int intVal, int argFlags ) const
+bool wxEnumProperty::ValueFromInt_( wxVariant& variant, int intVal, int argFlags ) const
 {
     // If wxPG_FULL_VALUE is *not* in argFlags, then intVal is index from combo box.
     //
@@ -1024,7 +1058,7 @@ bool wxBaseEnumProperty::ValueFromInt_( wxVariant& variant, int intVal, int argF
     }
     else
     {
-        if ( m_index != intVal )
+        if ( intVal != GetIndex() )
         {
             ms_nextIndex = intVal;
         }
@@ -1033,7 +1067,7 @@ bool wxBaseEnumProperty::ValueFromInt_( wxVariant& variant, int intVal, int argF
     if ( ms_nextIndex != -2 )
     {
         if ( !(argFlags & wxPG_FULL_VALUE) )
-            GetEntry(intVal, &intVal);
+            intVal = m_choices.GetValue(intVal);
 
         variant = (long)intVal;
 
@@ -1043,120 +1077,28 @@ bool wxBaseEnumProperty::ValueFromInt_( wxVariant& variant, int intVal, int argF
     return false;
 }
 
-void wxBaseEnumProperty::SetIndex( int index )
-{
-    ms_nextIndex = -2;
-    m_index = index;
-}
-
-int wxBaseEnumProperty::GetIndex() const
-{
-    if ( ms_nextIndex != -2 )
-        return ms_nextIndex;
-    return m_index;
-}
-
-// -----------------------------------------------------------------------
-// wxEnumProperty
-// -----------------------------------------------------------------------
-
-IMPLEMENT_DYNAMIC_CLASS(wxEnumProperty, wxPGProperty)
-
-WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEnumProperty,long,Choice)
-
-wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name, const wxChar** labels,
-    const long* values, int value ) : wxBaseEnumProperty(label,name)
-{
-    SetIndex(0);
-
-    if ( labels )
-    {
-        m_choices.Add(labels,values);
-
-        if ( GetItemCount() )
-            SetValue( (long)value );
-    }
-}
-
-wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name, const wxChar** labels,
-    const long* values, wxPGChoices* choicesCache, int value )
-    : wxBaseEnumProperty(label,name)
+void
+wxEnumProperty::OnValidationFailure( wxVariant& WXUNUSED(pendingValue) )
 {
-    SetIndex(0);
-
-    wxASSERT( choicesCache );
-
-    if ( choicesCache->IsOk() )
-    {
-        m_choices.Assign( *choicesCache );
-        m_value = wxPGVariant_Zero;
-    }
-    else if ( labels )
-    {
-        m_choices.Add(labels,values);
-
-        if ( GetItemCount() )
-            SetValue( (long)value );
-    }
+    // Revert index
+    ResetNextIndex();
 }
 
-wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name,
-    const wxArrayString& labels, const wxArrayInt& values, int value ) : wxBaseEnumProperty(label,name)
+void wxEnumProperty::SetIndex( int index )
 {
-    SetIndex(0);
-
-    if ( &labels && labels.size() )
-    {
-        m_choices.Set(labels, values);
-
-        if ( GetItemCount() )
-            SetValue( (long)value );
-    }
-}
-
-wxEnumProperty::wxEnumProperty( const wxString& label, const wxString& name,
-    wxPGChoices& choices, int value )
-    : wxBaseEnumProperty(label,name)
-{
-    m_choices.Assign( choices );
-
-    if ( GetItemCount() )
-        SetValue( (long)value );
+    ms_nextIndex = -2;
+    m_index = index;
 }
 
-int wxEnumProperty::GetIndexForValue( int value ) const
+int wxEnumProperty::GetIndex() const
 {
-    if ( !m_choices.IsOk() )
+    if ( m_value.IsNull() )
         return -1;
 
-    if ( m_choices.HasValues() )
-    {
-        int intVal = m_choices.Index(value);
-        if ( intVal >= 0 )
-            return intVal;
-    }
-
-    return value;
-}
-
-wxEnumProperty::~wxEnumProperty ()
-{
-}
-
-const wxString* wxEnumProperty::GetEntry( size_t index, int* pvalue ) const
-{
-    if ( m_choices.IsOk() && index < m_choices.GetCount() )
-    {
-        int value = (int)index;
-        if ( m_choices.HasValue(index) )
-            value = m_choices.GetValue(index);
-
-        if ( pvalue )
-            *pvalue = value;
+    if ( ms_nextIndex != -2 )
+        return ms_nextIndex;
 
-        return &m_choices.GetLabel(index);
-    }
-    return (const wxString*) NULL;
+    return m_index;
 }
 
 // -----------------------------------------------------------------------
@@ -1167,14 +1109,14 @@ IMPLEMENT_DYNAMIC_CLASS(wxEditEnumProperty, wxPGProperty)
 
 WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxEditEnumProperty,wxString,ComboBox)
 
-wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name, const wxChar** labels,
+wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name, const wxChar* const* labels,
     const long* values, const wxString& value )
     : wxEnumProperty(label,name,labels,values,0)
 {
     SetValue( value );
 }
 
-wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name, const wxChar** labels,
+wxEditEnumProperty::wxEditEnumProperty( const wxString& label, const wxString& name, const wxChar* const* labels,
     const long* values, wxPGChoices* choicesCache, const wxString& value )
     : wxEnumProperty(label,name,labels,values,choicesCache,0)
 {
@@ -1209,8 +1151,6 @@ WX_PG_IMPLEMENT_PROPERTY_CLASS_PLAIN(wxFlagsProperty,long,TextCtrl)
 
 void wxFlagsProperty::Init()
 {
-    SetParentalType(wxPG_PROP_AGGREGATE);
-
     long value = m_value;
 
     //
@@ -1248,6 +1188,12 @@ void wxFlagsProperty::Init()
 
     m_children.clear();
 
+    // Relay wxPG_BOOL_USE_CHECKBOX and wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING
+    // to child bool property controls.
+    long attrUseCheckBox = GetAttributeAsLong(wxPG_BOOL_USE_CHECKBOX, 0);
+    long attrUseDCC = GetAttributeAsLong(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING,
+                                         0);
+
     if ( m_choices.IsOk() )
     {
         const wxPGChoices& choices = m_choices;
@@ -1255,10 +1201,7 @@ void wxFlagsProperty::Init()
         for ( i=0; i<GetItemCount(); i++ )
         {
             bool child_val;
-            if ( choices.HasValue(i) )
-                child_val = ( value & choices.GetValue(i) )?true:false;
-            else
-                child_val = ( value & (1<<i) )?true:false;
+            child_val = ( value & choices.GetValue(i) )?true:false;
 
             wxPGProperty* boolProp;
             wxString label = GetLabel(i);
@@ -1273,7 +1216,13 @@ void wxFlagsProperty::Init()
             {
                 boolProp = new wxBoolProperty( label, label, child_val );
             }
-            AddChild(boolProp);
+            if ( attrUseCheckBox )
+                boolProp->SetAttribute(wxPG_BOOL_USE_CHECKBOX,
+                                       true);
+            if ( attrUseDCC )
+                boolProp->SetAttribute(wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING,
+                                       true);
+            AddPrivateChild(boolProp);
         }
 
         m_oldChoicesData = m_choices.GetDataPtr();
@@ -1286,9 +1235,9 @@ void wxFlagsProperty::Init()
 }
 
 wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
-    const wxChar** labels, const long* values, long value ) : wxPGProperty(label,name)
+    const wxChar* const* labels, const long* values, long value ) : wxPGProperty(label,name)
 {
-    m_oldChoicesData = (wxPGChoicesData*) NULL;
+    m_oldChoicesData = NULL;
 
     if ( labels )
     {
@@ -1308,7 +1257,7 @@ wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
         const wxArrayString& labels, const wxArrayInt& values, int value )
     : wxPGProperty(label,name)
 {
-    m_oldChoicesData = (wxPGChoicesData*) NULL;
+    m_oldChoicesData = NULL;
 
     if ( &labels && labels.size() )
     {
@@ -1328,7 +1277,7 @@ wxFlagsProperty::wxFlagsProperty( const wxString& label, const wxString& name,
     wxPGChoices& choices, long value )
     : wxPGProperty(label,name)
 {
-    m_oldChoicesData = (wxPGChoicesData*) NULL;
+    m_oldChoicesData = NULL;
 
     if ( choices.IsOk() )
     {
@@ -1365,10 +1314,7 @@ void wxFlagsProperty::OnSetValue()
         const wxPGChoices& choices = m_choices;
         for ( i = 0; i < GetItemCount(); i++ )
         {
-            if ( choices.HasValue(i) )
-                fullFlags |= choices.GetValue(i);
-            else
-                fullFlags |= (1<<i);
+            fullFlags |= choices.GetValue(i);
         }
 
         val &= fullFlags;
@@ -1394,37 +1340,32 @@ void wxFlagsProperty::OnSetValue()
         {
             int flag;
 
-            if ( choices.HasValue(i) )
-                flag = choices.GetValue(i);
-            else
-                flag = (1<<i);
+            flag = choices.GetValue(i);
 
             if ( (newFlags & flag) != (m_oldValue & flag) )
-                Item(i)->SetFlag( wxPG_PROP_MODIFIED );
+                Item(i)->ChangeFlag( wxPG_PROP_MODIFIED, true );
         }
 
         m_oldValue = newFlags;
     }
 }
 
-wxString wxFlagsProperty::GetValueAsString( int ) const
+wxString wxFlagsProperty::ValueToString( wxVariant& value,
+                                         int WXUNUSED(argFlags) ) const
 {
     wxString text;
 
     if ( !m_choices.IsOk() )
         return text;
 
-    long flags = m_value;
+    long flags = value;
     unsigned int i;
     const wxPGChoices& choices = m_choices;
 
     for ( i = 0; i < GetItemCount(); i++ )
     {
         int doAdd;
-        if ( choices.HasValue(i) )
-            doAdd = ( flags & choices.GetValue(i) );
-        else
-            doAdd = ( flags & (1<<i) );
+        doAdd = ( flags & choices.GetValue(i) );
 
         if ( doAdd )
         {
@@ -1486,9 +1427,7 @@ long wxFlagsProperty::IdToBit( const wxString& id ) const
     {
         if ( id == GetLabel(i) )
         {
-            if ( m_choices.HasValue(i) )
-                return m_choices.GetValue(i);
-            return (1<<i);
+            return m_choices.GetValue(i);
         }
     }
     return -1;
@@ -1506,16 +1445,13 @@ void wxFlagsProperty::RefreshChildren()
     {
         long flag;
 
-        if ( choices.HasValue(i) )
-            flag = choices.GetValue(i);
-        else
-            flag = (1<<i);
+        flag = choices.GetValue(i);
 
         long subVal = flags & flag;
         wxPGProperty* p = Item(i);
 
         if ( subVal != (m_oldValue & flag) )
-            p->SetFlag( wxPG_PROP_MODIFIED );
+            p->ChangeFlag( wxPG_PROP_MODIFIED, true );
 
         p->SetValue( subVal?true:false );
     }
@@ -1523,16 +1459,34 @@ void wxFlagsProperty::RefreshChildren()
     m_oldValue = flags;
 }
 
-void wxFlagsProperty::ChildChanged( wxVariant& thisValue, int childIndex, wxVariant& childValue ) const
+wxVariant wxFlagsProperty::ChildChanged( wxVariant& thisValue,
+                                         int childIndex,
+                                         wxVariant& childValue ) const
 {
     long oldValue = thisValue.GetLong();
     long val = childValue.GetLong();
-    unsigned long vi = (1<<childIndex);
-    if ( m_choices.HasValue(childIndex) ) vi = m_choices.GetValue(childIndex);
+    unsigned long vi = m_choices.GetValue(childIndex);
+
     if ( val )
-        thisValue = (long)(oldValue | vi);
-    else
-        thisValue = (long)(oldValue & ~(vi));
+        return (long) (oldValue | vi);
+
+    return (long) (oldValue & ~(vi));
+}
+
+bool wxFlagsProperty::DoSetAttribute( const wxString& name, wxVariant& value )
+{
+    if ( name == wxPG_BOOL_USE_CHECKBOX ||
+         name == wxPG_BOOL_USE_DOUBLE_CLICK_CYCLING )
+    {
+        for ( size_t i=0; i<GetChildCount(); i++ )
+        {
+            Item(i)->SetAttribute(name, value);
+        }
+        // Must return false so that the attribute is stored in
+        // flag property's actual property storage
+        return false;
+    }
+    return false;
 }
 
 // -----------------------------------------------------------------------
@@ -1559,17 +1513,21 @@ bool wxDirProperty::OnButtonClick( wxPropertyGrid* propGrid, wxString& value )
     // Update property value from editor, if necessary
     wxSize dlg_sz(300,400);
 
+    wxString dlgMessage(m_dlgMessage);
+    if ( dlgMessage.empty() )
+        dlgMessage = _("Choose a directory:");
     wxDirDialog dlg( propGrid,
-                     m_dlgMessage.length() ? m_dlgMessage : wxString(_("Choose a directory:")),
+                     dlgMessage,
                      value,
                      0,
 #if !wxPG_SMALL_SCREEN
                      propGrid->GetGoodEditorDialogPosition(this,dlg_sz),
-                     dlg_sz );
+                     dlg_sz
 #else
                      wxDefaultPosition,
-                     wxDefaultSize );
+                     wxDefaultSize
 #endif
+                    );
 
     if ( dlg.ShowModal() == wxID_OK )
     {
@@ -1602,7 +1560,8 @@ bool wxPGFileDialogAdapter::DoShowDialog( wxPropertyGrid* propGrid, wxPGProperty
     if ( property->IsKindOf(CLASSINFO(wxFileProperty)) )
     {
         fileProp = ((wxFileProperty*)property);
-        path = fileProp->m_filename.GetPath();
+        wxFileName filename = fileProp->GetValue().GetString();
+        path = filename.GetPath();
         indFilter = fileProp->m_indFilter;
 
         if ( !path.length() && fileProp->m_basePath.length() )
@@ -1654,10 +1613,9 @@ wxFileProperty::wxFileProperty( const wxString& label, const wxString& name,
 
 wxFileProperty::~wxFileProperty() {}
 
-#if wxUSE_VALIDATORS
-
 wxValidator* wxFileProperty::GetClassValidator()
 {
+#if wxUSE_VALIDATORS
     WX_PG_DOGETVALIDATOR_ENTRY()
 
     // Atleast wxPython 2.6.2.1 required that the string argument is given
@@ -1675,6 +1633,9 @@ wxValidator* wxFileProperty::GetClassValidator()
     validator->SetExcludes(exChars);
 
     WX_PG_DOGETVALIDATOR_EXIT(validator)
+#else
+    return NULL;
+#endif
 }
 
 wxValidator* wxFileProperty::DoGetValidator() const
@@ -1682,24 +1643,21 @@ wxValidator* wxFileProperty::DoGetValidator() const
     return GetClassValidator();
 }
 
-#endif
-
 void wxFileProperty::OnSetValue()
 {
     const wxString& fnstr = m_value.GetString();
 
-    m_filename = fnstr;
+    wxFileName filename = fnstr;
 
-    if ( !m_filename.HasName() )
+    if ( !filename.HasName() )
     {
         m_value = wxPGVariant_EmptyString;
-        m_filename.Clear();
     }
 
     // Find index for extension.
     if ( m_indFilter < 0 && fnstr.length() )
     {
-        wxString ext = m_filename.GetExt();
+        wxString ext = filename.GetExt();
         int curind = 0;
         size_t pos = 0;
         size_t len = m_wildcard.length();
@@ -1736,29 +1694,44 @@ void wxFileProperty::OnSetValue()
     }
 }
 
-wxString wxFileProperty::GetValueAsString( int argFlags ) const
+wxFileName wxFileProperty::GetFileName() const
+{
+    wxFileName filename;
+
+    if ( !m_value.IsNull() )
+        filename = m_value.GetString();
+
+    return filename;
+}
+
+wxString wxFileProperty::ValueToString( wxVariant& value,
+                                        int argFlags ) const
 {
-    // Always return empty string when name component is empty
-    wxString fullName = m_filename.GetFullName();
+    wxFileName filename = value.GetString();
+
+    if ( !filename.HasName() )
+        return wxEmptyString;
+
+    wxString fullName = filename.GetFullName();
     if ( !fullName.length() )
-        return fullName;
+        return wxEmptyString;
 
     if ( argFlags & wxPG_FULL_VALUE )
     {
-        return m_filename.GetFullPath();
+        return filename.GetFullPath();
     }
     else if ( m_flags & wxPG_PROP_SHOW_FULL_FILENAME )
     {
         if ( m_basePath.Length() )
         {
-            wxFileName fn2(m_filename);
+            wxFileName fn2(filename);
             fn2.MakeRelativeTo(m_basePath);
             return fn2.GetFullPath();
         }
-        return m_filename.GetFullPath();
+        return filename.GetFullPath();
     }
 
-    return m_filename.GetFullName();
+    return filename.GetFullName();
 }
 
 wxPGEditorDialogAdapter* wxFileProperty::GetEditorDialog() const
@@ -1768,9 +1741,11 @@ wxPGEditorDialogAdapter* wxFileProperty::GetEditorDialog() const
 
 bool wxFileProperty::StringToValue( wxVariant& variant, const wxString& text, int argFlags ) const
 {
+    wxFileName filename = variant.GetString();
+
     if ( (m_flags & wxPG_PROP_SHOW_FULL_FILENAME) || (argFlags & wxPG_FULL_VALUE) )
     {
-        if ( m_filename != text )
+        if ( filename != text )
         {
             variant = text;
             return true;
@@ -1778,9 +1753,9 @@ bool wxFileProperty::StringToValue( wxVariant& variant, const wxString& text, in
     }
     else
     {
-        if ( m_filename.GetFullName() != text )
+        if ( filename.GetFullName() != text )
         {
-            wxFileName fn = m_filename;
+            wxFileName fn = filename;
             fn.SetFullName(text);
             variant = fn.GetFullPath();
             return true;
@@ -1796,7 +1771,7 @@ bool wxFileProperty::DoSetAttribute( const wxString& name, wxVariant& value )
     // stored in m_attributes.
     if ( name == wxPG_FILE_SHOW_FULL_PATH )
     {
-        if ( wxPGVariantToInt(value) )
+        if ( value.GetLong() )
             m_flags |= wxPG_PROP_SHOW_FULL_FILENAME;
         else
             m_flags &= ~(wxPG_PROP_SHOW_FULL_FILENAME);
@@ -1873,9 +1848,10 @@ wxLongStringProperty::wxLongStringProperty( const wxString& label, const wxStrin
 
 wxLongStringProperty::~wxLongStringProperty() {}
 
-wxString wxLongStringProperty::GetValueAsString( int ) const
+wxString wxLongStringProperty::ValueToString( wxVariant& value,
+                                              int WXUNUSED(argFlags) ) const
 {
-    return m_value;
+    return value;
 }
 
 bool wxLongStringProperty::OnEvent( wxPropertyGrid* propGrid, wxWindow* WXUNUSED(primary),
@@ -1940,14 +1916,14 @@ bool wxLongStringProperty::DisplayEditorDialog( wxPGProperty* prop, wxPropertyGr
 
     rowsizer->Add( ed, 1, wxEXPAND|wxALL, spacing );
     topsizer->Add( rowsizer, 1, wxEXPAND, 0 );
-    rowsizer = new wxBoxSizer( wxHORIZONTAL );
-    const int but_sz_flags =
-        wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT;
-    rowsizer->Add( new wxButton(dlg,wxID_OK,_("Ok")),
-        0, but_sz_flags, spacing );
-    rowsizer->Add( new wxButton(dlg,wxID_CANCEL,_("Cancel")),
-        0, but_sz_flags, spacing );
-    topsizer->Add( rowsizer, 0, wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL, 0 );
+
+    wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer();
+    buttonSizer->AddButton(new wxButton(dlg, wxID_OK));
+    buttonSizer->AddButton(new wxButton(dlg, wxID_CANCEL));
+    buttonSizer->Realize();
+    topsizer->Add( buttonSizer, 0,
+                   wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxBOTTOM|wxRIGHT,
+                   spacing );
 
     dlg->SetSizer( topsizer );
     topsizer->SetSizeHints( dlg );
@@ -1980,70 +1956,49 @@ bool wxLongStringProperty::StringToValue( wxVariant& variant, const wxString& te
     return false;
 }
 
+#if wxUSE_EDITABLELISTBOX
+
 // -----------------------------------------------------------------------
-// wxArrayEditorDialog
+// wxPGArrayEditorDialog
 // -----------------------------------------------------------------------
 
-BEGIN_EVENT_TABLE(wxArrayEditorDialog, wxDialog)
-    EVT_IDLE(wxArrayEditorDialog::OnIdle)
-    EVT_LISTBOX(24, wxArrayEditorDialog::OnListBoxClick)
-    EVT_TEXT_ENTER(21, wxArrayEditorDialog::OnAddClick)
-    EVT_BUTTON(22, wxArrayEditorDialog::OnAddClick)
-    EVT_BUTTON(23, wxArrayEditorDialog::OnDeleteClick)
-    EVT_BUTTON(25, wxArrayEditorDialog::OnUpClick)
-    EVT_BUTTON(26, wxArrayEditorDialog::OnDownClick)
-    EVT_BUTTON(27, wxArrayEditorDialog::OnUpdateClick)
-    //EVT_BUTTON(28, wxArrayEditorDialog::OnCustomEditClick)
+BEGIN_EVENT_TABLE(wxPGArrayEditorDialog, wxDialog)
+    EVT_IDLE(wxPGArrayEditorDialog::OnIdle)
 END_EVENT_TABLE()
 
-IMPLEMENT_ABSTRACT_CLASS(wxArrayEditorDialog, wxDialog)
+IMPLEMENT_ABSTRACT_CLASS(wxPGArrayEditorDialog, wxDialog)
 
-#include "wx/statline.h"
+#include "wx/editlbox.h"
+#include "wx/listctrl.h"
 
 // -----------------------------------------------------------------------
 
-void wxArrayEditorDialog::OnIdle(wxIdleEvent& event)
+void wxPGArrayEditorDialog::OnIdle(wxIdleEvent& event)
 {
-    //
-    // Do control focus detection here.
-    //
+    // Repair focus - wxEditableListBox has bitmap buttons, which
+    // get focus, and lose focus (into the oblivion) when they
+    // become disabled due to change in control state.
 
-    wxWindow* focused = FindFocus();
+    wxWindow* lastFocused = m_lastFocused;
+    wxWindow* focus = ::wxWindow::FindFocus();
 
-    // This strange focus thing is a workaround for wxGTK wxListBox focus
-    // reporting bug.
-    if ( m_curFocus == 0 && focused != m_edValue &&
-         focused != m_butAdd && focused != m_butUpdate &&
-         m_lbStrings->GetSelection() >= 0 )
-    {
-        // ListBox was just focused.
-        m_butAdd->Enable(false);
-        m_butUpdate->Enable(false);
-        m_butRemove->Enable(true);
-        m_butUp->Enable(true);
-        m_butDown->Enable(true);
-        m_curFocus = 1;
-    }
-    else if ( (m_curFocus == 1 && focused == m_edValue) /*|| m_curFocus == 2*/ )
+    // If last focused control became disabled, set focus back to
+    // wxEditableListBox
+    if ( lastFocused && focus != lastFocused &&
+         lastFocused->GetParent() == m_elbSubPanel &&
+         !lastFocused->IsEnabled() )
     {
-        // TextCtrl was just focused.
-        m_butAdd->Enable(true);
-        bool upd_enable = false;
-        if ( m_lbStrings->GetCount() && m_lbStrings->GetSelection() >= 0 )
-            upd_enable = true;
-        m_butUpdate->Enable(upd_enable);
-        m_butRemove->Enable(false);
-        m_butUp->Enable(false);
-        m_butDown->Enable(false);
-        m_curFocus = 0;
+        m_elb->GetListCtrl()->SetFocus();
     }
 
+    m_lastFocused = focus;
+
     event.Skip();
 }
 
 // -----------------------------------------------------------------------
 
-wxArrayEditorDialog::wxArrayEditorDialog()
+wxPGArrayEditorDialog::wxPGArrayEditorDialog()
     : wxDialog()
 {
     Init();
@@ -2051,14 +2006,16 @@ wxArrayEditorDialog::wxArrayEditorDialog()
 
 // -----------------------------------------------------------------------
 
-void wxArrayEditorDialog::Init()
+void wxPGArrayEditorDialog::Init()
 {
-    m_custBtText = (const wxChar*) NULL;
+    m_lastFocused = NULL;
+    m_hasCustomNewAction = false;
+    m_itemPendingAtIndex = -1;
 }
 
 // -----------------------------------------------------------------------
 
-wxArrayEditorDialog::wxArrayEditorDialog( wxWindow *parent,
+wxPGArrayEditorDialog::wxPGArrayEditorDialog( wxWindow *parent,
                                           const wxString& message,
                                           const wxString& caption,
                                           long style,
@@ -2072,7 +2029,7 @@ wxArrayEditorDialog::wxArrayEditorDialog( wxWindow *parent,
 
 // -----------------------------------------------------------------------
 
-bool wxArrayEditorDialog::Create( wxWindow *parent,
+bool wxPGArrayEditorDialog::Create( wxWindow *parent,
                                   const wxString& message,
                                   const wxString& caption,
                                   long style,
@@ -2082,6 +2039,7 @@ bool wxArrayEditorDialog::Create( wxWindow *parent,
     // On wxMAC the dialog shows incorrectly if style is not exactly wxCAPTION
     // FIXME: This should be only a temporary fix.
 #ifdef __WXMAC__
+    wxUnusedVar(style);
     int useStyle = wxCAPTION;
 #else
     int useStyle = style;
@@ -2099,11 +2057,6 @@ bool wxArrayEditorDialog::Create( wxWindow *parent,
 
     m_modified = false;
 
-    m_curFocus = 1;
-
-    const int but_sz_flags =
-        wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxALL; //wxBOTTOM|wxLEFT|wxRIGHT;
-
     wxBoxSizer* topsizer = new wxBoxSizer( wxVERTICAL );
 
     // Message
@@ -2111,81 +2064,60 @@ bool wxArrayEditorDialog::Create( wxWindow *parent,
         topsizer->Add( new wxStaticText(this,-1,message),
             0, wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxALL, spacing );
 
-    // String editor
-    wxBoxSizer* rowsizer = new wxBoxSizer( wxHORIZONTAL );
-    m_edValue = new wxTextCtrl(this,21,wxEmptyString,
-        wxDefaultPosition,wxDefaultSize,wxTE_PROCESS_ENTER);
-    wxValidator* validator = GetTextCtrlValidator();
-    if ( validator )
-    {
-        m_edValue->SetValidator( *validator );
-        delete validator;
-    }
-    rowsizer->Add( m_edValue,
-        1, wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxALL, spacing );
-
-    // Add button
-    m_butAdd = new wxButton(this,22,_("Add"));
-    rowsizer->Add( m_butAdd,
-        0, wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT, spacing );
-    topsizer->Add( rowsizer, 0, wxEXPAND, spacing );
-
-    // Separator line
-    topsizer->Add( new wxStaticLine(this,-1),
-        0, wxEXPAND|wxBOTTOM|wxLEFT|wxRIGHT, spacing );
+    m_elb = new wxEditableListBox(this, wxID_ANY, message,
+                                  wxDefaultPosition,
+                                  wxDefaultSize,
+                                  wxEL_ALLOW_NEW |
+                                  wxEL_ALLOW_EDIT |
+                                  wxEL_ALLOW_DELETE);
 
-    rowsizer = new wxBoxSizer( wxHORIZONTAL );
-
-    // list box
-    m_lbStrings = new wxListBox(this, 24, wxDefaultPosition, wxDefaultSize);
-    unsigned int i;
-    for ( i=0; i<ArrayGetCount(); i++ )
-        m_lbStrings->Append( ArrayGet(i) );
-    rowsizer->Add( m_lbStrings, 1, wxEXPAND|wxRIGHT, spacing );
-
-    // Manipulator buttons
-    wxBoxSizer* colsizer = new wxBoxSizer( wxVERTICAL );
-    m_butCustom = (wxButton*) NULL;
-    if ( m_custBtText )
-    {
-        m_butCustom = new wxButton(this,28,::wxGetTranslation(m_custBtText));
-        colsizer->Add( m_butCustom,
-            0, wxALIGN_CENTER|wxTOP/*wxALIGN_LEFT|wxALIGN_CENTRE_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT*/,
-            spacing );
-    }
-    m_butUpdate = new wxButton(this,27,_("Update"));
-    colsizer->Add( m_butUpdate,
-        0, wxALIGN_CENTER|wxTOP, spacing );
-    m_butRemove = new wxButton(this,23,_("Remove"));
-    colsizer->Add( m_butRemove,
-        0, wxALIGN_CENTER|wxTOP, spacing );
-    m_butUp = new wxButton(this,25,_("Up"));
-    colsizer->Add( m_butUp,
-        0, wxALIGN_CENTER|wxTOP, spacing );
-    m_butDown = new wxButton(this,26,_("Down"));
-    colsizer->Add( m_butDown,
-        0, wxALIGN_CENTER|wxTOP, spacing );
-    rowsizer->Add( colsizer, 0, 0, spacing );
-
-    topsizer->Add( rowsizer, 1, wxLEFT|wxRIGHT|wxEXPAND, spacing );
-
-    // Separator line
-    topsizer->Add( new wxStaticLine(this,-1),
-        0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, spacing );
-
-    // buttons
-    rowsizer = new wxBoxSizer( wxHORIZONTAL );
-    /*
-    const int but_sz_flags =
-        wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxBOTTOM|wxLEFT|wxRIGHT;
-    */
-    rowsizer->Add( new wxButton(this,wxID_OK,_("Ok")),
-        0, but_sz_flags, spacing );
-    rowsizer->Add( new wxButton(this,wxID_CANCEL,_("Cancel")),
-        0, but_sz_flags, spacing );
-    topsizer->Add( rowsizer, 0, wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL, 0 );
-
-    m_edValue->SetFocus();
+    // Populate the list box
+    wxArrayString arr;
+    for ( unsigned int i=0; i<ArrayGetCount(); i++ )
+        arr.push_back(ArrayGet(i));
+    m_elb->SetStrings(arr);
+
+    // Connect event handlers
+    wxButton* but;
+    wxListCtrl* lc = m_elb->GetListCtrl();
+
+    but = m_elb->GetNewButton();
+    m_elbSubPanel = but->GetParent();
+    but->Connect(but->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
+        wxCommandEventHandler(wxPGArrayEditorDialog::OnAddClick),
+        NULL, this);
+
+    but = m_elb->GetDelButton();
+    but->Connect(but->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
+        wxCommandEventHandler(wxPGArrayEditorDialog::OnDeleteClick),
+        NULL, this);
+
+    but = m_elb->GetUpButton();
+    but->Connect(but->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
+        wxCommandEventHandler(wxPGArrayEditorDialog::OnUpClick),
+        NULL, this);
+
+    but = m_elb->GetDownButton();
+    but->Connect(but->GetId(), wxEVT_COMMAND_BUTTON_CLICKED,
+        wxCommandEventHandler(wxPGArrayEditorDialog::OnDownClick),
+        NULL, this);
+
+    lc->Connect(lc->GetId(), wxEVT_COMMAND_LIST_END_LABEL_EDIT,
+        wxListEventHandler(wxPGArrayEditorDialog::OnEndLabelEdit),
+        NULL, this);
+
+    topsizer->Add( m_elb, 1, wxEXPAND, spacing );
+
+    // Standard dialog buttons
+    wxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer();
+    buttonSizer->AddButton(new wxButton(this, wxID_OK));
+    buttonSizer->AddButton(new wxButton(this, wxID_CANCEL));
+    buttonSizer->Realize();
+    topsizer->Add( buttonSizer, 0,
+                   wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL|wxALL,
+                   spacing );
+
+    m_elb->SetFocus();
 
     SetSizer( topsizer );
     topsizer->SetSizeHints( this );
@@ -2203,108 +2135,139 @@ bool wxArrayEditorDialog::Create( wxWindow *parent,
 
 // -----------------------------------------------------------------------
 
-void wxArrayEditorDialog::OnAddClick(wxCommandEvent& )
+int wxPGArrayEditorDialog::GetSelection() const
+{
+    wxListCtrl* lc = m_elb->GetListCtrl();
+
+    int index = lc->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+    if ( index == -1 )
+        return wxNOT_FOUND;
+
+    return index;
+}
+
+// -----------------------------------------------------------------------
+
+void wxPGArrayEditorDialog::OnAddClick(wxCommandEvent& event)
 {
-    wxString text = m_edValue->GetValue();
-    if ( text.length() )
+    wxListCtrl* lc = m_elb->GetListCtrl();
+    int newItemIndex = lc->GetItemCount() - 1;
+
+    if ( m_hasCustomNewAction )
     {
-        if ( ArrayInsert( text, -1 ) )
+        wxString str;
+        if ( OnCustomNewAction(&str) )
         {
-            m_lbStrings->Append( text );
-            m_modified = true;
-            m_edValue->Clear();
+            if ( ArrayInsert(str, newItemIndex) )
+            {
+                lc->InsertItem(newItemIndex, str);
+                m_modified = true;
+            }
         }
+
+        // Do *not* skip the event! We do not want the wxEditableListBox
+        // to do anything.
+    }
+    else
+    {
+        m_itemPendingAtIndex = newItemIndex;
+
+        event.Skip();
     }
 }
 
 // -----------------------------------------------------------------------
 
-void wxArrayEditorDialog::OnDeleteClick(wxCommandEvent& )
+void wxPGArrayEditorDialog::OnDeleteClick(wxCommandEvent& event)
 {
-    int index = m_lbStrings->GetSelection();
+    int index = GetSelection();
     if ( index >= 0 )
     {
         ArrayRemoveAt( index );
-        m_lbStrings->Delete ( index );
         m_modified = true;
     }
+
+    event.Skip();
 }
 
 // -----------------------------------------------------------------------
 
-void wxArrayEditorDialog::OnUpClick(wxCommandEvent& )
+void wxPGArrayEditorDialog::OnUpClick(wxCommandEvent& event)
 {
-    int index = m_lbStrings->GetSelection();
+    int index = GetSelection();
     if ( index > 0 )
     {
         ArraySwap(index-1,index);
-        /*wxString old_str = m_array[index-1];
-        wxString new_str = m_array[index];
-        m_array[index-1] = new_str;
-        m_array[index] = old_str;*/
-        m_lbStrings->SetString ( index-1, ArrayGet(index-1) );
-        m_lbStrings->SetString ( index, ArrayGet(index) );
-        m_lbStrings->SetSelection ( index-1 );
         m_modified = true;
     }
+
+    event.Skip();
 }
 
 // -----------------------------------------------------------------------
 
-void wxArrayEditorDialog::OnDownClick(wxCommandEvent& )
+void wxPGArrayEditorDialog::OnDownClick(wxCommandEvent& event)
 {
-    int index = m_lbStrings->GetSelection();
-    int lastStringIndex = ((int) m_lbStrings->GetCount()) - 1;
+    wxListCtrl* lc = m_elb->GetListCtrl();
+    int index = GetSelection();
+    int lastStringIndex = lc->GetItemCount() - 1;
     if ( index >= 0 && index < lastStringIndex )
     {
-        ArraySwap(index,index+1);
-        /*wxString old_str = m_array[index+1];
-        wxString new_str = m_array[index];
-        m_array[index+1] = new_str;
-        m_array[index] = old_str;*/
-        m_lbStrings->SetString ( index+1, ArrayGet(index+1) );
-        m_lbStrings->SetString ( index, ArrayGet(index) );
-        m_lbStrings->SetSelection ( index+1 );
+        ArraySwap(index, index+1);
         m_modified = true;
     }
+
+    event.Skip();
 }
 
 // -----------------------------------------------------------------------
 
-void wxArrayEditorDialog::OnUpdateClick(wxCommandEvent& )
+void wxPGArrayEditorDialog::OnEndLabelEdit(wxListEvent& event)
 {
-    int index = m_lbStrings->GetSelection();
-    if ( index >= 0 )
+    wxString str = event.GetLabel();
+
+    if ( m_itemPendingAtIndex >= 0 )
     {
-        wxString str = m_edValue->GetValue();
-        if ( ArraySet(index,str) )
+        // Add a new item
+        if ( ArrayInsert(str, m_itemPendingAtIndex) )
         {
-            m_lbStrings->SetString ( index, str );
-            //m_array[index] = str;
             m_modified = true;
         }
+        else
+        {
+            // Editable list box doesn't really respect Veto(), but
+            // it recognizes if no text was added, so we simulate
+            // Veto() using it.
+            event.m_item.SetText(wxEmptyString);
+            m_elb->GetListCtrl()->SetItemText(m_itemPendingAtIndex,
+                                              wxEmptyString);
+
+            event.Veto();
+        }
     }
-}
-
-// -----------------------------------------------------------------------
-
-void wxArrayEditorDialog::OnListBoxClick(wxCommandEvent& )
-{
-    int index = m_lbStrings->GetSelection();
-    if ( index >= 0 )
+    else
     {
-        m_edValue->SetValue( m_lbStrings->GetString(index) );
+        // Change an existing item
+        int index = GetSelection();
+        wxASSERT( index != wxNOT_FOUND );
+        if ( ArraySet(index, str) )
+            m_modified = true;
+        else
+            event.Veto();
     }
+
+    event.Skip();
 }
 
+#endif // wxUSE_EDITABLELISTBOX
+
 // -----------------------------------------------------------------------
 // wxPGArrayStringEditorDialog
 // -----------------------------------------------------------------------
 
-IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog, wxArrayEditorDialog)
+IMPLEMENT_DYNAMIC_CLASS(wxPGArrayStringEditorDialog, wxPGArrayEditorDialog)
 
-BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog, wxArrayEditorDialog)
-    EVT_BUTTON(28, wxPGArrayStringEditorDialog::OnCustomEditClick)
+BEGIN_EVENT_TABLE(wxPGArrayStringEditorDialog, wxPGArrayEditorDialog)
 END_EVENT_TABLE()
 
 // -----------------------------------------------------------------------
@@ -2348,27 +2311,20 @@ void wxPGArrayStringEditorDialog::ArraySwap( size_t first, size_t second )
 }
 
 wxPGArrayStringEditorDialog::wxPGArrayStringEditorDialog()
-    : wxArrayEditorDialog()
+    : wxPGArrayEditorDialog()
 {
     Init();
 }
 
 void wxPGArrayStringEditorDialog::Init()
 {
-    m_pCallingClass = (wxArrayStringProperty*) NULL;
+    m_pCallingClass = NULL;
 }
 
-void wxPGArrayStringEditorDialog::OnCustomEditClick(wxCommandEvent& )
+bool
+wxPGArrayStringEditorDialog::OnCustomNewAction(wxString* resString)
 {
-    wxASSERT( m_pCallingClass );
-    wxString str = m_edValue->GetValue();
-    if ( m_pCallingClass->OnCustomStringEdit(m_parent,str) )
-    {
-        //m_edValue->SetValue ( str );
-        m_lbStrings->Append ( str );
-        m_array.Add ( str );
-        m_modified = true;
-    }
+    return m_pCallingClass->OnCustomStringEdit(m_parent, *resString);
 }
 
 // -----------------------------------------------------------------------
@@ -2386,6 +2342,7 @@ wxArrayStringProperty::wxArrayStringProperty( const wxString& label,
                                                         const wxArrayString& array )
     : wxPGProperty(label,name)
 {
+    m_delimiter = ',';
     SetValue( array );
 }
 
@@ -2396,52 +2353,80 @@ void wxArrayStringProperty::OnSetValue()
     GenerateValueAsString();
 }
 
-wxString wxArrayStringProperty::GetValueAsString( int WXUNUSED(argFlags) ) const
+void
+wxArrayStringProperty::ConvertArrayToString(const wxArrayString& arr,
+                                            wxString* pString,
+                                            const wxUniChar& delimiter) const
+{
+    if ( delimiter == '"' || delimiter == '\'' )
+    {
+        // Quoted strings
+        ArrayStringToString(*pString,
+                            arr,
+                            delimiter,
+                            Escape | QuoteStrings);
+    }
+    else
+    {
+        // Regular delimiter
+        ArrayStringToString(*pString,
+                            arr,
+                            delimiter,
+                            0);
+    }
+}
+
+wxString wxArrayStringProperty::ValueToString( wxVariant& WXUNUSED(value),
+                                               int argFlags ) const
 {
-    return m_display;
+    //
+    // If this is called from GetValueAsString(), return cached string
+    if ( argFlags & wxPG_VALUE_IS_CURRENT )
+    {
+        return m_display;
+    }
+
+    wxArrayString arr = m_value.GetArrayString();
+    wxString s;
+    ConvertArrayToString(arr, &s, m_delimiter);
+    return s;
 }
 
 // Converts wxArrayString to a string separated by delimeters and spaces.
 // preDelim is useful for "str1" "str2" style. Set flags to 1 to do slash
 // conversion.
-void wxPropertyGrid::ArrayStringToString( wxString& dst, const wxArrayString& src,
-                                          wxChar preDelim, wxChar postDelim,
-                                          int flags )
+void
+wxArrayStringProperty::ArrayStringToString( wxString& dst,
+                                            const wxArrayString& src,
+                                            wxUniChar delimiter, int flags )
 {
     wxString pdr;
+    wxString preas;
 
     unsigned int i;
     unsigned int itemCount = src.size();
 
-    wxChar preas[2];
-
     dst.Empty();
 
-    if ( !preDelim )
-        preas[0] = 0;
-    else if ( (flags & 1) )
+    if ( flags & Escape )
     {
-        preas[0] = preDelim;
-        preas[1] = 0;
-        pdr = wxS("\\");
-        pdr += preDelim;
+        preas = delimiter;
+        pdr = wxS("\\") + static_cast<wchar_t>(delimiter);
     }
 
     if ( itemCount )
         dst.append( preas );
 
-    wxASSERT( postDelim );
-    wxString postDelimStr(postDelim);
-    //wxString preDelimStr(preDelim);
+    wxString delimStr(delimiter);
 
     for ( i = 0; i < itemCount; i++ )
     {
         wxString str( src.Item(i) );
 
         // Do some character conversion.
-        // Convertes \ to \\ and <preDelim> to \<preDelim>
-        // Useful when preDelim and postDelim are "\"".
-        if ( flags & 1 )
+        // Converts \ to \\ and $delimiter to \$delimiter
+        // Useful when quoting.
+        if ( flags & Escape )
         {
             str.Replace( wxS("\\"), wxS("\\\\"), true );
             if ( pdr.length() )
@@ -2452,22 +2437,19 @@ void wxPropertyGrid::ArrayStringToString( wxString& dst, const wxArrayString& sr
 
         if ( i < (itemCount-1) )
         {
-            dst.append( postDelimStr );
+            dst.append( delimStr );
             dst.append( wxS(" ") );
             dst.append( preas );
         }
-        else if ( preDelim )
-            dst.append( postDelimStr );
+        else if ( flags & QuoteStrings )
+            dst.append( delimStr );
     }
 }
 
-#define ARRSTRPROP_ARRAY_TO_STRING(STRING,ARRAY) \
-    wxPropertyGrid::ArrayStringToString(STRING,ARRAY,wxS('"'),wxS('"'),1);
-
 void wxArrayStringProperty::GenerateValueAsString()
 {
     wxArrayString arr = m_value.GetArrayString();
-    ARRSTRPROP_ARRAY_TO_STRING(m_display, arr)
+    ConvertArrayToString(arr, &m_display, m_delimiter);
 }
 
 // Default implementation doesn't do anything.
@@ -2476,7 +2458,7 @@ bool wxArrayStringProperty::OnCustomStringEdit( wxWindow*, wxString& )
     return false;
 }
 
-wxArrayEditorDialog* wxArrayStringProperty::CreateEditorDialog()
+wxPGArrayEditorDialog* wxArrayStringProperty::CreateEditorDialog()
 {
     return new wxPGArrayStringEditorDialog();
 }
@@ -2492,7 +2474,7 @@ bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid* propGrid,
         return false;
 
     // Create editor dialog.
-    wxArrayEditorDialog* dlg = CreateEditorDialog();
+    wxPGArrayEditorDialog* dlg = CreateEditorDialog();
 #if wxUSE_VALIDATORS
     wxValidator* validator = GetValidator();
     wxPGInDialogValidator dialogValidator;
@@ -2525,9 +2507,10 @@ bool wxArrayStringProperty::OnButtonClick( wxPropertyGrid* propGrid,
             {
                 wxArrayString actualValue = value.GetArrayString();
                 wxString tempStr;
-                ARRSTRPROP_ARRAY_TO_STRING(tempStr, actualValue)
+                ConvertArrayToString(actualValue, &tempStr, m_delimiter);
             #if wxUSE_VALIDATORS
-                if ( dialogValidator.DoValidate( propGrid, validator, tempStr ) )
+                if ( dialogValidator.DoValidate(propGrid, validator,
+                                                tempStr) )
             #endif
                 {
                     SetValueInEvent( actualValue );
@@ -2556,25 +2539,48 @@ bool wxArrayStringProperty::OnEvent( wxPropertyGrid* propGrid,
     return false;
 }
 
-bool wxArrayStringProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
+bool wxArrayStringProperty::StringToValue( wxVariant& variant,
+                                           const wxString& text, int ) const
 {
     wxArrayString arr;
 
-    WX_PG_TOKENIZER2_BEGIN(text,wxS('"'))
+    if ( m_delimiter == '"' || m_delimiter == '\'' )
+    {
+        // Quoted strings
+        WX_PG_TOKENIZER2_BEGIN(text, m_delimiter)
 
-        // Need to replace backslashes with empty characters
-        // (opposite what is done in GenerateValueString).
-        token.Replace ( wxS("\\"), wxEmptyString, true );
+            // Need to replace backslashes with empty characters
+            // (opposite what is done in ConvertArrayToString()).
+            token.Replace ( wxS("\\\\"), wxS("\\"), true );
 
-        arr.Add( token );
+            arr.Add( token );
 
-    WX_PG_TOKENIZER2_END()
+        WX_PG_TOKENIZER2_END()
+    }
+    else
+    {
+        // Regular delimiter
+        WX_PG_TOKENIZER1_BEGIN(text, m_delimiter)
+            arr.Add( token );
+        WX_PG_TOKENIZER1_END()
+    }
 
     variant = arr;
 
     return true;
 }
 
+bool wxArrayStringProperty::DoSetAttribute( const wxString& name, wxVariant& value )
+{
+    if ( name == wxPG_ARRAY_DELIMITER )
+    {
+        m_delimiter = value.GetChar();
+        GenerateValueAsString();
+        return false;
+    }
+    return true;
+}
+
 // -----------------------------------------------------------------------
 // wxPGInDialogValidator
 // -----------------------------------------------------------------------