]> git.saurik.com Git - wxWidgets.git/blobdiff - src/propgrid/propgridpagestate.cpp
Ensure that wxFileName::GetTempDir() doesn't return trailing slashes.
[wxWidgets.git] / src / propgrid / propgridpagestate.cpp
index 6ee8c0f58f4a9dcf51c1971a0d8e4d0fa299a76e..00357190c07a789115d250957ad7f89957e34f10 100644 (file)
@@ -4,7 +4,7 @@
 // Author:      Jaakko Salli
 // Modified by:
 // Created:     2008-08-24
-// RCS-ID:      $Id:
+// RCS-ID:      $Id$
 // Copyright:   (c) Jaakko Salli
 // Licence:     wxWindows license
 /////////////////////////////////////////////////////////////////////////////
     #include "wx/pen.h"
     #include "wx/brush.h"
     #include "wx/intl.h"
+    #include "wx/stopwatch.h"
 #endif
 
 // This define is necessary to prevent macro clearing
 #define __wxPG_SOURCE_FILE__
 
-#include <wx/propgrid/propgridpagestate.h>
-#include <wx/propgrid/propgrid.h>
-#include <wx/propgrid/editors.h>
+#include "wx/propgrid/propgridpagestate.h"
+#include "wx/propgrid/propgrid.h"
+#include "wx/propgrid/editors.h"
 
 #define wxPG_DEFAULT_SPLITTERX      110
 
