]> git.saurik.com Git - wxWidgets.git/blobdiff - src/propgrid/advprops.cpp
fixed wxXmlDocument::Save() to interpret the indentstep argument correctly
[wxWidgets.git] / src / propgrid / advprops.cpp
index dcc6b982076037441e0f6a80e41c74205789effb..22c5089f77f4f21dda3a4ed87d36e38735648de7 100644 (file)
@@ -4,7 +4,7 @@
 // Author:      Jaakko Salli
 // Modified by:
 // Created:     2004-09-25
-// RCS-ID:      $Id:
+// RCS-ID:      $Id$
 // Copyright:   (c) Jaakko Salli
 // Licence:     wxWindows license
 /////////////////////////////////////////////////////////////////////////////
     #include "wx/scrolwin.h"
     #include "wx/dirdlg.h"
     #include "wx/combobox.h"
-    #include "wx/layout.h"
     #include "wx/sizer.h"
     #include "wx/textdlg.h"
     #include "wx/filedlg.h"
     #include "wx/intl.h"
+    #include "wx/wxcrtvararg.h"
 #endif
 
 #define __wxPG_SOURCE_FILE__
 
-#include <wx/propgrid/propgrid.h>
+#include "wx/propgrid/propgrid.h"
 
 #if wxPG_INCLUDE_ADVPROPS
 
-#include <wx/propgrid/advprops.h>
+#include "wx/propgrid/advprops.h"
 
 #ifdef __WXMSW__
-    #include <wx/msw/private.h>
-    #include <wx/msw/dc.h>
+    #include "wx/msw/private.h"
+    #include "wx/msw/dc.h"
 #endif
 
-#include <typeinfo>
+#include "wx/odcombo.h"
 
 // -----------------------------------------------------------------------
 
 // -----------------------------------------------------------------------
 
 
-bool operator == (const wxFont&, const wxFont&)
-{
-    return false;
-}
-
 // Implement dynamic class for type value.
 IMPLEMENT_DYNAMIC_CLASS(wxColourPropertyValue, wxObject)
 
@@ -115,9 +110,134 @@ bool operator == (const wxArrayInt& array1, const wxArrayInt& array2)
 #if wxUSE_SPINBTN
 
 
-// This macro also defines global wxPGEditor_SpinCtrl for storing
-// the singleton class instance.
-WX_PG_IMPLEMENT_EDITOR_CLASS(SpinCtrl,wxPGSpinCtrlEditor,wxPGEditor)
+#ifdef __WXMSW__
+  #define IS_MOTION_SPIN_SUPPORTED  1
+#else
+  #define IS_MOTION_SPIN_SUPPORTED  0
+#endif
+
+#if IS_MOTION_SPIN_SUPPORTED
+
+//
+// This class implements ability to rapidly change "spin" value
+// by moving mouse when one of the spin buttons is depressed.
+class wxPGSpinButton : public wxSpinButton
+{
+public:
+    wxPGSpinButton() : wxSpinButton()
+    {
+        m_bLeftDown = false;
+        m_hasCapture = false;
+        m_spins = 1;
+
+        Connect( wxEVT_LEFT_DOWN,
+                 wxMouseEventHandler(wxPGSpinButton::OnMouseEvent) );
+        Connect( wxEVT_LEFT_UP,
+                 wxMouseEventHandler(wxPGSpinButton::OnMouseEvent) );
+        Connect( wxEVT_MOTION,
+                 wxMouseEventHandler(wxPGSpinButton::OnMouseEvent) );
+        Connect( wxEVT_MOUSE_CAPTURE_LOST,
+          wxMouseCaptureLostEventHandler(wxPGSpinButton::OnMouseCaptureLost) );
+    }
+
+    int GetSpins() const
+    {
+        return m_spins;
+    }
+
+private:
+    wxPoint m_ptPosition;
+
+    // Having a separate spins variable allows us to handle validation etc. for
+    // multiple spin events at once (with quick mouse movements there could be
+    // hundreds of 'spins' being done at once). Technically things like this
+    // should be stored in event (wxSpinEvent in this case), but there probably
+    // isn't anything there that can be reliably reused.
+    int     m_spins;
+
+    bool    m_bLeftDown;
+
+    // SpinButton seems to be a special for mouse capture, so we may need track
+    // privately whether mouse is actually captured.
+    bool    m_hasCapture;
+
+    void Capture()
+    {
+        if ( !m_hasCapture )
+        {
+            CaptureMouse();
+            m_hasCapture = true;
+        }
+
+        SetCursor(wxCURSOR_SIZENS);
+    }
+    void Release()
+    {
+        m_bLeftDown = false;
+
+        if ( m_hasCapture )
+        {
+            ReleaseMouse();
+            m_hasCapture = false;
+        }
+
+        wxWindow *parent = GetParent();
+        if ( parent )
+            SetCursor(parent->GetCursor());
+        else
+            SetCursor(wxNullCursor);
+    }
+
+    void OnMouseEvent(wxMouseEvent& event)
+    {
+        if ( event.GetEventType() == wxEVT_LEFT_DOWN )
+        {
+            m_bLeftDown = true;
+            m_ptPosition = event.GetPosition();
+        }
+        else if ( event.GetEventType() == wxEVT_LEFT_UP )
+        {
+            Release();
+            m_bLeftDown = false;
+        }
+        else if ( event.GetEventType() == wxEVT_MOTION )
+        {
+            if ( m_bLeftDown )
+            {
+                int dy = m_ptPosition.y - event.GetPosition().y;
+                if ( dy )
+                {
+                    Capture();
+                    m_ptPosition = event.GetPosition();
+
+                    wxSpinEvent evtscroll( (dy >= 0) ? wxEVT_SCROLL_LINEUP :
+                                                       wxEVT_SCROLL_LINEDOWN,
+                                           GetId() );
+                    evtscroll.SetEventObject(this);
+
+                    wxASSERT( m_spins == 1 );
+
+                    m_spins = abs(dy);
+                    GetEventHandler()->ProcessEvent(evtscroll);
+                    m_spins = 1;
+                }
+            }
+        }
+
+        event.Skip();
+    }
+    void OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
+    {
+        Release();
+    }
+};
+
+#endif  // IS_MOTION_SPIN_SUPPORTED
+
+
+WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(SpinCtrl,
+                                      wxPGSpinCtrlEditor,
+                                      wxPGEditor)
 
 
 // Trivial destructor.