@@ -73,11 +74,10 @@ void wxPropertyGridIteratorBase::Init( wxPropertyGridPageState* state, int flags
 
 void wxPropertyGridIteratorBase::Init( wxPropertyGridPageState* state, int flags, int startPos, int dir  )
 {
-    wxPGProperty* property;
+    wxPGProperty* property = NULL;
 
     if ( startPos == wxTOP )
     {
-        property = NULL;
         if ( dir == 0 )
             dir = 1;
     }
@@ -89,8 +89,7 @@ void wxPropertyGridIteratorBase::Init( wxPropertyGridPageState* state, int flags
     }
     else
     {
-        wxASSERT_MSG( false, wxT("Only supported stating positions are wxTOP and wxBOTTOM") );
-        property = NULL;
+        wxFAIL_MSG("Only supported starting positions are wxTOP and wxBOTTOM");
     }
 
     Init( state, flags, property, dir );
@@ -108,7 +107,8 @@ void wxPropertyGridIteratorBase::Assign( const wxPropertyGridIteratorBase& it )
 void wxPropertyGridIteratorBase::Prev()
 {
     wxPGProperty* property = m_property;
-    wxASSERT( property );
+    if ( !property )
+        return;
 
     wxPGProperty* parent = property->GetParent();
     wxASSERT( parent );
@@ -153,7 +153,8 @@ void wxPropertyGridIteratorBase::Prev()
 void wxPropertyGridIteratorBase::Next( bool iterateChildren )
 {
     wxPGProperty* property = m_property;
-    wxASSERT( property );
+    if ( !property )
+        return;
 
     if ( property->GetChildCount() &&
          wxPG_ITERATOR_PARENTEXMASK_TEST(property, m_parentExMask) &&
@@ -202,12 +203,11 @@ void wxPropertyGridIteratorBase::Next( bool iterateChildren )
 
 wxPropertyGridPageState::wxPropertyGridPageState()
 {
-    m_pPropGrid = (wxPropertyGrid*) NULL;
+    m_pPropGrid = NULL;
     m_regularArray.SetParentState(this);
     m_properties = &m_regularArray;
-    m_abcArray = (wxPGRootProperty*) NULL;
-    m_currentCategory = (wxPropertyCategory*) NULL;
-    m_selected = (wxPGProperty*) NULL;
+    m_abcArray = NULL;
+    m_currentCategory = NULL;
     m_width = 0;
     m_virtualHeight = 0;
     m_lastCaptionBottomnest = 1;
@@ -217,6 +217,15 @@ wxPropertyGridPageState::wxPropertyGridPageState()
     m_colWidths.push_back( wxPG_DEFAULT_SPLITTERX );
     m_colWidths.push_back( wxPG_DEFAULT_SPLITTERX );
     m_fSplitterX = wxPG_DEFAULT_SPLITTERX;
+
+    m_columnProportions.push_back(1);
+    m_columnProportions.push_back(1);
+
+    m_isSplitterPreSet = false;
+    m_dontCenterSplitter = false;
+
+    // By default, we only have the 'value' column editable
+    m_editableColumns.push_back(1);
 }
 
 // -----------------------------------------------------------------------
@@ -232,7 +241,7 @@ void wxPropertyGridPageState::InitNonCatMode()
 {
     if ( !m_abcArray )
     {
-        m_abcArray = new wxPGRootProperty();
+        m_abcArray = new wxPGRootProperty(wxS("<Root_NonCat>"));
         m_abcArray->SetParentState(this);
         m_abcArray->SetFlag(wxPG_PROP_CHILDREN_ARE_COPIES);
     }
@@ -246,17 +255,17 @@ void wxPropertyGridPageState::InitNonCatMode()
 
     if ( m_properties->GetChildCount() )
     {
-        // Copy items.
-        wxPropertyGridIterator it( this, wxPG_ITERATE_DEFAULT|wxPG_ITERATE_CATEGORIES );
+        //
+        // Prepare m_abcArray
+        wxPropertyGridIterator it( this, wxPG_ITERATE_PROPERTIES );
 
         for ( ; !it.AtEnd(); it.Next() )
         {
             wxPGProperty* p = it.GetProperty();
             wxPGProperty* parent = p->GetParent();
-            if ( p->HasFlag(wxPG_PROP_MISC_PARENT) &&
-                ( parent == m_properties || (parent->IsCategory() || parent->IsRoot()) ) )
+            if ( parent->IsCategory() || parent->IsRoot() )
             {
-                m_abcArray->AddChild2( p );
+                m_abcArray->DoAddChild(p);
                 p->m_parent = &m_regularArray;
             }
         }
@@ -269,20 +278,27 @@ void wxPropertyGridPageState::InitNonCatMode()
 
 void wxPropertyGridPageState::DoClear()
 {
+    if ( m_pPropGrid && m_pPropGrid->GetState() == this  )
+    {
+        m_pPropGrid->ClearSelection(false);
+    }
+    else
+    {
+        m_selection.clear();
+    }
+
     m_regularArray.Empty();
     if ( m_abcArray )
         m_abcArray->Empty();
 
     m_dictName.clear();
 
-    m_currentCategory = (wxPropertyCategory*) NULL;
+    m_currentCategory = NULL;
     m_lastCaptionBottomnest = 1;
     m_itemsAdded = 0;
 
     m_virtualHeight = 0;
     m_vhCalcPending = 0;
-
-    m_selected = (wxPGProperty*) NULL;
 }
 
 // -----------------------------------------------------------------------
@@ -309,7 +325,11 @@ void wxPropertyGridPageState::CalculateFontAndBitmapStuff( int WXUNUSED(vspacing
 
 void wxPropertyGridPageState::SetVirtualWidth( int width )
 {
-    wxASSERT( width >= 0 );
+    // Sometimes width less than 0 is offered. Let's make things easy for
+    // everybody and deal with it here.
+    if ( width < 0 )
+        width = 0;
+
     wxPropertyGrid* pg = GetGrid();
     int gw = pg->GetClientSize().x;
     if ( width < gw )
@@ -341,22 +361,21 @@ void wxPropertyGridPageState::OnClientWidthChange( int newWidth, int widthChange
             widthChange = 0;
         CheckColumnWidths(widthChange);
 
-        if ( !(GetGrid()->GetInternalFlags() & wxPG_FL_SPLITTER_PRE_SET) &&
-             (GetGrid()->GetInternalFlags() & wxPG_FL_DONT_CENTER_SPLITTER) )
+        if ( !m_isSplitterPreSet && m_dontCenterSplitter )
         {
             long timeSinceCreation = (::wxGetLocalTimeMillis() - GetGrid()->m_timeCreated).ToLong();
 
             // If too long, don't set splitter
-            if ( timeSinceCreation < 3000 )
+            if ( timeSinceCreation < 250 )
             {
-                if ( m_properties->GetChildCount() || timeSinceCreation > 750 )
+                if ( m_properties->GetChildCount() )
                 {
                     SetSplitterLeft( false );
                 }
                 else
                 {
                     DoSetSplitterPosition( newWidth / 2 );
-                    GetGrid()->ClearInternalFlag(wxPG_FL_SPLITTER_PRE_SET);
+                    m_isSplitterPreSet = false;
                 }
             }
         }
@@ -370,7 +389,7 @@ void wxPropertyGridPageState::OnClientWidthChange( int newWidth, int widthChange
 wxPGProperty* wxPropertyGridPageState::GetLastItem( int flags )
 {
     if ( !m_properties->GetChildCount() )
-        return (wxPGProperty*) NULL;
+        return NULL;
 
     wxPG_ITERATOR_CREATE_MASKS(flags, int itemExMask, int parentExMask)
 
@@ -404,7 +423,7 @@ wxPropertyCategory* wxPropertyGridPageState::GetPropertyCategory( const wxPGProp
             return (wxPropertyCategory*)parent;
     } while ( grandparent );
 
-    return (wxPropertyCategory*) NULL;
+    return NULL;
 }
 
 // -----------------------------------------------------------------------
@@ -444,7 +463,27 @@ wxPGProperty* wxPropertyGridPageState::BaseGetPropertyByName( const wxString& na
     it = m_dictName.find(name);
     if ( it != m_dictName.end() )
         return (wxPGProperty*) it->second;
-    return (wxPGProperty*) NULL;
+    return NULL;
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGridPageState::DoSetPropertyName( wxPGProperty* p,
+                                                 const wxString& newName )
+{
+    wxCHECK_RET( p, wxT("invalid property id") );
+
+    wxPGProperty* parent = p->GetParent();
+
+    if ( parent->IsCategory() || parent->IsRoot() )
+    {
+        if ( p->GetBaseName().length() )
+            m_dictName.erase( p->GetBaseName() );
+        if ( newName.length() )
+            m_dictName[newName] = (void*) p;
+    }
+
+    p->DoSetName(newName);
 }
 
 // -----------------------------------------------------------------------
@@ -456,7 +495,7 @@ wxPGProperty* wxPropertyGridPageState::BaseGetPropertyByName( const wxString& na
 //   NB: Nowadays only needed for alphabetic/categoric mode switching.
 // -----------------------------------------------------------------------
 
-#define II_INVALID_I    0x00FFFFFF
+//#define II_INVALID_I    0x00FFFFFF
 
 #define ITEM_ITERATION_VARIABLES \
     wxPGProperty* parent; \
@@ -467,14 +506,16 @@ wxPGProperty* wxPropertyGridPageState::BaseGetPropertyByName( const wxString& na
     parent = m_properties; \
     i = 0;
 
+#if 0
 #define ITEM_ITERATION_INIT(startparent, startindex, state) \
     parent = startparent; \
     i = (unsigned int)startindex; \
-    if ( parent == (wxPGProperty*) NULL ) \
+    if ( parent == NULL ) \
     { \
         parent = state->m_properties; \
         i = 0; \
     }
+#endif
 
 #define ITEM_ITERATION_LOOP_BEGIN \
     do \
@@ -578,51 +619,113 @@ bool wxPropertyGridPageState::EnableCategories( bool enable )
 
 // -----------------------------------------------------------------------
 
-static int wxPG_SortFunc(void **p1, void **p2)
+static int wxPG_SortFunc_ByFunction(wxPGProperty **pp1, wxPGProperty **pp2)
+{
+    wxPGProperty *p1 = *pp1;
+    wxPGProperty *p2 = *pp2;
+    wxPropertyGrid* pg = p1->GetGrid();
+    wxPGSortCallback sortFunction = pg->GetSortFunction();
+    return sortFunction(pg, p1, p2);
+}
+
+static int wxPG_SortFunc_ByLabel(wxPGProperty **pp1, wxPGProperty **pp2)
 {
-    wxPGProperty *pp1 = *((wxPGProperty**)p1);
-    wxPGProperty *pp2 = *((wxPGProperty**)p2);
-    return pp1->GetLabel().compare( pp2->GetLabel() );
+    wxPGProperty *p1 = *pp1;
+    wxPGProperty *p2 = *pp2;
+    return p1->GetLabel().CmpNoCase( p2->GetLabel() );
 }
 
-void wxPropertyGridPageState::SortChildren( wxPGProperty* p )
+#if 0
+//
+// For wxVector w/ wxUSE_STL=1, you would use code like this instead:
+//
+
+#include <algorithm>
+
+static bool wxPG_SortFunc_ByFunction(wxPGProperty *p1, wxPGProperty *p2)
+{
+    wxPropertyGrid* pg = p1->GetGrid();
+    wxPGSortCallback sortFunction = pg->GetSortFunction();
+    return sortFunction(pg, p1, p2) < 0;
+}
+
+static bool wxPG_SortFunc_ByLabel(wxPGProperty *p1, wxPGProperty *p2)
+{
+    return p1->GetLabel().CmpNoCase( p2->GetLabel() ) < 0;
+}
+#endif
+
+void wxPropertyGridPageState::DoSortChildren( wxPGProperty* p,
+                                              int flags )
 {
     if ( !p )
-        p = (wxPGProperty*)m_properties;
+        p = m_properties;
 
+    // Can only sort items with children
     if ( !p->GetChildCount() )
         return;
 
-    wxPGProperty* pwc = (wxPGProperty*)p;
+    // Never sort children of aggregate properties
+    if ( p->HasFlag(wxPG_PROP_AGGREGATE) )
+        return;
 
-    // Can only sort items with children
-    if ( pwc->GetChildCount() < 1 )
+    if ( (flags & wxPG_SORT_TOP_LEVEL_ONLY)
+         && !p->IsCategory() && !p->IsRoot() )
         return;
 
-    pwc->m_children.Sort( wxPG_SortFunc );
+    if ( GetGrid()->GetSortFunction() )
+        p->m_children.Sort( wxPG_SortFunc_ByFunction );
+    else
+        p->m_children.Sort( wxPG_SortFunc_ByLabel );
+
+#if 0
+    //
+    // For wxVector w/ wxUSE_STL=1, you would use code like this instead:
+    //
+    if ( GetGrid()->GetSortFunction() )
+        std::sort(p->m_children.begin(), p->m_children.end(),
+                  wxPG_SortFunc_ByFunction);
+    else
+        std::sort(p->m_children.begin(), p->m_children.end(),
+                  wxPG_SortFunc_ByLabel);
+#endif
 
-    // Fix indexes
-    pwc->FixIndexesOfChildren();
+    // Fix indices
+    p->FixIndicesOfChildren();
 
+    if ( flags & wxPG_RECURSE )
+    {
+        // Apply sort recursively
+        for ( unsigned int i=0; i<p->GetChildCount(); i++ )
+            DoSortChildren(p->Item(i), flags);
+    }
 }
 
 // -----------------------------------------------------------------------
 
-void wxPropertyGridPageState::Sort()
+void wxPropertyGridPageState::DoSort( int flags )
 {
-    SortChildren( m_properties );
+    DoSortChildren( m_properties, flags | wxPG_RECURSE );
 
-    // Sort categories as well
-    if ( !IsInNonCatMode() )
-    {
-        size_t i;
-        for ( i=0;i<m_properties->GetChildCount();i++)
-        {
-            wxPGProperty* p = m_properties->Item(i);
-            if ( p->IsCategory() )
-                SortChildren( p );
-        }
-    }
+    // We used to sort categories as well here also if in non-categorized
+    // mode, but doing would naturally cause child indices to become
+    // corrupted.
+}
+
+// -----------------------------------------------------------------------
+
+bool wxPropertyGridPageState::PrepareAfterItemsAdded()
+{
+    if ( !m_itemsAdded ) return false;
+
+    wxPropertyGrid* pg = GetGrid();
+
+    m_itemsAdded = 0;
+
+    if ( pg->HasFlag(wxPG_AUTO_SORT) )
+        DoSort(wxPG_SORT_TOP_LEVEL_ONLY);
+
+    return true;
 }
 
 // -----------------------------------------------------------------------
@@ -633,7 +736,7 @@ wxPGProperty* wxPropertyGridPageState::DoGetItemAtY( int y ) const
 {
     // Outside?
     if ( y < 0 )
-        return (wxPGProperty*) NULL;
+        return NULL;
 
     unsigned int a = 0;
     return m_properties->GetItemAtY(y, GetGrid()->m_lineHeight, &a);
@@ -641,11 +744,13 @@ wxPGProperty* wxPropertyGridPageState::DoGetItemAtY( int y ) const
 
 // -----------------------------------------------------------------------
 
-wxPropertyGridHitTestResult wxPropertyGridPageState::HitTest( const wxPoint&pt ) const
+wxPropertyGridHitTestResult
+wxPropertyGridPageState::HitTest( const wxPoint&pt ) const
 {
     wxPropertyGridHitTestResult result;
-    result.column = HitTestH( pt.x, &result.splitter, &result.splitterHitOffset );
-    result.property = DoGetItemAtY( pt.y );
+    result.m_column = HitTestH( pt.x, &result.m_splitter,
+                                &result.m_splitterHitOffset );
+    result.m_property = DoGetItemAtY( pt.y );
     return result;
 }
 
@@ -667,12 +772,17 @@ int wxPropertyGridPageState::GetColumnFitWidth(wxClientDC& dc,
         wxPGProperty* p = pwc->Item(i);
         if ( !p->IsCategory() )
         {
-            dc.GetTextExtent( p->GetColumnText(col), &w, &h );
+            const wxPGCell* cell = NULL;
+            wxString text;
+            p->GetDisplayInfo(col, -1, 0, &text, &cell);
+            dc.GetTextExtent(text, &w, &h);
             if ( col == 0 )
                 w += ( ((int)p->m_depth-1) * pg->m_subgroup_extramargin );
 
-            //
-            // TODO: Add bitmap support.
+            // account for the bitmap
+            if ( col == 1 )
+                w += p->GetImageOffset(pg->GetImageRect(p, -1).GetWidth());
+
 
             w += (wxPG_XBEFORETEXT*2);
 
@@ -707,7 +817,9 @@ int wxPropertyGridPageState::GetColumnMinWidth( int WXUNUSED(column) ) const
     return wxPG_DRAG_MARGIN;
 }
 
-void wxPropertyGridPageState::PropagateColSizeDec( int column, int decrease, int dir )
+void wxPropertyGridPageState::PropagateColSizeDec( int column,
+                                                   int decrease,
+                                                   int dir )
 {
     int origWidth = m_colWidths[column];
     m_colWidths[column] -= decrease;
@@ -731,7 +843,9 @@ void wxPropertyGridPageState::PropagateColSizeDec( int column, int decrease, int
         PropagateColSizeDec( column, more, dir );
 }
 
-void wxPropertyGridPageState::DoSetSplitterPosition( int newXPos, int splitterColumn, bool WXUNUSED(allPages), bool fromAutoCenter )
+void wxPropertyGridPageState::DoSetSplitterPosition( int newXPos,
+                                                     int splitterColumn,
+                                                     int flags )
 {
     wxPropertyGrid* pg = GetGrid();
 
@@ -766,11 +880,11 @@ void wxPropertyGridPageState::DoSetSplitterPosition( int newXPos, int splitterCo
     if ( splitterColumn == 0 )
         m_fSplitterX = (double) newXPos;
 
-    if ( !fromAutoCenter )
+    if ( !(flags & wxPG_SPLITTER_FROM_AUTO_CENTER) &&
+         !(flags & wxPG_SPLITTER_FROM_EVENT) )
     {
         // Don't allow initial splitter auto-positioning after this.
-        if ( pg->GetState() == this )
-            pg->SetInternalFlag(wxPG_FL_SPLITTER_PRE_SET);
+        m_isSplitterPreSet = true;
 
         CheckColumnWidths();
     }
@@ -781,7 +895,7 @@ void wxPropertyGridPageState::SetSplitterLeft( bool subProps )
 {
     wxPropertyGrid* pg = GetGrid();
     wxClientDC dc(pg);
-    dc.SetFont(pg->m_font);
+    dc.SetFont(pg->GetFont());
 
     int maxW = GetColumnFitWidth(dc, m_properties, 0, subProps);
 
@@ -791,14 +905,14 @@ void wxPropertyGridPageState::SetSplitterLeft( bool subProps )
         DoSetSplitterPosition( maxW );
     }
 
-    pg->SetInternalFlag(wxPG_FL_DONT_CENTER_SPLITTER);
+    m_dontCenterSplitter = true;
 }
 
 wxSize wxPropertyGridPageState::DoFitColumns( bool WXUNUSED(allowGridResize) )
 {
     wxPropertyGrid* pg = GetGrid();
     wxClientDC dc(pg);
-    dc.SetFont(pg->m_font);
+    dc.SetFont(pg->GetFont());
 
     int marginWidth = pg->m_marginWidth;
     int accWid = marginWidth;
@@ -822,7 +936,7 @@ wxSize wxPropertyGridPageState::DoFitColumns( bool WXUNUSED(allowGridResize) )
     int remaining = m_width - accWid;
     m_colWidths[GetColumnCount()-1] += remaining;
 
-    pg->SetInternalFlag(wxPG_FL_DONT_CENTER_SPLITTER);
+    m_dontCenterSplitter = true;
 
     int firstSplitterX = marginWidth + m_colWidths[0];
     m_fSplitterX = (double) firstSplitterX;
@@ -847,10 +961,6 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
 
     wxPropertyGrid* pg = GetGrid();
 
-#ifdef __WXDEBUG__
-    const bool debug = false;
-#endif
-
     unsigned int i;
     unsigned int lastColumn = m_colWidths.size() - 1;
     int width = m_width;
@@ -858,16 +968,11 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
 
     //
     // Column to reduce, if needed. Take last one that exceeds minimum width.
-    // Except if auto splitter centering is used, in which case use widest.
     int reduceCol = -1;
-    int highestColWidth = 0;
-
-    bool minimizedCols = false;
 
-#ifdef __WXDEBUG__
-    if ( debug )
-        wxLogDebug(wxT("ColumnWidthCheck (virtualWidth: %i, clientWidth: %i)"), width, clientWidth);
-#endif
+    wxLogTrace("propgrid",
+               wxS("ColumnWidthCheck (virtualWidth: %i, clientWidth: %i)"),
+               width, clientWidth);
 
     //
     // Check min sizes
@@ -877,22 +982,12 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
         if ( m_colWidths[i] <= min )
         {
             m_colWidths[i] = min;
-            minimizedCols = true;
         }
         else
         {
-            if ( pg->HasFlag(wxPG_SPLITTER_AUTO_CENTER) )
-            {
-                if ( m_colWidths[i] >= highestColWidth )
-                {
-                    highestColWidth = m_colWidths[i];
-                    reduceCol = i;
-                }
-            }
-            else
-            {
-                reduceCol = i;
-            }
+            // Always reduce the last column that is larger than minimum size
+            // (looks nicer, even with auto-centering enabled).
+            reduceCol = i;
         }
     }
 
@@ -900,10 +995,9 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
     for ( i=0; i<m_colWidths.size(); i++ )
         colsWidth += m_colWidths[i];
 
-#ifdef __WXDEBUG__
-    if ( debug )
-        wxLogDebug(wxT("  HasVirtualWidth: %i  colsWidth: %i"),(int)pg->HasVirtualWidth(),colsWidth);
-#endif
+    wxLogTrace("propgrid",
+               wxS("  HasVirtualWidth: %i  colsWidth: %i"),
+               (int)pg->HasVirtualWidth(), colsWidth);
 
     // Then mode-based requirement
     if ( !pg->HasVirtualWidth() )
@@ -914,10 +1008,9 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
         if ( colsWidth < width )
         {
             // Increase column
-        #ifdef __WXDEBUG__
-        if ( debug )
-            wxLogDebug(wxT("  Adjust last column to %i"), m_colWidths[lastColumn] + widthHigher);
-        #endif
+            wxLogTrace("propgrid",
+                       wxS("  Adjust last column to %i"),
+                       m_colWidths[lastColumn] + widthHigher);
             m_colWidths[lastColumn] = m_colWidths[lastColumn] + widthHigher;
         }
         else if ( colsWidth > width )
@@ -925,10 +1018,10 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
             // Reduce column
             if ( reduceCol != -1 )
             {
-            #ifdef __WXDEBUG__
-                if ( debug )
-                    wxLogDebug(wxT("  Reduce column %i (by %i)"), reduceCol, -widthHigher);
-            #endif
+                wxLogTrace("propgrid",
+                           wxT("  Reduce column %i (by %i)"),
+                           reduceCol, -widthHigher);
+
                 // Reduce widest column, and recheck
                 m_colWidths[reduceCol] = m_colWidths[reduceCol] + widthHigher;
                 CheckColumnWidths();
@@ -950,54 +1043,91 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
             pg->RecalculateVirtualSize();
     }
 
-#ifdef __WXDEBUG__
-    if ( debug )
-        for ( i=0; i<m_colWidths.size(); i++ )
-            wxLogDebug(wxT("col%i: %i"),i,m_colWidths[i]);
-#endif
+    for ( i=0; i<m_colWidths.size(); i++ )
+    {
+        wxLogTrace("propgrid", wxS("col%i: %i"), i, m_colWidths[i]);
+    }
 
     // Auto center splitter
-    if ( !(pg->GetInternalFlags() & wxPG_FL_DONT_CENTER_SPLITTER) &&
-         m_colWidths.size() == 2 )
+    if ( !m_dontCenterSplitter )
     {
-        float centerX = (float)(pg->m_width/2);
-        float splitterX;
-
-        if ( m_fSplitterX < 0.0 )
-        {
-            splitterX = centerX;
-        }
-        else if ( widthChange )
+        if ( m_colWidths.size() == 2 &&
+             m_columnProportions[0] == m_columnProportions[1] )
         {
-            //float centerX = float(pg->GetSize().x) * 0.5;
+            //
+            // When we have two columns of equal proportion, then use this
+            // code. It will look nicer when the scrollbar visibility is
+            // toggled on and off.
+            //
+            // TODO: Adapt this to generic recenter code.
+            //
+            float centerX = (float)(pg->m_width/2);
+            float splitterX;
 
-            // Recenter?
-            splitterX = m_fSplitterX + (float(widthChange) * 0.5);
-            float deviation = fabs(centerX - splitterX);
+            if ( m_fSplitterX < 0.0 )
+            {
+                splitterX = centerX;
+            }
+            else if ( widthChange )
+            {
+                //float centerX = float(pg->GetSize().x) * 0.5;
 
-            // If deviating from center, adjust towards it
-            if ( deviation > 20.0 )
+                // Recenter?
+                splitterX = m_fSplitterX + (float(widthChange) * 0.5);
+                float deviation = fabs(centerX - splitterX);
+
+                // If deviating from center, adjust towards it
+                if ( deviation > 20.0 )
+                {
+                    if ( splitterX > centerX)
+                        splitterX -= 2;
+                    else
+                        splitterX += 2;
+                }
+            }
+            else
             {
-                if ( splitterX > centerX)
-                    splitterX -= 2;
-                else
-                    splitterX += 2;
+                // No width change, just keep sure we keep splitter position intact
+                splitterX = m_fSplitterX;
+                float deviation = fabs(centerX - splitterX);
+                if ( deviation > 50.0 )
+                {
+                    splitterX = centerX;
+                }
             }
+
+            DoSetSplitterPosition((int)splitterX, 0,
+                                  wxPG_SPLITTER_FROM_AUTO_CENTER);
+
+            m_fSplitterX = splitterX; // needed to retain accuracy
         }
         else
         {
-            // No width change, just keep sure we keep splitter position intact
-            splitterX = m_fSplitterX;
-            float deviation = fabs(centerX - splitterX);
-            if ( deviation > 50.0 )
-            {
-                splitterX = centerX;
-            }
+            //
+            // Generic re-center code
+            //
+            ResetColumnSizes(wxPG_SPLITTER_FROM_AUTO_CENTER);
         }
+    }
+}
 
-        DoSetSplitterPosition((int)splitterX, 0, false, true);
+void wxPropertyGridPageState::ResetColumnSizes( int setSplitterFlags )
+{
+    unsigned int i;
+    // Calculate sum of proportions
+    int psum = 0;
+    for ( i=0; i<m_colWidths.size(); i++ )
+        psum += m_columnProportions[i];
+    int puwid = (m_pPropGrid->m_width*256) / psum;
+    int cpos = 0;
 
-        m_fSplitterX = splitterX; // needed to retain accuracy
+    // Convert proportion to splitter positions
+    for ( i=0; i<(m_colWidths.size() - 1); i++ )
+    {
+        int cwid = (puwid*m_columnProportions[i]) / 256;
+        cpos += cwid;
+        DoSetSplitterPosition(cpos, i,
+                              setSplitterFlags);
     }
 }
 
@@ -1005,8 +1135,10 @@ void wxPropertyGridPageState::SetColumnCount( int colCount )
 {
     wxASSERT( colCount >= 2 );
     m_colWidths.SetCount( colCount, wxPG_DRAG_MARGIN );
+    m_columnProportions.SetCount( colCount, 1 );
     if ( m_colWidths.size() > (unsigned int)colCount )
-        m_colWidths.RemoveAt( m_colWidths.size(), m_colWidths.size() - colCount );
+        m_colWidths.RemoveAt( m_colWidths.size()-1,
+                              m_colWidths.size() - colCount );
 
     if ( m_pPropGrid->GetState() == this )
         m_pPropGrid->RecalculateVirtualSize();
@@ -1014,6 +1146,21 @@ void wxPropertyGridPageState::SetColumnCount( int colCount )
         CheckColumnWidths();
 }
 
+void wxPropertyGridPageState::DoSetColumnProportion( unsigned int column,
+                                                 int proportion )
+{
+    wxASSERT_MSG( proportion >= 1,
+                  "Column proportion must 1 or higher" );
+
+    if ( proportion < 1 )
+        proportion = 1;
+
+    while ( m_columnProportions.size() <= column )
+        m_columnProportions.push_back(1);
+
+    m_columnProportions[column] = proportion;
+}
+
 // Returns column index, -1 for margin
 int wxPropertyGridPageState::HitTestH( int x, int* pSplitterHit, int* pSplitterHitOffset ) const
 {
@@ -1062,6 +1209,29 @@ int wxPropertyGridPageState::HitTestH( int x, int* pSplitterHit, int* pSplitterH
     return col;
 }
 
+bool wxPropertyGridPageState::ArePropertiesAdjacent( wxPGProperty* prop1,
+                                                     wxPGProperty* prop2,
+                                                     int iterFlags ) const
+{
+    const wxPGProperty* ap1 =
+        wxPropertyGridConstIterator::OneStep(this,
+                                             iterFlags,
+                                             prop1,
+                                             1);
+    if ( ap1 && ap1 == prop2 )
+        return true;
+
+    const wxPGProperty* ap2 =
+        wxPropertyGridConstIterator::OneStep(this,
+                                             iterFlags,
+                                             prop1,
+                                             -1);
+    if ( ap2 && ap2 == prop2 )
+        return true;
+
+    return false;
+}
+
 // -----------------------------------------------------------------------
 // wxPropertyGridPageState property value setting and getting
 // -----------------------------------------------------------------------
@@ -1070,7 +1240,7 @@ bool wxPropertyGridPageState::DoSetPropertyValueString( wxPGProperty* p, const w
 {
     if ( p )
     {
-        int flags = wxPG_REPORT_ERROR|wxPG_FULL_VALUE;
+        int flags = wxPG_REPORT_ERROR|wxPG_FULL_VALUE|wxPG_PROGRAMMATIC_VALUE;
 
         wxVariant variant = p->GetValueRef();
         bool res;
@@ -1083,8 +1253,9 @@ bool wxPropertyGridPageState::DoSetPropertyValueString( wxPGProperty* p, const w
         if ( res )
         {
             p->SetValue(variant);
-            if ( m_selected==p && this==m_pPropGrid->GetState() )
-                p->UpdateControl(m_pPropGrid->GetEditorControl());
+            if ( p == m_pPropGrid->GetSelection() &&
+                 this == m_pPropGrid->GetState() )
+                m_pPropGrid->RefreshEditor();
         }
 
         return true;
@@ -1099,8 +1270,9 @@ bool wxPropertyGridPageState::DoSetPropertyValue( wxPGProperty* p, wxVariant& va
     if ( p )
     {
         p->SetValue(value);
-        if ( m_selected==p && this==m_pPropGrid->GetState() )
-            p->UpdateControl(m_pPropGrid->GetEditorControl());
+        if ( p == m_pPropGrid->GetSelection() &&
+             this == m_pPropGrid->GetState() )
+            m_pPropGrid->RefreshEditor();
 
         return true;
     }
@@ -1121,35 +1293,56 @@ bool wxPropertyGridPageState::DoSetPropertyValueWxObjectPtr( wxPGProperty* p, wx
     return false;
 }
 
+// -----------------------------------------------------------------------
+// wxPropertyGridPageState property operations
 // -----------------------------------------------------------------------
 
-void wxPropertyGridPageState::DoSetPropertyValueUnspecified( wxPGProperty* p )
+bool wxPropertyGridPageState::DoIsPropertySelected( wxPGProperty* prop ) const
 {
-    wxCHECK_RET( p, wxT("invalid property id") );
+    if ( wxPGFindInVector(m_selection, prop) != wxNOT_FOUND )
+        return true;
 
-    if ( !p->IsValueUnspecified() )
-    {
-        // Value should be set first - editor class methods may need it
-        p->m_value.MakeNull();
+    return false;
+}
 
-        wxASSERT( m_pPropGrid );
+// -----------------------------------------------------------------------
 
-        if ( m_pPropGrid->GetState() == this )
+void wxPropertyGridPageState::DoRemoveFromSelection( wxPGProperty* prop )
+{
+    for ( unsigned int i=0; i<m_selection.size(); i++ )
+    {
+        if ( m_selection[i] == prop )
         {
-            if ( m_pPropGrid->m_selected == p && m_pPropGrid->m_wndEditor )
+            wxPropertyGrid* pg = m_pPropGrid;
+            if ( i == 0 && pg->GetState() == this )
+            {
+                // If first item (ie. one with the active editor) was
+                // deselected, then we need to take some extra measures.
+                wxArrayPGProperty sel = m_selection;
+                sel.erase( sel.begin() + i );
+
+                wxPGProperty* newFirst;
+                if ( sel.size() )
+                    newFirst = sel[0];
+                else
+                    newFirst = NULL;
+
+                pg->DoSelectProperty(newFirst,
+                                     wxPG_SEL_DONT_SEND_EVENT);
+
+                m_selection = sel;
+
+                pg->Refresh();
+            }
+            else
             {
-                p->GetEditorClass()->SetValueToUnspecified(p, m_pPropGrid->GetEditorControl());
+                m_selection.erase( m_selection.begin() + i );
             }
+            return;
         }
-
-        unsigned int i;
-        for ( i = 0; i < p->GetChildCount(); i++ )
-            DoSetPropertyValueUnspecified( p->Item(i) );
     }
 }
 
-// -----------------------------------------------------------------------
-// wxPropertyGridPageState property operations
 // -----------------------------------------------------------------------
 
 bool wxPropertyGridPageState::DoCollapse( wxPGProperty* p )
@@ -1191,7 +1384,7 @@ bool wxPropertyGridPageState::DoSelectProperty( wxPGProperty* p, unsigned int fl
     if ( this == m_pPropGrid->GetState() )
         return m_pPropGrid->DoSelectProperty( p, flags );
 
-    m_selected = p;
+    DoSetSelection(p);
     return true;
 }
 
@@ -1199,18 +1392,7 @@ bool wxPropertyGridPageState::DoSelectProperty( wxPGProperty* p, unsigned int fl
 
 bool wxPropertyGridPageState::DoHideProperty( wxPGProperty* p, bool hide, int flags )
 {
-    if ( !hide )
-        p->ClearFlag( wxPG_PROP_HIDDEN );
-    else
-        p->SetFlag( wxPG_PROP_HIDDEN );
-
-    if ( flags & wxPG_RECURSE )
-    {
-        unsigned int i;
-        for ( i = 0; i < p->GetChildCount(); i++ )
-            DoHideProperty(p->Item(i), hide, flags | wxPG_RECURSE_STARTS);
-    }
-
+    p->DoHide(hide, flags);
     VirtualHeightChanged();
 
     return true;
@@ -1343,7 +1525,7 @@ void wxPropertyGridPageState::DoSetPropertyValues( const wxVariantList& list, wx
 
     //
     // Second pass for special entries
-    for ( node = list.begin(); node != list.end(); node++ )
+    for ( node = list.begin(); node != list.end(); ++node )
     {
         wxVariant *current = (wxVariant*)*node;
 
@@ -1371,18 +1553,17 @@ void wxPropertyGridPageState::DoSetPropertyValues( const wxVariantList& list, wx
                     if ( wxStrcmp(current->GetType(), wxS("list")) == 0 )
                     {
                         DoSetPropertyValues( current->GetList(),
-                                p->IsCategory()?p:((wxPGProperty*)NULL)
+                                p->IsCategory()?p:(NULL)
                             );
                     }
                     else
                     {
-                #ifdef __WXDEBUG__
-                        if ( wxStrcmp(current->GetType(), p->GetValue().GetType()) != 0)
-                        {
-                            wxLogDebug(wxT("wxPropertyGridPageState::DoSetPropertyValues Warning: Setting value of property \"%s\" from variant"),
-                                p->GetName().c_str());
-                        }
-                #endif
+                        wxASSERT_LEVEL_2_MSG(
+                            wxStrcmp(current->GetType(), p->GetValue().GetType()) == 0,
+                            wxString::Format(
+                                wxS("setting value of property \"%s\" from variant"),
+                                p->GetName().c_str())
+                        );
 
                         p->SetValue(*current);
                     }
@@ -1407,7 +1588,7 @@ void wxPropertyGridPageState::DoSetPropertyValues( const wxVariantList& list, wx
 
     if ( numSpecialEntries )
     {
-        for ( node = list.begin(); node != list.end(); node++ )
+        for ( node = list.begin(); node != list.end(); ++node )
         {
             wxVariant *current = (wxVariant*)*node;
 
@@ -1438,7 +1619,7 @@ void wxPropertyGridPageState::DoSetPropertyValues( const wxVariantList& list, wx
                                 wxVariantList& list2 = current->GetList();
                                 wxVariantList::const_iterator node2;
 
-                                for ( node2 = list2.begin(); node2 != list2.end(); node2++ )
+                                for ( node2 = list2.begin(); node2 != list2.end(); ++node2 )
                                 {
                                     wxVariant *attr = (wxVariant*)*node2;
                                     foundProp->SetAttribute( attr->GetName(), *attr );
@@ -1467,9 +1648,7 @@ void wxPropertyGridPageState::DoSetPropertyValues( const wxVariantList& list, wx
         m_pPropGrid->Thaw();
 
         if ( this == m_pPropGrid->GetState() )
-        {
-            m_selected->UpdateControl(m_pPropGrid->GetEditorControl());
-        }
+            m_pPropGrid->RefreshEditor();
     }
 
 }
@@ -1478,14 +1657,14 @@ void wxPropertyGridPageState::DoSetPropertyValues( const wxVariantList& list, wx
 // wxPropertyGridPageState property adding and removal
 // -----------------------------------------------------------------------
 
-int wxPropertyGridPageState::PrepareToAddItem( wxPGProperty* property,
-                                           wxPGProperty* scheduledParent )
+bool wxPropertyGridPageState::PrepareToAddItem( wxPGProperty* property,
+                                                wxPGProperty* scheduledParent )
 {
     wxPropertyGrid* propGrid = m_pPropGrid;
 
     // This will allow better behavior.
     if ( scheduledParent == m_properties )
-        scheduledParent = (wxPGProperty*) NULL;
+        scheduledParent = NULL;
 
     if ( scheduledParent && !scheduledParent->IsCategory() )
     {
@@ -1515,140 +1694,44 @@ int wxPropertyGridPageState::PrepareToAddItem( wxPGProperty* property,
             {
                 delete property;
                 m_currentCategory = pwc;
-                return 2; // Tells the caller what we did.
+                return false;
             }
         }
     }
 
-#ifdef __WXDEBUG__
+#if wxDEBUG_LEVEL
     // Warn for identical names in debug mode.
     if ( BaseGetPropertyByName(property->GetName()) &&
          (!scheduledParent || scheduledParent->IsCategory()) )
     {
-        wxLogError(wxT("wxPropertyGrid: Warning - item with name \"%s\" already exists."),
-            property->GetName().c_str());
-        wxPGGlobalVars->m_warnings++;
-    }
-#endif
-
-    // Make sure nothing is selected.
-    if ( propGrid && propGrid->m_selected )
-    {
-        bool selRes = propGrid->ClearSelection();
-        wxPG_CHECK_MSG_DBG( selRes,
-                            -1,
-                            wxT("failed to deselect a property (editor probably had invalid value)") );
-    }
-
-    if ( scheduledParent )
-    {
-        // Use parent's colours.
-        property->m_bgColIndex = scheduledParent->m_bgColIndex;
-        property->m_fgColIndex = scheduledParent->m_fgColIndex;
-
-        // Fix no parent does not yet have parenting flag yet, set one now
-        if ( !scheduledParent->HasFlag(wxPG_PROP_PARENTAL_FLAGS) )
-            scheduledParent->SetParentalType(wxPG_PROP_MISC_PARENT);
-            //scheduledParent->SetFlag(wxPG_PROP_MISC_PARENT);
-    }
+        wxFAIL_MSG(wxString::Format(
+            "wxPropertyGrid item with name \"%s\" already exists",
+            property->GetName()));
 
-    // If in hideable adding mode, or if assigned parent is hideable, then
-    // make this one hideable.
-    if (
-         ( scheduledParent && (scheduledParent->m_flags & wxPG_PROP_HIDDEN) ) ||
-         ( propGrid && (propGrid->m_iFlags & wxPG_FL_ADDING_HIDEABLES) )
-       )
-        property->SetFlag( wxPG_PROP_HIDDEN );
-
-    // Set custom image flag.
-    int custImgHeight = property->OnMeasureImage().y;
-    if ( custImgHeight < 0 /*|| custImgHeight > 1*/ )
-    {
-        property->m_flags |= wxPG_PROP_CUSTOMIMAGE;
+        wxPGGlobalVars->m_warnings++;
     }
+#endif // wxDEBUG_LEVEL
 
-    if ( propGrid && (propGrid->GetWindowStyleFlag() & wxPG_LIMITED_EDITING) )
-        property->m_flags |= wxPG_PROP_NOEDITOR;
-
-    if ( !property->IsCategory() )
-    {
-        // This is not a category.
-
-        //wxASSERT_MSG( property->GetEditorClass(), wxT("Editor class not initialized!") );
-
-        // Depth.
-        //
-        unsigned char depth = 1;
-        if ( scheduledParent )
-        {
-            depth = scheduledParent->m_depth;
-            if ( !scheduledParent->IsCategory() )
-                depth++;
-        }
-        property->m_depth = depth;
-        unsigned char greyDepth = depth;
+    // NULL parent == root parent
+    if ( !scheduledParent )
+        scheduledParent = DoGetRoot();
 
-        if ( scheduledParent )
-        {
-            wxPropertyCategory* pc;
+    property->m_parent = scheduledParent;
 
-            if ( scheduledParent->IsCategory() || scheduledParent->IsRoot() )
-                pc = (wxPropertyCategory*)scheduledParent;
-            else
-                // This conditional compile is necessary to
-                // bypass some compiler bug.
-                pc = GetPropertyCategory(scheduledParent);
+    property->InitAfterAdded(this, propGrid);
 
-            if ( pc )
-                greyDepth = pc->GetDepth();
-            else
-                greyDepth = scheduledParent->m_depthBgCol;
-        }
-
-        property->m_depthBgCol = greyDepth;
-
-        // Prepare children pre-added children
-        if ( property->GetChildCount() )
-        {
-            property->SetParentalType(wxPG_PROP_AGGREGATE);
-
-            property->SetExpanded(false); // Properties with children are not expanded by default.
-            if ( propGrid && propGrid->GetWindowStyleFlag() & wxPG_HIDE_MARGIN )
-                property->SetExpanded(true); // ...unless it cannot be expanded.
-
-            property->PrepareSubProperties();
-
-            return -1;
-        }
-
-        if ( propGrid && (propGrid->GetExtraStyle() & wxPG_EX_AUTO_UNSPECIFIED_VALUES) )
-            property->SetFlagRecursively(wxPG_PROP_AUTO_UNSPECIFIED, true);
-
-        return 0;
-    }
-    else
+    if ( property->IsCategory() )
     {
-        // This is a category.
-
-        // depth
-        unsigned char depth = 1;
-        if ( scheduledParent )
-        {
-            depth = scheduledParent->m_depth + 1;
-        }
-        property->m_depth = depth;
-        property->m_depthBgCol = depth;
+        wxPropertyCategory* pc = wxStaticCast(property, wxPropertyCategory);
 
-        m_currentCategory = (wxPropertyCategory*)property;
+        m_currentCategory = pc;
 
-        wxPropertyCategory* pc = (wxPropertyCategory*)property;
-
-        // Calculate text extent for caption item.
+        // Calculate text extent for category caption
         if ( propGrid )
             pc->CalculateTextExtent(propGrid, propGrid->GetCaptionFont());
-
-        return 1;
     }
+
+    return true;
 }
 
 // -----------------------------------------------------------------------
@@ -1657,7 +1740,7 @@ wxPGProperty* wxPropertyGridPageState::DoAppend( wxPGProperty* property )
 {
     wxPropertyCategory* cur_cat = m_currentCategory;
     if ( property->IsCategory() )
-        cur_cat = (wxPropertyCategory*) NULL;
+        cur_cat = NULL;
 
     return DoInsert( cur_cat, -1, property );
 }
@@ -1673,13 +1756,16 @@ wxPGProperty* wxPropertyGridPageState::DoInsert( wxPGProperty* parent, int index
                  wxNullProperty,
                  wxT("when adding properties to fixed parents, use BeginAddChildren and EndAddChildren.") );
 
-    int parenting = PrepareToAddItem( property, (wxPropertyCategory*)parent );
+    bool res = PrepareToAddItem( property, (wxPropertyCategory*)parent );
 
-    // This type of invalid parenting value indicates we should exit now, returning
-    // id of most recent category.
-    if ( parenting > 1 )
+    // PrepareToAddItem() may just decide to use use current category
+    // instead of adding new one.
+    if ( !res )
         return m_currentCategory;
 
+    bool parentIsRoot = parent->IsRoot();
+    bool parentIsCategory = parent->IsCategory();
+
     // Note that item must be added into current mode later.
 
     // If parent is wxParentProperty, just stick it in...
@@ -1692,42 +1778,34 @@ wxPGProperty* wxPropertyGridPageState::DoInsert( wxPGProperty* parent, int index
     //   1) Add to given category in given index.
     //   2) Add as last item in m_abcArray.
 
-    if ( !parent->IsCategory() && !parent->IsRoot() )
-    {
-        // Parent is wxParentingProperty: Just stick it in...
-        parent->AddChild2( property, index );
-    }
-    else
+    if ( m_properties == &m_regularArray )
     {
-        // Parent is Category or Root.
+        // We are currently in Categorized mode
 
-        if ( m_properties == &m_regularArray )
+        // Only add non-categories to m_abcArray.
+        if ( m_abcArray && !property->IsCategory() &&
+             (parentIsCategory || parentIsRoot) )
         {
-            // Categorized mode
-
-            // Only add non-categories to m_abcArray.
-            if ( m_abcArray && parenting <= 0 )
-                m_abcArray->AddChild2( property, -1, false );
-
-            // Add to current mode.
-            parent->AddChild2( property, index );
-
+            m_abcArray->DoAddChild( property, -1, false );
         }
-        else
-        {
-            // Non-categorized mode.
-
-            if ( parent != m_properties )
-                // Parent is category.
-                parent->AddChild2( property, index, false );
-            else
-                // Parent is root.
-                m_regularArray.AddChild2( property, -1, false );
 
-            // Add to current mode (no categories).
-            if ( parenting <= 0 )
-                m_abcArray->AddChild2( property, index );
-        }
+        // Add to current mode.
+        parent->DoAddChild( property, index, true );
+    }
+    else
+    {
+        // We are currently in Non-categorized/Alphabetic mode
+
+        if ( parentIsCategory )
+            // Parent is category.
+            parent->DoAddChild( property, index, false );
+        else if ( parentIsRoot )
+            // Parent is root.
+            m_regularArray.DoAddChild( property, -1, false );
+
+        // Add to current mode
+        if ( !property->IsCategory() )
+            m_abcArray->DoAddChild( property, index, true );
     }
 
     // category stuff
@@ -1740,7 +1818,8 @@ wxPGProperty* wxPropertyGridPageState::DoInsert( wxPGProperty* parent, int index
     }
 
     // Only add name to hashmap if parent is root or category
-    if ( (parent->IsCategory() || parent->IsRoot()) && property->m_name.length() )
+    if ( property->m_name.length() &&
+        (parentIsCategory || parentIsRoot) )
         m_dictName[property->m_name] = (void*) property;
 
     VirtualHeightChanged();
@@ -1754,7 +1833,7 @@ wxPGProperty* wxPropertyGridPageState::DoInsert( wxPGProperty* parent, int index
 
 // -----------------------------------------------------------------------
 
-void wxPropertyGridPageState::DoDelete( wxPGProperty* item )
+void wxPropertyGridPageState::DoDelete( wxPGProperty* item, bool doDelete )
 {
     wxCHECK_RET( item->GetParent(),
         wxT("this property was already deleted") );
@@ -1762,60 +1841,84 @@ void wxPropertyGridPageState::DoDelete( wxPGProperty* item )
     wxCHECK_RET( item != &m_regularArray && item != m_abcArray,
         wxT("wxPropertyGrid: Do not attempt to remove the root item.") );
 
-    size_t i;
+    wxPropertyGrid* pg = GetGrid();
+
+    // Must defer deletion? Yes, if handling a wxPG event.
+    if ( pg && pg->m_processedEvent )
+    {
+        if ( doDelete )
+            pg->m_deletedProperties.push_back(item);
+        else
+            pg->m_removedProperties.push_back(item);
+
+        // Rename the property so it won't remain in the way
+        // of the user code.
+
+        // Let's trust that no sane property uses prefix like
+        // this. It would be anyway fairly inconvenient (in
+        // current code) to check whether a new name is used
+        // by another property with parent (due to the child
+        // name notation).
+        wxString newName = wxS("_&/_%$") + item->GetBaseName();
+        DoSetPropertyName(item, newName);
+
+        return;
+    }
+
     unsigned int indinparent = item->GetIndexInParent();
 
     wxPGProperty* pwc = (wxPGProperty*)item;
+    wxPGProperty* parent = item->GetParent();
 
-    wxCHECK_RET( !item->GetParent()->HasFlag(wxPG_PROP_AGGREGATE),
+    wxCHECK_RET( !parent->HasFlag(wxPG_PROP_AGGREGATE),
         wxT("wxPropertyGrid: Do not attempt to remove sub-properties.") );
 
-    if ( item->IsCategory() )
-    {
-        // deleting a category
+    wxASSERT( item->GetParentState() == this );
 
-        // erase category entries from the hash table
-        for ( i=0; i<pwc->GetChildCount(); i++ )
+    if ( DoIsPropertySelected(item) )
+    {
+        if ( pg && pg->GetState() == this )
+        {
+            pg->DoRemoveFromSelection(item,
+                wxPG_SEL_DELETING|wxPG_SEL_NOVALIDATE);
+        }
+        else
         {
-            wxPGProperty* sp = pwc->Item( i );
-            if ( sp->GetBaseName().Len() ) m_dictName.erase(sp->GetBaseName());
+            DoRemoveFromSelection(item);
         }
+    }
 
-        if ( pwc == m_currentCategory )
-            m_currentCategory = (wxPropertyCategory*) NULL;
+    item->SetFlag(wxPG_PROP_BEING_DELETED);
 
-        if ( m_abcArray )
+    // Delete children
+    if ( item->GetChildCount() && !item->HasFlag(wxPG_PROP_AGGREGATE) )
+    {
+        // deleting a category
+        if ( item->IsCategory() )
         {
-            // Remove children from non-categorized array.
-            for ( i=0; i<pwc->GetChildCount(); i++ )
-            {
-                wxPGProperty * p = pwc->Item( i );
-                wxASSERT( p != NULL );
-                if ( !p->IsCategory() )
-                    m_abcArray->m_children.Remove( p );
-            }
-
-            if ( IsInNonCatMode() )
-                m_abcArray->FixIndexesOfChildren();
+            if ( pwc == m_currentCategory )
+                m_currentCategory = NULL;
         }
+
+        item->DeleteChildren();
     }
 
     if ( !IsInNonCatMode() )
     {
         // categorized mode - non-categorized array
 
-        // Remove from non-cat array, but only if parent is in it
-        if ( !item->IsCategory() && item->GetParent()->IsCategory() )
+        // Remove from non-cat array
+        if ( !item->IsCategory() &&
+             (parent->IsCategory() || parent->IsRoot()) )
         {
             if ( m_abcArray )
-            {
-                m_abcArray->m_children.Remove( item );
-            }
+                m_abcArray->RemoveChild(item);
         }
 
         // categorized mode - categorized array
-        item->m_parent->m_children.RemoveAt(indinparent);
-        item->m_parent->FixIndexesOfChildren(/*indinparent*/);
+        wxArrayPGProperty& parentsChildren = parent->m_children;
+        parentsChildren.erase( parentsChildren.begin() + indinparent );
+        item->m_parent->FixIndicesOfChildren();
     }
     else
     {
@@ -1840,21 +1943,33 @@ void wxPropertyGridPageState::DoDelete( wxPGProperty* item )
                 }
             }
         }
-        cat_parent->m_children.RemoveAt(cat_index);
+        cat_parent->m_children.erase(cat_parent->m_children.begin()+cat_index);
 
         // non-categorized mode - non-categorized array
         if ( !item->IsCategory() )
         {
             wxASSERT( item->m_parent == m_abcArray );
-            item->m_parent->m_children.RemoveAt(indinparent);
-            item->m_parent->FixIndexesOfChildren(indinparent);
+            wxArrayPGProperty& parentsChildren = item->m_parent->m_children;
+            parentsChildren.erase(parentsChildren.begin() + indinparent);
+            item->m_parent->FixIndicesOfChildren(indinparent);
         }
     }
 
-    if ( item->GetBaseName().Len() ) m_dictName.erase(item->GetBaseName());
+    if ( item->GetBaseName().length() &&
+         (parent->IsCategory() || parent->IsRoot()) )
+        m_dictName.erase(item->GetBaseName());
+
+    // We need to clear parent grid's m_propHover, if it matches item
+    if ( pg && pg->m_propHover == item )
+        pg->m_propHover = NULL;
+
+    // Mark the property as 'unattached'
+    item->m_parentState = NULL;
+    item->m_parent = NULL;
 
     // We can actually delete it now
-    delete item;
+    if ( doDelete )
+        delete item;
 
     m_itemsAdded = 1; // Not a logical assignment (but required nonetheless).