@@ -135,7 +255,19 @@ wxPGWindowList wxPGSpinCtrlEditor::CreateControls( wxPropertyGrid* propgrid, wxP
     wxSize tcSz(sz.x - butSz.x - margin, sz.y);
     wxPoint butPos(pos.x + tcSz.x + margin, pos.y);
 
-    wxSpinButton* wnd2 = new wxSpinButton();
+    wxSpinButton* wnd2;
+
+#if IS_MOTION_SPIN_SUPPORTED
+    if ( property->GetAttributeAsLong(wxT("MotionSpin"), 0) )
+    {
+        wnd2 = new wxPGSpinButton();
+    }
+    else
+#endif
+    {
+        wnd2 = new wxSpinButton();
+    }
+
 #ifdef __WXMSW__
     wnd2->Hide();
 #endif
@@ -144,21 +276,12 @@ wxPGWindowList wxPGSpinCtrlEditor::CreateControls( wxPropertyGrid* propgrid, wxP
     wnd2->SetRange( INT_MIN, INT_MAX );
     wnd2->SetValue( 0 );
 
-    propgrid->Connect( wxPG_SUBID2, wxEVT_SCROLL_LINEUP,
-                       (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
-                       &wxPropertyGrid::OnCustomEditorEvent, NULL, propgrid );
-    propgrid->Connect( wxPG_SUBID2, wxEVT_SCROLL_LINEDOWN,
-                       (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
-                       &wxPropertyGrid::OnCustomEditorEvent, NULL, propgrid );
-    propgrid->Connect( wxPG_SUBID1, wxEVT_KEY_DOWN,
-                       (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
-                       &wxPropertyGrid::OnCustomEditorEvent, NULL, propgrid );
-
+    wxWindow* wnd1 = wxPGTextCtrlEditor::CreateControls(propgrid, property, pos, tcSz).m_primary;
+#if wxUSE_VALIDATORS
     // Let's add validator to make sure only numbers can be entered
     wxTextValidator validator(wxFILTER_NUMERIC, &m_tempString);
-
-    wxTextCtrl* wnd1 = (wxTextCtrl*) wxPGTextCtrlEditor::CreateControls( propgrid, property, pos, tcSz ).m_primary;
     wnd1->SetValidator(validator);
+#endif
 
     return wxPGWindowList(wnd1, wnd2);
 }
@@ -169,6 +292,7 @@ bool wxPGSpinCtrlEditor::OnEvent( wxPropertyGrid* propgrid, wxPGProperty* proper
 {
     int evtType = event.GetEventType();
     int keycode = -1;
+    int spins = 1;
     bool bigStep = false;
 
     if ( evtType == wxEVT_KEY_DOWN )
@@ -194,6 +318,17 @@ bool wxPGSpinCtrlEditor::OnEvent( wxPropertyGrid* propgrid, wxPGProperty* proper
 
     if ( evtType == wxEVT_SCROLL_LINEUP || evtType == wxEVT_SCROLL_LINEDOWN )
     {
+    #if IS_MOTION_SPIN_SUPPORTED
+        if ( property->GetAttributeAsLong(wxT("MotionSpin"), 0) )
+        {
+            wxPGSpinButton* spinButton =
+                (wxPGSpinButton*) propgrid->GetEditorControlSecondary();
+
+            if ( spinButton )
+                spins = spinButton->GetSpins();
+        }
+    #endif
+
         wxString s;
         // Can't use wnd since it might be clipper window
         wxTextCtrl* tc = wxDynamicCast(propgrid->GetEditorControl(), wxTextCtrl);
@@ -219,6 +354,8 @@ bool wxPGSpinCtrlEditor::OnEvent( wxPropertyGrid* propgrid, wxPGProperty* proper
                 if ( bigStep )
                     step *= 10.0;
 
+                step *= (double) spins;
+
                 if ( evtType == wxEVT_SCROLL_LINEUP ) v_d += step;
                 else v_d -= step;
 
@@ -243,6 +380,8 @@ bool wxPGSpinCtrlEditor::OnEvent( wxPropertyGrid* propgrid, wxPGProperty* proper
                 if ( bigStep )
                     step *= 10;
 
+                step *= spins;
+
                 if ( evtType == wxEVT_SCROLL_LINEUP ) v_ll += step;
                 else v_ll -= step;
 
@@ -281,17 +420,20 @@ bool wxPGSpinCtrlEditor::OnEvent( wxPropertyGrid* propgrid, wxPGProperty* proper
 #if wxUSE_DATEPICKCTRL
 
 
-#include <wx/datectrl.h>
-#include <wx/dateevt.h>
+#include "wx/datectrl.h"
+#include "wx/dateevt.h"
 
 class wxPGDatePickerCtrlEditor : public wxPGEditor
 {
-    WX_PG_DECLARE_EDITOR_CLASS(wxPGDatePickerCtrlEditor)
+    DECLARE_DYNAMIC_CLASS(wxPGDatePickerCtrlEditor)
 public:
     virtual ~wxPGDatePickerCtrlEditor();
 
-    wxPG_DECLARE_CREATECONTROLS
-
+    wxString GetName() const;
+    virtual wxPGWindowList CreateControls(wxPropertyGrid* propgrid,
+                                          wxPGProperty* property,
+                                          const wxPoint& pos,
+                                          const wxSize& size) const;
     virtual void UpdateControl( wxPGProperty* property, wxWindow* wnd ) const;
     virtual bool OnEvent( wxPropertyGrid* propgrid, wxPGProperty* property,
         wxWindow* wnd, wxEvent& event ) const;
@@ -300,7 +442,9 @@ public:
 };
 
 
-WX_PG_IMPLEMENT_EDITOR_CLASS(DatePickerCtrl,wxPGDatePickerCtrlEditor,wxPGEditor)
+WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(DatePickerCtrl,
+                                      wxPGDatePickerCtrlEditor,
+                                      wxPGEditor)
 
 
 wxPGDatePickerCtrlEditor::~wxPGDatePickerCtrlEditor()
@@ -316,7 +460,7 @@ wxPGWindowList wxPGDatePickerCtrlEditor::CreateControls( wxPropertyGrid* propgri
                  NULL,
                  wxT("DatePickerCtrl editor can only be used with wxDateProperty or derivative.") );
 
-    wxDateProperty* prop = (wxDateProperty*) property;
+    wxDateProperty* prop = wxDynamicCast(property, wxDateProperty);
 
     // Use two stage creation to allow cleaner display on wxMSW
     wxDatePickerCtrl* ctrl = new wxDatePickerCtrl();
@@ -327,20 +471,20 @@ wxPGWindowList wxPGDatePickerCtrlEditor::CreateControls( wxPropertyGrid* propgri
 #else
     wxSize useSz = sz;
 #endif
+
+    wxDateTime dateValue(wxInvalidDateTime);
+
+    wxVariant value = prop->GetValue();
+    if ( value.GetType() == wxT("datetime") )
+        dateValue = value.GetDateTime();
+
     ctrl->Create(propgrid->GetPanel(),
                  wxPG_SUBID1,
-                 prop->GetDateValue(),
+                 dateValue,
                  pos,
                  useSz,
                  prop->GetDatePickerStyle() | wxNO_BORDER);
 
-    // Connect all required events to grid's OnCustomEditorEvent
-    // (all relevenat wxTextCtrl, wxComboBox and wxButton events are
-    // already connected)
-    propgrid->Connect( wxPG_SUBID1, wxEVT_DATE_CHANGED,
-                       (wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
-                       &wxPropertyGrid::OnCustomEditorEvent );
-
 #ifdef __WXMSW__
     ctrl->Show();
 #endif
@@ -349,14 +493,18 @@ wxPGWindowList wxPGDatePickerCtrlEditor::CreateControls( wxPropertyGrid* propgri
 }
 
 // Copies value from property to control
-void wxPGDatePickerCtrlEditor::UpdateControl( wxPGProperty* property, wxWindow* wnd ) const
+void wxPGDatePickerCtrlEditor::UpdateControl( wxPGProperty* property,
+                                              wxWindow* wnd ) const
 {
     wxDatePickerCtrl* ctrl = (wxDatePickerCtrl*) wnd;
     wxASSERT( ctrl && ctrl->IsKindOf(CLASSINFO(wxDatePickerCtrl)) );
 
-    // We assume that property's data type is 'int' (or something similar),
-    // thus allowing us to get raw, unchecked value via DoGetValue.
-    ctrl->SetValue( property->GetValue().GetDateTime() );
+    wxDateTime dateValue(wxInvalidDateTime);
+    wxVariant v(property->GetValue());
+    if ( v.GetType() == wxT("datetime") )
+        dateValue = v.GetDateTime();
+
+    ctrl->SetValue( dateValue );
 }
 
 // Control's events are redirected here
@@ -381,11 +529,20 @@ bool wxPGDatePickerCtrlEditor::GetValueFromControl( wxVariant& variant, wxPGProp
     return true;
 }
 
-void wxPGDatePickerCtrlEditor::SetValueToUnspecified( wxPGProperty* WXUNUSED(property), wxWindow* WXUNUSED(wnd) ) const
+void wxPGDatePickerCtrlEditor::SetValueToUnspecified( wxPGProperty* property,
+                                                      wxWindow* wnd ) const
 {
-    // TODO?
-    //wxDateProperty* prop = (wxDateProperty*) property;
-    //ctrl->SetValue(?);
+    wxDatePickerCtrl* ctrl = (wxDatePickerCtrl*) wnd;
+    wxASSERT( ctrl && ctrl->IsKindOf(CLASSINFO(wxDatePickerCtrl)) );
+
+    wxDateProperty* prop = wxDynamicCast(property, wxDateProperty);
+
+    if ( prop )
+    {
+        int datePickerStyle = prop->GetDatePickerStyle();
+        if ( datePickerStyle & wxDP_ALLOWNONE )
+            ctrl->SetValue(wxInvalidDateTime);
+    }
 }
 
 #endif // wxUSE_DATEPICKCTRL
@@ -395,20 +552,26 @@ void wxPGDatePickerCtrlEditor::SetValueToUnspecified( wxPGProperty* WXUNUSED(pro
 // wxFontProperty
 // -----------------------------------------------------------------------
 
-#include <wx/fontdlg.h>
-#include <wx/fontenum.h>
+#include "wx/fontdlg.h"
+#include "wx/fontenum.h"
+
+//
+// NB: Do not use wxS here since unlike wxT it doesn't translate to wxChar*
+//
 
 static const wxChar* gs_fp_es_family_labels[] = {
     wxT("Default"), wxT("Decorative"),
     wxT("Roman"), wxT("Script"),
     wxT("Swiss"), wxT("Modern"),
+    wxT("Teletype"), wxT("Unknown"),
     (const wxChar*) NULL
 };
 
 static long gs_fp_es_family_values[] = {
-    wxDEFAULT, wxDECORATIVE,
-    wxROMAN, wxSCRIPT,
-    wxSWISS, wxMODERN
+    wxFONTFAMILY_DEFAULT, wxFONTFAMILY_DECORATIVE,
+    wxFONTFAMILY_ROMAN, wxFONTFAMILY_SCRIPT,
+    wxFONTFAMILY_SWISS, wxFONTFAMILY_MODERN,
+    wxFONTFAMILY_TELETYPE, wxFONTFAMILY_UNKNOWN
 };
 
 static const wxChar* gs_fp_es_style_labels[] = {
@@ -453,14 +616,7 @@ wxFontProperty::wxFontProperty( const wxString& label, const wxString& name,
     // Initialize font family choices list
     if ( !wxPGGlobalVars->m_fontFamilyChoices )
     {
-        wxFontEnumerator enumerator;
-        enumerator.EnumerateFacenames();
-
-#if wxMINOR_VERSION > 6
-        wxArrayString faceNames = enumerator.GetFacenames();
-#else
-        wxArrayString& faceNames = *enumerator.GetFacenames();
-#endif
+        wxArrayString faceNames = wxFontEnumerator::GetFacenames();
 
         faceNames.Sort();
 
@@ -472,11 +628,8 @@ wxFontProperty::wxFontProperty( const wxString& label, const wxString& name,
     wxFont font;
     font << m_value;
 
-    AddChild( new wxIntProperty( _("Point Size"), wxS("Point Size"),(long)font.GetPointSize() ) );
-
-    AddChild( new wxEnumProperty(_("Family"), wxS("PointSize"),
-              gs_fp_es_family_labels,gs_fp_es_family_values,
-              font.GetFamily()) );
+    AddPrivateChild( new wxIntProperty( _("Point Size"),
+                     wxS("Point Size"),(long)font.GetPointSize() ) );
 
     wxString faceName = font.GetFaceName();
     // If font was not in there, add it now
@@ -489,16 +642,22 @@ wxFontProperty::wxFontProperty( const wxString& label, const wxString& name,
 
     p->SetValueFromString(faceName, wxPG_FULL_VALUE);
 
-    AddChild( p );
+    AddPrivateChild( p );
+
+    AddPrivateChild( new wxEnumProperty(_("Style"), wxS("Style"),
+                     gs_fp_es_style_labels,gs_fp_es_style_values,
+                     font.GetStyle()) );
 
-    AddChild( new wxEnumProperty(_("Style"), wxS("Style"),
-              gs_fp_es_style_labels,gs_fp_es_style_values,font.GetStyle()) );
+    AddPrivateChild( new wxEnumProperty(_("Weight"), wxS("Weight"),
+                     gs_fp_es_weight_labels,gs_fp_es_weight_values,
+                     font.GetWeight()) );
 
-    AddChild( new wxEnumProperty(_("Weight"), wxS("Weight"),
-              gs_fp_es_weight_labels,gs_fp_es_weight_values,font.GetWeight()) );
+    AddPrivateChild( new wxBoolProperty(_("Underlined"), wxS("Underlined"),
+                     font.GetUnderlined()) );
 
-    AddChild( new wxBoolProperty(_("Underlined"), wxS("Underlined"),
-              font.GetUnderlined()) );
+    AddPrivateChild( new wxEnumProperty(_("Family"), wxS("PointSize"),
+                     gs_fp_es_family_labels,gs_fp_es_family_values,
+                     font.GetFamily()) );
 }
 
 wxFontProperty::~wxFontProperty() { }
@@ -510,14 +669,14 @@ void wxFontProperty::OnSetValue()
 
     if ( !font.Ok() )
     {
-        font = wxFont(10,wxSWISS,wxNORMAL,wxNORMAL);
-        m_value << font;
+        m_value << *wxNORMAL_FONT;
     }
 }
 
-wxString wxFontProperty::GetValueAsString( int argFlags ) const
+wxString wxFontProperty::ValueToString( wxVariant& value,
+                                        int argFlags ) const
 {
-    return wxPGProperty::GetValueAsString(argFlags);
+    return wxPGProperty::ValueToString(value, argFlags);
 }
 
 bool wxFontProperty::OnEvent( wxPropertyGrid* propgrid, wxWindow* WXUNUSED(primary),
@@ -526,11 +685,11 @@ bool wxFontProperty::OnEvent( wxPropertyGrid* propgrid, wxWindow* WXUNUSED(prima
     if ( propgrid->IsMainButtonEvent(event) )
     {
         // Update value from last minute changes
-        PrepareValueForDialogEditing(propgrid);
+        wxVariant useValue = propgrid->GetUncommittedPropertyValue();
 
         wxFontData data;
         wxFont font;
-        font << m_value;
+        font << useValue;
         data.SetInitialFont( font );
         data.SetColour(*wxBLACK);
 
@@ -554,31 +713,25 @@ void wxFontProperty::RefreshChildren()
     wxFont font;
     font << m_value;
     Item(0)->SetValue( (long)font.GetPointSize() );
-    Item(1)->SetValue( (long)font.GetFamily() );
-    Item(2)->SetValueFromString( font.GetFaceName(), wxPG_FULL_VALUE );
-    Item(3)->SetValue( (long)font.GetStyle() );
-    Item(4)->SetValue( (long)font.GetWeight() );
-    Item(5)->SetValue( font.GetUnderlined() );
+    Item(1)->SetValueFromString( font.GetFaceName(), wxPG_FULL_VALUE );
+    Item(2)->SetValue( (long)font.GetStyle() );
+    Item(3)->SetValue( (long)font.GetWeight() );
+    Item(4)->SetValue( font.GetUnderlined() );
+    Item(5)->SetValue( (long)font.GetFamily() );
 }
 
-void wxFontProperty::ChildChanged( wxVariant& thisValue, int ind, wxVariant& childValue ) const
+wxVariant wxFontProperty::ChildChanged( wxVariant& thisValue,
+                                        int ind,
+                                        wxVariant& childValue ) const
 {
     wxFont font;
     font << thisValue;
 
     if ( ind == 0 )
     {
-        font.SetPointSize( wxPGVariantToInt(childValue) );
+        font.SetPointSize( childValue.GetLong() );
     }
     else if ( ind == 1 )
-    {
-        int fam = childValue.GetLong();
-        if ( fam < wxDEFAULT ||
-             fam > wxTELETYPE )
-             fam = wxDEFAULT;
-        font.SetFamily( fam );
-    }
-    else if ( ind == 2 )
     {
         wxString faceName;
         int faceIndex = childValue.GetLong();
@@ -588,7 +741,7 @@ void wxFontProperty::ChildChanged( wxVariant& thisValue, int ind, wxVariant& chi
 
         font.SetFaceName( faceName );
     }
-    else if ( ind == 3 )
+    else if ( ind == 2 )
     {
         int st = childValue.GetLong();
         if ( st != wxFONTSTYLE_NORMAL &&
@@ -597,7 +750,7 @@ void wxFontProperty::ChildChanged( wxVariant& thisValue, int ind, wxVariant& chi
              st = wxFONTWEIGHT_NORMAL;
         font.SetStyle( st );
     }
-    else if ( ind == 4 )
+    else if ( ind == 3 )
     {
         int wt = childValue.GetLong();
         if ( wt != wxFONTWEIGHT_NORMAL &&
@@ -606,12 +759,22 @@ void wxFontProperty::ChildChanged( wxVariant& thisValue, int ind, wxVariant& chi
              wt = wxFONTWEIGHT_NORMAL;
         font.SetWeight( wt );
     }
-    else if ( ind == 5 )
+    else if ( ind == 4 )
     {
         font.SetUnderlined( childValue.GetBool() );
     }
+    else if ( ind == 5 )
+    {
+        int fam = childValue.GetLong();
+        if ( fam < wxDEFAULT ||
+             fam > wxTELETYPE )
+             fam = wxDEFAULT;
+        font.SetFamily( fam );
+    }
 
-    thisValue << font;
+    wxVariant newVariant;
+    newVariant << font;
+    return newVariant;
 }
 
 /*
@@ -665,7 +828,7 @@ void wxFontProperty::OnCustomPaint(wxDC& dc,
 // wxEnumProperty based classes cannot use wxPG_PROP_CLASS_SPECIFIC_1
 #define wxPG_PROP_HIDE_CUSTOM_COLOUR        wxPG_PROP_CLASS_SPECIFIC_2
 
-#include <wx/colordlg.h>
+#include "wx/colordlg.h"
 
 //#define wx_cp_es_syscolours_len 25
 static const wxChar* gs_cp_es_syscolour_labels[] = {
@@ -876,7 +1039,10 @@ wxVariant wxSystemColourProperty::DoTranslateVal( wxColourPropertyValue& v ) con
 int wxSystemColourProperty::ColToInd( const wxColour& colour ) const
 {
     size_t i;
-    size_t i_max = m_choices.GetCount() - 1;
+    size_t i_max = m_choices.GetCount();
+
+    if ( !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
+        i_max -= 1;
 
     for ( i=0; i<i_max; i++ )
     {
@@ -894,13 +1060,6 @@ int wxSystemColourProperty::ColToInd( const wxColour& colour ) const
     return wxNOT_FOUND;
 }
 
-
-static inline wxColour wxColourFromPGLong( long col )
-{
-    return wxColour((col&0xFF),((col>>8)&0xFF),((col>>16)&0xFF));
-}
-
-
 void wxSystemColourProperty::OnSetValue()
 {
     // Convert from generic wxobject ptr to wxPGVariantDataColour
@@ -926,7 +1085,7 @@ void wxSystemColourProperty::OnSetValue()
         m_value = TranslateVal(val);
     }
 
-    int ind;
+    int ind = wxNOT_FOUND;
 
     if ( m_value.GetType() == wxS("wxColourPropertyValue") )
     {
@@ -941,12 +1100,10 @@ void wxSystemColourProperty::OnSetValue()
             return;
         }
 
-        if ( cpv.m_type < wxPG_COLOUR_WEB_BASE )
+        if ( cpv.m_type < wxPG_COLOUR_WEB_BASE ||
+             (m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
         {
-            if ( m_choices.HasValues() )
-                ind = GetIndexForValue(cpv.m_type);
-            else
-                ind = ColToInd(col);
+            ind = GetIndexForValue(cpv.m_type);
         }
         else
         {
@@ -968,7 +1125,8 @@ void wxSystemColourProperty::OnSetValue()
 
         ind = ColToInd(col);
 
-        if ( ind == wxNOT_FOUND )
+        if ( ind == wxNOT_FOUND &&
+             !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
             ind = GetCustomColourIndex();
     }
 
@@ -992,24 +1150,31 @@ wxString wxSystemColourProperty::ColourToString( const wxColour& col, int index
         return m_choices.GetLabel(index);
 }
 
-wxString wxSystemColourProperty::GetValueAsString( int argFlags ) const
+wxString wxSystemColourProperty::ValueToString( wxVariant& value,
+                                                int argFlags ) const
 {
-    wxColourPropertyValue val = GetVal();
+    wxColourPropertyValue val = GetVal(&value);
 
-    int ind = GetIndex();
+    int index;
 
-    // Always show custom colour for textctrl-editor
-    if ( val.m_type == wxPG_COLOUR_CUSTOM ||
-         ind == GetCustomColourIndex() ||
-         (argFlags & wxPG_PROPERTY_SPECIFIC) )
+    if ( argFlags & wxPG_VALUE_IS_CURRENT )
     {
-        return ColourToString(val.m_colour, wxNOT_FOUND);
+        // GetIndex() only works reliably if wxPG_VALUE_IS_CURRENT flag is set,
+        // but we should use it whenever possible.
+        index = GetIndex();
+
+        // If custom colour was selected, use invalid index, so that
+        // ColourToString() will return properly formatted colour text.
+        if ( index == GetCustomColourIndex() &&
+             !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
+            index = wxNOT_FOUND;
+    }
+    else
+    {
+        index = m_choices.Index(val.m_type);
     }
 
-    if ( ind == -1 )
-        return wxEmptyString;
-
-    return ColourToString(val.m_colour, ind);
+    return ColourToString(val.m_colour, index);
 }
 
 
@@ -1034,7 +1199,7 @@ bool wxSystemColourProperty::QueryColourFromUser( wxVariant& variant ) const
     wxASSERT( propgrid );
 
     // Must only occur when user triggers event
-    if ( !(propgrid->GetInternalFlags() & wxPG_FL_IN_ONCUSTOMEDITOREVENT) )
+    if ( !(propgrid->GetInternalFlags() & wxPG_FL_IN_HANDLECUSTOMEDITOREVENT) )
         return res;
 
     wxColourPropertyValue val = GetVal();
@@ -1071,14 +1236,9 @@ bool wxSystemColourProperty::QueryColourFromUser( wxVariant& variant ) const
 bool wxSystemColourProperty::IntToValue( wxVariant& variant, int number, int WXUNUSED(argFlags) ) const
 {
     int index = number;
-    int type = GetValueForIndex(index);
-    bool hasValue = m_choices[index].HasValue();
+    int type = m_choices.GetValue(index);
 
-    if ( ( hasValue && type == wxPG_COLOUR_CUSTOM ) ||
-         ( !hasValue && (index == (int)GetCustomColourIndex() &&
-                                      !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR))
-         )
-       )
+    if ( type == wxPG_COLOUR_CUSTOM )
     {
         QueryColourFromUser(variant);
     }
@@ -1091,12 +1251,37 @@ bool wxSystemColourProperty::IntToValue( wxVariant& variant, int number, int WXU
 }
 
 // Need to do some extra event handling.
-bool wxSystemColourProperty::OnEvent( wxPropertyGrid* propgrid, wxWindow* WXUNUSED(primary), wxEvent& event )
+bool wxSystemColourProperty::OnEvent( wxPropertyGrid* propgrid,
+                                      wxWindow* WXUNUSED(primary),
+                                      wxEvent& event )
 {
+    bool askColour = false;
+
     if ( propgrid->IsMainButtonEvent(event) )
     {
         // We need to handle button click in case editor has been
         // switched to one that has wxButton as well.
+        askColour = true;
+    }
+    else if ( event.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED )
+    {
+        // Must override index detection since at this point GetIndex()
+        // will return old value.
+        wxOwnerDrawnComboBox* cb =
+            static_cast<wxOwnerDrawnComboBox*>(propgrid->GetEditorControl());
+
+        if ( cb )
+        {
+            int index = cb->GetSelection();
+
+            if ( index == GetCustomColourIndex() &&
+                    !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
+                askColour = true;
+        }
+    }
+
+    if ( askColour && !propgrid->WasValueChangedInEvent() )
+    {
         wxVariant variant;
         if ( QueryColourFromUser(variant) )
             return true;
@@ -1161,8 +1346,10 @@ void wxSystemColourProperty::OnCustomPaint( wxDC& dc, const wxRect& rect,
 {
     wxColour col;
 
-    if ( paintdata.m_choiceItem >= 0 && paintdata.m_choiceItem < (int)m_choices.GetCount() &&
-         paintdata.m_choiceItem != GetCustomColourIndex() )
+    if ( paintdata.m_choiceItem >= 0 &&
+         paintdata.m_choiceItem < (int)m_choices.GetCount() &&
+         (paintdata.m_choiceItem != GetCustomColourIndex() ||
+          m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
     {
         int colInd = m_choices[paintdata.m_choiceItem].GetValue();
         col = GetColour( colInd );
@@ -1211,6 +1398,7 @@ bool wxSystemColourProperty::StringToValue( wxVariant& value, const wxString& te
         colourRGB.clear();
 
     if ( colourRGB.length() == 0 && m_choices.GetCount() &&
+         !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) &&
          colourName == m_choices.GetLabel(GetCustomColourIndex()) )
     {
         if ( !(argFlags & wxPG_EDITABLE_VALUE ))
@@ -1236,7 +1424,7 @@ bool wxSystemColourProperty::StringToValue( wxVariant& value, const wxString& te
             if ( res && GetIndex() >= 0 )
             {
                 val.m_type = GetIndex();
-                if ( val.m_type >= 0 && val.m_type < m_choices.GetCount() && m_choices[val.m_type].HasValue() )
+                if ( val.m_type < m_choices.GetCount() )
                     val.m_type = m_choices[val.m_type].GetValue();
 
                 // Get proper colour for type.
@@ -1280,9 +1468,7 @@ bool wxSystemColourProperty::DoSetAttribute( const wxString& name, wxVariant& va
 {
     if ( name == wxPG_COLOUR_ALLOW_CUSTOM )
     {
-        int ival = wxPGVariantToInt(value);
-
-        SetChoicesExclusive(); // Make sure we don't corrupt colour lists of other properties
+        int ival = value.GetLong();
 
         if ( ival && (m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
         {
@@ -1351,11 +1537,63 @@ static unsigned long gs_cp_es_normcolour_colours[] = {
     wxPG_COLOUR(0,0,0)
 };
 
-WX_PG_IMPLEMENT_CUSTOM_COLOUR_PROPERTY_USES_WXCOLOUR2(wxColourProperty,
-                                                     gs_cp_es_normcolour_labels,
-                                                     (const long*)NULL,
-                                                     gs_cp_es_normcolour_colours,
-                                                     TextCtrlAndButton)
+WX_PG_IMPLEMENT_PROPERTY_CLASS(wxColourProperty, wxSystemColourProperty,
+                               wxColour, const wxColour&, TextCtrlAndButton)
+
+static wxPGChoices gs_wxColourProperty_choicesCache;
+
+wxColourProperty::wxColourProperty( const wxString& label,
+                      const wxString& name,
+                      const wxColour& value )
+    : wxSystemColourProperty(label, name, gs_cp_es_normcolour_labels,
+                             NULL,
+                             &gs_wxColourProperty_choicesCache, value )
+{
+    Init( value );
+
+    m_flags |= wxPG_PROP_TRANSLATE_CUSTOM;
+}
+
+wxColourProperty::~wxColourProperty()
+{
+}
+
+void wxColourProperty::Init( wxColour colour )
+{
+    if ( !colour.Ok() )
+        colour = *wxWHITE;
+    wxVariant variant;
+    variant << colour;
+    m_value = variant;
+    int ind = ColToInd(colour);
+    if ( ind < 0 )
+        ind = m_choices.GetCount() - 1;
+    SetIndex( ind );
+}
+
+wxString wxColourProperty::ValueToString( wxVariant& value,
+                                          int argFlags ) const
+{
+    const wxPGEditor* editor = GetEditorClass();
+    if ( editor != wxPGEditor_Choice &&
+         editor != wxPGEditor_ChoiceAndButton &&
+         editor != wxPGEditor_ComboBox )
+        argFlags |= wxPG_PROPERTY_SPECIFIC;
+
+    return wxSystemColourProperty::ValueToString(value, argFlags);
+}
+
+wxColour wxColourProperty::GetColour( int index ) const
+{
+    return gs_cp_es_normcolour_colours[m_choices.GetValue(index)];
+}
+
+wxVariant wxColourProperty::DoTranslateVal( wxColourPropertyValue& v ) const
+{
+    wxVariant variant;
+    variant << v.m_colour;
+    return variant;
+}
 
 // -----------------------------------------------------------------------
 // wxCursorProperty
@@ -1472,13 +1710,14 @@ void wxCursorProperty::OnCustomPaint( wxDC& dc,
 
         if ( paintdata.m_choiceItem < NUM_CURSORS )
         {
-            int cursorindex = gs_cp_es_syscursors_values[paintdata.m_choiceItem];
+            wxStockCursor cursorIndex =
+                (wxStockCursor) gs_cp_es_syscursors_values[paintdata.m_choiceItem];
 
             {
-                if ( cursorindex == wxCURSOR_NONE )
-                    cursorindex = wxCURSOR_ARROW;
+                if ( cursorIndex == wxCURSOR_NONE )
+                    cursorIndex = wxCURSOR_ARROW;
 
-                wxCursor cursor( cursorindex );
+                wxCursor cursor( cursorIndex );
 
             #ifdef __WXMSW__
                 HDC hDc = (HDC)((const wxMSWDCImpl *)dc.GetImpl())->GetHDC();
@@ -1490,7 +1729,10 @@ void wxCursorProperty::OnCustomPaint( wxDC& dc,
                               0,
                               0,
                               NULL,
-                              DI_COMPAT | DI_DEFAULTSIZE | DI_NORMAL
+            #if !defined(__WXWINCE__)
+                              DI_COMPAT | DI_DEFAULTSIZE |
+            #endif
+                              DI_NORMAL
                             );
             #endif
             }
@@ -1528,7 +1770,7 @@ const wxString& wxPGGetDefaultImageWildcard()
 
         // Let's iterate over the image handler list.
         //for ( wxList::Node *node = handlers.GetFirst(); node; node = node->GetNext() )
-        for ( node = handlers.begin(); node != handlers.end(); node++ )
+        for ( node = handlers.begin(); node != handlers.end(); ++node )
         {
             wxImageHandler *handler = (wxImageHandler*)*node;
 
@@ -1551,9 +1793,7 @@ const wxString& wxPGGetDefaultImageWildcard()
     return wxPGGlobalVars->m_pDefaultImageWildcard;
 }
 
-WX_PG_IMPLEMENT_DERIVED_PROPERTY_CLASS(wxImageFileProperty,
-                                       wxFileProperty,
-                                       const wxString&)
+IMPLEMENT_DYNAMIC_CLASS(wxImageFileProperty, wxFileProperty)
 
 wxImageFileProperty::wxImageFileProperty( const wxString& label, const wxString& name,
     const wxString& value )
@@ -1561,8 +1801,8 @@ wxImageFileProperty::wxImageFileProperty( const wxString& label, const wxString&
 {
     SetAttribute( wxPG_FILE_WILDCARD, wxPGGetDefaultImageWildcard() );
 
-    m_pImage = (wxImage*) NULL;
-    m_pBitmap = (wxBitmap*) NULL;
+    m_pImage = NULL;
+    m_pBitmap = NULL;
 }
 
 wxImageFileProperty::~wxImageFileProperty()
@@ -1589,10 +1829,12 @@ void wxImageFileProperty::OnSetValue()
         m_pBitmap = NULL;
     }
 
+    wxFileName filename = GetFileName();
+
     // Create the image thumbnail
-    if ( m_filename.FileExists() )
+    if ( filename.FileExists() )
     {
-        m_pImage = new wxImage( m_filename.GetFullPath() );
+        m_pImage = new wxImage( filename.GetFullPath() );
     }
 }
 
@@ -1636,7 +1878,7 @@ void wxImageFileProperty::OnCustomPaint( wxDC& dc,
 
 #if wxUSE_CHOICEDLG
 
-#include <wx/choicdlg.h>
+#include "wx/choicdlg.h"
 
 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxMultiChoiceProperty,wxPGProperty,
                                wxArrayInt,const wxArrayInt&,TextCtrlAndButton)
@@ -1677,22 +1919,30 @@ wxMultiChoiceProperty::~wxMultiChoiceProperty()
 
 void wxMultiChoiceProperty::OnSetValue()
 {
-    GenerateValueAsString();
+    GenerateValueAsString(m_value, &m_display);
 }
 
-wxString wxMultiChoiceProperty::GetValueAsString( int ) const
+wxString wxMultiChoiceProperty::ValueToString( wxVariant& value,
+                                               int argFlags ) const
 {
-    return m_display;
+    // If possible, use cached string
+    if ( argFlags & wxPG_VALUE_IS_CURRENT )
+        return m_display;
+
+    wxString s;
+    GenerateValueAsString(value, &s);
+    return s;
 }
 
-void wxMultiChoiceProperty::GenerateValueAsString()
+void wxMultiChoiceProperty::GenerateValueAsString( wxVariant& value,
+                                                   wxString* target ) const
 {
     wxArrayString strings;
 
-    if ( m_value.GetType() == wxPG_VARIANT_TYPE_ARRSTRING )
-        strings = m_value.GetArrayString();
+    if ( value.GetType() == wxPG_VARIANT_TYPE_ARRSTRING )
+        strings = value.GetArrayString();
 
-    wxString& tempStr = m_display;
+    wxString& tempStr = *target;
     unsigned int i;
     unsigned int itemCount = strings.size();
 
@@ -1712,7 +1962,8 @@ void wxMultiChoiceProperty::GenerateValueAsString()
 
 wxArrayInt wxMultiChoiceProperty::GetValueAsIndices() const
 {
-    const wxArrayInt& valueArr = wxArrayIntRefFromVariant(GetValue());
+    wxVariant variant = GetValue();
+    const wxArrayInt& valueArr = wxArrayIntRefFromVariant(variant);
     unsigned int i;
 
     // Translate values to string indices.
@@ -1743,7 +1994,7 @@ bool wxMultiChoiceProperty::OnEvent( wxPropertyGrid* propgrid,
     if ( propgrid->IsMainButtonEvent(event) )
     {
         // Update the value
-        PrepareValueForDialogEditing(propgrid);
+        wxVariant useValue = propgrid->GetUncommittedPropertyValue();
 
         wxArrayString labels = m_choices.GetLabels();
         unsigned int choiceCount;
@@ -1763,7 +2014,7 @@ bool wxMultiChoiceProperty::OnEvent( wxPropertyGrid* propgrid,
 
         dlg.Move( propgrid->GetGoodEditorDialogPosition(this,dlg.GetSize()) );
 
-        wxArrayString strings = m_value.GetArrayString();
+        wxArrayString strings = useValue.GetArrayString();
         wxArrayString extraStrings;
 
         dlg.SetSelections(m_choices.GetIndicesForStrings(strings, &extraStrings));
@@ -1808,13 +2059,6 @@ bool wxMultiChoiceProperty::OnEvent( wxPropertyGrid* propgrid,
     return false;
 }
 
-int wxMultiChoiceProperty::GetChoiceInfo( wxPGChoiceInfo* choiceinfo )
-{
-    if ( choiceinfo )
-        choiceinfo->m_choices = &m_choices;
-    return -1;
-}
-
 bool wxMultiChoiceProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
 {
     wxArrayString arr;
@@ -1880,12 +2124,25 @@ wxDateProperty::~wxDateProperty()
 {
 }
 
+void wxDateProperty::OnSetValue()
+{
+    //
+    // Convert invalid dates to unspecified value
+    if ( m_value.GetType() == wxT("datetime") )
+    {
+        if ( !m_value.GetDateTime().IsValid() )
+            m_value.MakeNull();
+    }
+}
+
 bool wxDateProperty::StringToValue( wxVariant& variant, const wxString& text,
                                     int WXUNUSED(argFlags) ) const
 {
     wxDateTime dt;
 
-    const char* c = dt.ParseFormat(text, wxString(wxDefaultDateTimeFormat), wxDefaultDateTime, NULL);
+    // FIXME: do we really want to return true from here if only part of the
+    //        string was parsed?
+    const char* c = dt.ParseFormat(text);
 
     if ( c )
     {
@@ -1896,11 +2153,12 @@ bool wxDateProperty::StringToValue( wxVariant& variant, const wxString& text,
     return false;
 }
 
-wxString wxDateProperty::GetValueAsString( int argFlags ) const
+wxString wxDateProperty::ValueToString( wxVariant& value,
+                                        int argFlags ) const
 {
     const wxChar* format = (const wxChar*) NULL;
 
-    wxDateTime dateTime = m_value.GetDateTime();
+    wxDateTime dateTime = value.GetDateTime();
 
     if ( !dateTime.IsValid() )
         return wxT("Invalid");
@@ -2003,6 +2261,10 @@ void wxPropertyGridInterface::InitAllTypeHandlers()
 
 void wxPropertyGridInterface::RegisterAdditionalEditors()
 {
+    // Register editor classes, if necessary.
+    if ( wxPGGlobalVars->m_mapEditorClasses.empty() )
+        wxPropertyGrid::RegisterDefaultEditors();
+
 #if wxUSE_SPINBTN
     wxPGRegisterEditorClass(SpinCtrl);
 #endif