]> git.saurik.com Git - wxWidgets.git/blobdiff - src/propgrid/propgrid.cpp
fixing setting initial value under osx_cocoa for single line text controls
[wxWidgets.git] / src / propgrid / propgrid.cpp
index 62459e647616ff0b9350769afcc3127442938757..18370b90df7aa76163f3c6f7fc1db799e731aa8b 100644 (file)
 #include "wx/timer.h"
 #include "wx/dcbuffer.h"
 
-#ifdef __WXMSW__
-    #include "wx/msw/private.h"
-#endif
-
 // Two pics for the expand / collapse buttons.
 // Files are not supplied with this project (since it is
 // recommended to use either custom or native rendering).
@@ -398,8 +394,10 @@ bool wxPropertyGrid::Create( wxWindow *parent,
                              const wxString& name )
 {
 
-    if ( !(style&wxBORDER_MASK) )
-        style |= wxSIMPLE_BORDER;
+    if (!(style&wxBORDER_MASK))
+    {
+        style |= wxBORDER_THEME;
+    }
 
     style |= wxVSCROLL;
 
@@ -428,11 +426,14 @@ void wxPropertyGrid::Init1()
     m_iFlags = 0;
     m_pState = NULL;
     m_wndEditor = m_wndEditor2 = NULL;
-    m_selected = NULL;
-    m_selColumn = -1;
+    m_selColumn = 1;
+    m_colHover = 1;
     m_propHover = NULL;
+    m_labelEditor = NULL;
+    m_labelEditorProperty = NULL;
     m_eventObject = this;
     m_curFocused = NULL;
+    m_processedEvent = NULL;
     m_sortFunction = NULL;
     m_inDoPropertyChanged = 0;
     m_inCommitChangesFromEditor = 0;
@@ -553,7 +554,6 @@ void wxPropertyGrid::Init2()
     m_tlp = NULL;
     m_tlpClosed = NULL;
     m_tlpClosedTime = 0;
-    OnTLPChanging(::wxGetTopLevelParent(this));
 
     // set virtual size to this window size
     wxSize wndsize = GetSize();
@@ -562,7 +562,7 @@ void wxPropertyGrid::Init2()
     m_timeCreated = ::wxGetLocalTimeMillis();
 
     m_canvas = new wxPGCanvas();
-    m_canvas->Create(this, 1, wxPoint(0, 0), GetClientSize(),
+    m_canvas->Create(this, wxID_ANY, wxPoint(0, 0), GetClientSize(),
                      wxWANTS_CHARS | wxCLIP_CHILDREN);
     m_canvas->SetBackgroundStyle( wxBG_STYLE_CUSTOM );
 
@@ -582,7 +582,38 @@ wxPropertyGrid::~wxPropertyGrid()
 {
     size_t i;
 
-    DoSelectProperty(NULL);
+#if wxUSE_THREADS
+    wxCriticalSectionLocker(wxPGGlobalVars->m_critSect);
+#endif
+
+    //
+    // Remove grid and property pointers from live wxPropertyGridEvents.
+    for ( i=0; i<m_liveEvents.size(); i++ )
+    {
+        wxPropertyGridEvent* evt = m_liveEvents[i];
+        evt->SetPropertyGrid(NULL);
+        evt->SetProperty(NULL);
+    }
+    m_liveEvents.clear();
+
+    if ( m_processedEvent )
+    {
+        // All right... we are being deleted while wxPropertyGrid event
+        // is being sent. Make sure that event propagates as little
+        // as possible (although usually this is not enough to prevent
+        // a crash).
+        m_processedEvent->Skip(false);
+        m_processedEvent->StopPropagation();
+
+        // Let's use wxMessageBox to make the message appear more
+        // reliably (and *before* the crash can happen).
+        ::wxMessageBox("wxPropertyGrid was being destroyed in an event "
+                       "generated by it. This usually leads to a crash "
+                       "so it is recommended to destroy the control "
+                       "at idle time instead.");
+    }
+
+    DoSelectProperty(NULL, wxPG_SEL_NOVALIDATE|wxPG_SEL_DONT_SEND_EVENT);
 
     // This should do prevent things from going too badly wrong
     m_iFlags &= ~(wxPG_FL_INITIALIZED);
@@ -591,20 +622,22 @@ wxPropertyGrid::~wxPropertyGrid()
         m_canvas->ReleaseMouse();
 
     // Call with NULL to disconnect event handling
-    OnTLPChanging(NULL);
+    if ( GetExtraStyle() & wxPG_EX_ENABLE_TLP_TRACKING )
+    {
+        OnTLPChanging(NULL);
 
-    wxASSERT_MSG( !IsEditorsValueModified(),
-                  wxS("Most recent change in property editor was lost!!! ")
-                  wxS("(if you don't want this to happen, close your frames ")
-                  wxS("and dialogs using Close(false).)") );
+        wxASSERT_MSG( !IsEditorsValueModified(),
+                      wxS("Most recent change in property editor was ")
+                      wxS("lost!!! (if you don't want this to happen, ")
+                      wxS("close your frames and dialogs using ")
+                      wxS("Close(false).)") );
+    }
 
 #if wxPG_DOUBLE_BUFFER
     if ( m_doubleBuffer )
         delete m_doubleBuffer;
 #endif
 
-    //m_selected = NULL;
-
     if ( m_iFlags & wxPG_FL_CREATEDSTATE )
         delete m_pState;
 
@@ -618,7 +651,9 @@ wxPropertyGrid::~wxPropertyGrid()
     // Delete common value records
     for ( i=0; i<m_commonValues.size(); i++ )
     {
-        delete GetCommonValue(i);
+        // Use temporary variable to work around possible strange VC6 (asserts because m_size is zero)
+        wxPGCommonValue* value = m_commonValues[i];
+        delete value;
     }
 }
 
@@ -731,15 +766,364 @@ void wxPropertyGrid::Thaw()
     #endif
 
         // Force property re-selection
-        if ( m_selected )
-            DoSelectProperty(m_selected, wxPG_SEL_FORCE);
+        // NB: We must copy the selection.
+        wxArrayPGProperty selection = m_pState->m_selection;
+        DoSetSelection(selection, wxPG_SEL_FORCE);
+    }
+}
+
+// -----------------------------------------------------------------------
+
+bool wxPropertyGrid::DoAddToSelection( wxPGProperty* prop, int selFlags )
+{
+    wxCHECK( prop, false );
+
+    if ( !(GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION) )
+        return DoSelectProperty(prop, selFlags);
+
+    wxArrayPGProperty& selection = m_pState->m_selection;
+
+    if ( !selection.size() )
+    {
+        return DoSelectProperty(prop, selFlags);
+    }
+    else
+    {
+        // For categories, only one can be selected at a time
+        if ( prop->IsCategory() || selection[0]->IsCategory() )
+            return true;
+
+        selection.push_back(prop);
+
+        if ( !(selFlags & wxPG_SEL_DONT_SEND_EVENT) )
+        {
+            SendEvent( wxEVT_PG_SELECTED, prop, NULL );
+        }
+
+        DrawItem(prop);
+    }
+
+    return true;
+}
+
+// -----------------------------------------------------------------------
+
+bool wxPropertyGrid::DoRemoveFromSelection( wxPGProperty* prop, int selFlags )
+{
+    wxCHECK( prop, false );
+    bool res;
+
+    wxArrayPGProperty& selection = m_pState->m_selection;
+    if ( selection.size() <= 1 )
+    {
+        res = DoSelectProperty(NULL, selFlags);
+    }
+    else
+    {
+        m_pState->DoRemoveFromSelection(prop);
+        DrawItem(prop);
+        res = true;
+    }
+
+    return res;
+}
+
+// -----------------------------------------------------------------------
+
+bool wxPropertyGrid::DoSelectAndEdit( wxPGProperty* prop,
+                                      unsigned int colIndex,
+                                      unsigned int selFlags )
+{
+    //
+    // NB: Enable following if label editor background colour is
+    //     ever changed to any other than m_colSelBack.
+    //
+    // We use this workaround to prevent visible flicker when editing
+    // a cell. Atleast on wxMSW, there is a difficult to find
+    // (and perhaps prevent) redraw somewhere between making property
+    // selected and enabling label editing.
+    //
+    //wxColour prevColSelBack = m_colSelBack;
+    //m_colSelBack = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
+
+    bool res;
+
+    if ( colIndex == 1 )
+    {
+        res = DoSelectProperty(prop, selFlags);
+    }
+    else
+    {
+        // send event
+        DoClearSelection(false, wxPG_SEL_NO_REFRESH);
+
+        if ( m_pState->m_editableColumns.Index(colIndex) == wxNOT_FOUND )
+        {
+            res = DoAddToSelection(prop, selFlags);
+        }
+        else
+        {
+            res = DoAddToSelection(prop, selFlags|wxPG_SEL_NO_REFRESH);
+
+            DoBeginLabelEdit(colIndex, selFlags);
+        }
+    }
+
+    //m_colSelBack = prevColSelBack;
+    return res;
+}
+
+// -----------------------------------------------------------------------
+
+bool wxPropertyGrid::AddToSelectionFromInputEvent( wxPGProperty* prop,
+                                                   unsigned int colIndex,
+                                                   wxMouseEvent* mouseEvent,
+                                                   int selFlags )
+{
+    bool alreadySelected = m_pState->DoIsPropertySelected(prop);
+    bool res = true;
+    bool addToExistingSelection;
+
+    if ( GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION )
+    {
+        if ( mouseEvent )
+        {
+            if ( mouseEvent->GetEventType() == wxEVT_RIGHT_DOWN ||
+                 mouseEvent->GetEventType() == wxEVT_RIGHT_UP )
+            {
+                // Allow right-click for context menu without
+                // disturbing the selection.
+                if ( GetSelectedProperties().size() <= 1 ||
+                     !alreadySelected )
+                    return DoSelectAndEdit(prop, colIndex, selFlags);
+                return true;
+            }
+            else
+            {
+                addToExistingSelection = mouseEvent->ShiftDown();
+            }
+        }
+        else
+        {
+            addToExistingSelection = false;
+        }
+    }
+    else
+    {
+        addToExistingSelection = false;
+    }
+
+    if ( addToExistingSelection )
+    {
+        if ( !alreadySelected )
+        {
+            res = DoAddToSelection(prop, selFlags);
+        }
+        else if ( GetSelectedProperties().size() > 1 )
+        {
+            res = DoRemoveFromSelection(prop, selFlags);
+        }
+    }
+    else
+    {
+        res = DoSelectAndEdit(prop, colIndex, selFlags);
+    }
+
+    return res;
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::DoSetSelection( const wxArrayPGProperty& newSelection,
+                                     int selFlags )
+{
+    if ( newSelection.size() > 0 )
+    {
+        if ( !DoSelectProperty(newSelection[0], selFlags) )
+            return;
+    }
+    else
+    {
+        DoClearSelection(false, selFlags);
+    }
+
+    for ( unsigned int i = 1; i < newSelection.size(); i++ )
+    {
+        DoAddToSelection(newSelection[i], selFlags);
+    }
+
+    Refresh();
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::MakeColumnEditable( unsigned int column,
+                                         bool editable )
+{
+    wxASSERT( column != 1 );
+
+    wxArrayInt& cols = m_pState->m_editableColumns;
+
+    if ( editable )
+    {
+        cols.push_back(column);
+    }
+    else
+    {
+        for ( int i = cols.size() - 1; i > 0; i-- )
+        {
+            if ( cols[i] == (int)column )
+                cols.erase( cols.begin() + i );
+        }
+    }
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::DoBeginLabelEdit( unsigned int colIndex,
+                                       int selFlags )
+{
+    wxPGProperty* selected = GetSelection();
+    wxCHECK_RET(selected, wxT("No property selected"));
+    wxCHECK_RET(colIndex != 1, wxT("Do not use this for column 1"));
+
+    if ( !(selFlags & wxPG_SEL_DONT_SEND_EVENT) )
+    {
+        if ( SendEvent( wxEVT_PG_LABEL_EDIT_BEGIN,
+                        selected, NULL, 0,
+                        colIndex ) )
+            return;
+    }
+
+    wxString text;
+    const wxPGCell* cell = NULL;
+    if ( selected->HasCell(colIndex) )
+    {
+        cell = &selected->GetCell(colIndex);
+        if ( !cell->HasText() && colIndex == 0 )
+            text = selected->GetLabel();
+    }
+
+    if ( !cell  )
+    {
+        if ( colIndex == 0 )
+            text = selected->GetLabel();
+        else
+            cell = &selected->GetOrCreateCell(colIndex);
+    }
+
+    if ( cell && cell->HasText() )
+        text = cell->GetText();
+
+    DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE);  // send event
+
+    m_selColumn = colIndex;
+
+    wxRect r = GetEditorWidgetRect(selected, m_selColumn);
+
+    wxWindow* tc = GenerateEditorTextCtrl(r.GetPosition(),
+                                          r.GetSize(),
+                                          text,
+                                          NULL,
+                                          wxTE_PROCESS_ENTER,
+                                          0,
+                                          colIndex);
+
+    wxWindowID id = tc->GetId();
+    tc->Connect(id, wxEVT_COMMAND_TEXT_ENTER,
+        wxCommandEventHandler(wxPropertyGrid::OnLabelEditorEnterPress),
+        NULL, this);
+    tc->Connect(id, wxEVT_KEY_DOWN,
+        wxKeyEventHandler(wxPropertyGrid::OnLabelEditorKeyPress),
+        NULL, this);
+
+    tc->SetFocus();
+
+    m_labelEditor = wxStaticCast(tc, wxTextCtrl);
+    m_labelEditorProperty = selected;
+}
+
+// -----------------------------------------------------------------------
+
+void
+wxPropertyGrid::OnLabelEditorEnterPress( wxCommandEvent& WXUNUSED(event) )
+{
+    DoEndLabelEdit(true);
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::OnLabelEditorKeyPress( wxKeyEvent& event )
+{
+    int keycode = event.GetKeyCode();
+
+    if ( keycode == WXK_ESCAPE )
+    {
+        DoEndLabelEdit(false);
+    }
+    else
+    {
+        event.Skip();
+    }
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::DoEndLabelEdit( bool commit, int selFlags )
+{
+    if ( !m_labelEditor )
+        return;
+
+    wxPGProperty* prop = m_labelEditorProperty;
+    wxASSERT(prop);
+
+    if ( commit )
+    {
+        if ( !(selFlags & wxPG_SEL_DONT_SEND_EVENT) )
+        {
+            // wxPG_SEL_NOVALIDATE is passed correctly in selFlags
+            if ( SendEvent( wxEVT_PG_LABEL_EDIT_ENDING,
+                            prop, NULL, selFlags,
+                            m_selColumn ) )
+                return;
+        }
+
+        wxString text = m_labelEditor->GetValue();
+        wxPGCell* cell = NULL;
+        if ( prop->HasCell(m_selColumn) )
+        {
+            cell = &prop->GetCell(m_selColumn);
+        }
+        else
+        {
+            if ( m_selColumn == 0 )
+                prop->SetLabel(text);
+            else
+                cell = &prop->GetOrCreateCell(m_selColumn);
+        }
+
+        if ( cell )
+            cell->SetText(text);
     }
+
+    m_selColumn = 1;
+
+    DestroyEditorWnd(m_labelEditor);
+    m_labelEditor = NULL;
+    m_labelEditorProperty = NULL;
+
+    DrawItem(prop);
 }
 
 // -----------------------------------------------------------------------
 
 void wxPropertyGrid::SetExtraStyle( long exStyle )
 {
+    if ( exStyle & wxPG_EX_ENABLE_TLP_TRACKING )
+        OnTLPChanging(::wxGetTopLevelParent(this));
+    else
+        OnTLPChanging(NULL);
+
     if ( exStyle & wxPG_EX_NATIVE_DOUBLE_BUFFERING )
     {
 #if defined(__WXMSW__)
@@ -801,7 +1185,15 @@ wxSize wxPropertyGrid::DoGetBestSize() const
                     10
                    );
 
-    const wxSize sz = wxSize(60, lineHeight*numLines + 40);
+    wxClientDC dc(const_cast<wxPropertyGrid *>(this));
+    int width = m_marginWidth;
+    for ( unsigned int i = 0; i < m_pState->m_colWidths.size(); i++ )
+    {
+        width += m_pState->GetColumnFitWidth(dc, m_pState->DoGetRoot(), i, true);
+    }
+
+    const wxSize sz = wxSize(width, lineHeight*numLines + 40);
+
     CacheBestSize(sz);
     return sz;
 }
@@ -810,6 +1202,9 @@ wxSize wxPropertyGrid::DoGetBestSize() const
 
 void wxPropertyGrid::OnTLPChanging( wxWindow* newTLP )
 {
+    if ( newTLP == m_tlp )
+        return;
+
     wxLongLong currentTime = ::wxGetLocalTimeMillis();
 
     //
@@ -849,7 +1244,7 @@ void wxPropertyGrid::OnTLPChanging( wxWindow* newTLP )
 void wxPropertyGrid::OnTLPClose( wxCloseEvent& event )
 {
     // ClearSelection forces value validation/commit.
-    if ( event.CanVeto() && !ClearSelection() )
+    if ( event.CanVeto() && !DoClearSelection() )
     {
         event.Veto();
         return;
@@ -1071,10 +1466,10 @@ void wxPropertyGrid::ResetColours()
 bool wxPropertyGrid::SetFont( const wxFont& font )
 {
     // Must disable active editor.
-    ClearSelection(false);
+    DoClearSelection();
 
     bool res = wxScrolledWindow::SetFont( font );
-    if ( res && GetParent()) // may not have been Create()ed yet
+    if ( res && GetParent()) // may not have been Create()ed yet if SetFont called from SetWindowVariant
     {
         CalculateFontAndBitmapStuff( m_vspacing );
         Refresh();
@@ -1684,7 +2079,7 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
 
     bool reallyFocused = (m_iFlags & wxPG_FL_FOCUSED) != 0;
 
-    bool isEnabled = IsEnabled();
+    bool isPgEnabled = IsEnabled();
 
     //
     // Prepare some pens and brushes that are often changed to.
@@ -1695,6 +2090,12 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
     wxBrush capbgbrush(m_colCapBack,wxSOLID);
     wxPen linepen(m_colLine,1,wxSOLID);
 
+    wxColour selBackCol;
+    if ( isPgEnabled )
+        selBackCol = m_colSelBack;
+    else
+        selBackCol = m_colMargin;
+
     // pen that has same colour as text
     wxPen outlinepen(m_colPropFore,1,wxSOLID);
 
@@ -1708,7 +2109,7 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
         dc.DrawRectangle(-1-xRelMod,firstItemTopY-1,x+2,lastItemBottomY-firstItemTopY+2);
     }
 
-    const wxPGProperty* selected = m_selected;
+    const wxPGProperty* firstSelected = GetSelection();
     const wxPropertyGridPageState* state = m_pState;
 
 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
@@ -1782,8 +2183,28 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
 
         int y2 = y + lh;
 
+#ifdef __WXMSW__
         // Margin Edge
-        dc.DrawLine( greyDepthX, y, greyDepthX, y2 );
+        // Modified by JACS to not draw a margin if wxPG_HIDE_MARGIN is specified, since it
+        // looks better, at least under Windows when we have a themed border (the themed-window-specific
+        // whitespace between the real border and the propgrid margin exacerbates the double-border look).
+
+        // Is this or its parent themed?
+        bool suppressMarginEdge = (GetWindowStyle() & wxPG_HIDE_MARGIN) &&
+            (((GetWindowStyle() & wxBORDER_MASK) == wxBORDER_THEME) ||
+            (((GetWindowStyle() & wxBORDER_MASK) == wxBORDER_NONE) && ((GetParent()->GetWindowStyle() & wxBORDER_MASK) == wxBORDER_THEME)));
+#else
+        bool suppressMarginEdge = false;
+#endif
+        if (!suppressMarginEdge)
+            dc.DrawLine( greyDepthX, y, greyDepthX, y2 );
+        else
+        {
+            // Blank out the margin edge
+            dc.SetPen(wxPen(GetBackgroundColour()));
+            dc.DrawLine( greyDepthX, y, greyDepthX, y2 );
+            dc.SetPen( linepen );
+        }
 
         // Splitters
         unsigned int si;
@@ -1808,7 +2229,9 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
         wxColour rowFgCol;
         wxColour rowBgCol;
 
-        if ( p != selected )
+        bool isSelected = state->DoIsPropertySelected(p);
+
+        if ( !isSelected )
         {
             // Disabled may get different colour.
             if ( !p->IsEnabled() )
@@ -1820,6 +2243,11 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
         }
         else
         {
+#if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
+            if ( p == firstSelected )
+                wasSelectedPainted = true;
+#endif
+
             renderFlags |= wxPGCellRenderer::Selected;
 
             if ( !p->IsCategory() )
@@ -1827,25 +2255,23 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
                 renderFlags |= wxPGCellRenderer::DontUseCellFgCol |
                                wxPGCellRenderer::DontUseCellBgCol;
 
-#if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
-                wasSelectedPainted = true;
-#endif
-
-                // Selected gets different colour.
-                if ( reallyFocused )
+                if ( reallyFocused && p == firstSelected )
                 {
                     rowFgCol = m_colSelFore;
-                    rowBgCol = m_colSelBack;
+                    rowBgCol = selBackCol;
                 }
-                else if ( isEnabled )
+                else if ( isPgEnabled )
                 {
                     rowFgCol = m_colPropFore;
-                    rowBgCol = m_colMargin;
+                    if ( p == firstSelected )
+                        rowBgCol = m_colMargin;
+                    else
+                        rowBgCol = selBackCol;
                 }
                 else
                 {
                     rowFgCol = m_colDisPropFore;
-                    rowBgCol = m_colSelBack;
+                    rowBgCol = selBackCol;
                 }
             }
         }
@@ -1926,24 +2352,47 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
             {
                 cellRect.width = nextCellWidth - 1;
 
-                bool ctrlCell = false;
+                wxWindow* cellEditor = NULL;
                 int cellRenderFlags = renderFlags;
 
-                // Tree Item Button
+                // Tree Item Button (must be drawn before clipping is set up)
                 if ( ci == 0 && !HasFlag(wxPG_HIDE_MARGIN) && p->HasVisibleChildren() )
                     DrawExpanderButton( dc, butRect, p );
 
                 // Background
-                if ( p == selected && m_wndEditor && ci == 1 )
+                if ( isSelected && (ci == 1 || ci == m_selColumn) )
                 {
-                    wxColour editorBgCol = GetEditorControl()->GetBackgroundColour();
-                    dc.SetBrush(editorBgCol);
-                    dc.SetPen(editorBgCol);
-                    dc.SetTextForeground(m_colPropFore);
-                    dc.DrawRectangle(cellRect);
-
-                    if ( m_dragStatus == 0 && !(m_iFlags & wxPG_FL_CUR_USES_CUSTOM_IMAGE) )
-                        ctrlCell = true;
+                    if ( p == firstSelected )
+                    {
+                        if ( ci == 1 && m_wndEditor )
+                            cellEditor = m_wndEditor;
+                        else if ( ci == m_selColumn && m_labelEditor )
+                            cellEditor = m_labelEditor;
+                    }
+
+                    if ( cellEditor )
+                    {
+                        wxColour editorBgCol =
+                            cellEditor->GetBackgroundColour();
+                        dc.SetBrush(editorBgCol);
+                        dc.SetPen(editorBgCol);
+                        dc.SetTextForeground(m_colPropFore);
+                        dc.DrawRectangle(cellRect);
+
+                        if ( m_dragStatus != 0 ||
+                             (m_iFlags & wxPG_FL_CUR_USES_CUSTOM_IMAGE) )
+                            cellEditor = NULL;
+                    }
+                    else
+                    {
+                        dc.SetBrush(m_colPropBack);
+                        dc.SetPen(m_colPropBack);
+                        dc.SetTextForeground(m_colDisPropFore);
+                        if ( p->IsEnabled() )
+                            dc.SetTextForeground(rowFgCol);
+                        else
+                            dc.SetTextForeground(m_colDisPropFore);
+                    }
                 }
                 else
                 {
@@ -1965,7 +2414,7 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
                 cellRect.width -= textXAdd;
 
                 // Foreground
-                if ( !ctrlCell )
+                if ( !cellEditor )
                 {
                     wxPGCellRenderer* renderer;
                     int cmnVal = p->GetCommonValue();
@@ -2038,7 +2487,7 @@ wxRect wxPropertyGrid::GetPropertyRect( const wxPGProperty* p1, const wxPGProper
 
     // If seleced property is inside the range, we'll extend the range to include
     // control's size.
-    wxPGProperty* selected = m_selected;
+    wxPGProperty* selected = GetSelection();
     if ( selected )
     {
         int selectedY = selected->GetY();
@@ -2078,8 +2527,12 @@ void wxPropertyGrid::DrawItems( const wxPGProperty* p1, const wxPGProperty* p2 )
 
 void wxPropertyGrid::RefreshProperty( wxPGProperty* p )
 {
-    if ( p == m_selected )
-        DoSelectProperty(p, wxPG_SEL_FORCE);
+    if ( m_pState->DoIsPropertySelected(p) )
+    {
+        // NB: We must copy the selection.
+        wxArrayPGProperty selection = m_pState->m_selection;
+        DoSetSelection(selection, wxPG_SEL_FORCE);
+    }
 
     DrawItemAndChildren(p);
 }
@@ -2118,7 +2571,8 @@ void wxPropertyGrid::DrawItemAndChildren( wxPGProperty* p )
         return;
 
     // Update child control.
-    if ( m_selected && m_selected->GetParent() == p )
+    wxPGProperty* selected = GetSelection();
+    if ( selected && selected->GetParent() == p )
         RefreshEditor();
 
     const wxPGProperty* lastDrawn = p->GetLastVisibleSubItem();
@@ -2168,7 +2622,7 @@ void wxPropertyGrid::Clear()
 
 bool wxPropertyGrid::EnableCategories( bool enable )
 {
-    ClearSelection(false);
+    DoClearSelection();
 
     if ( enable )
     {
@@ -2218,11 +2672,13 @@ void wxPropertyGrid::SwitchState( wxPropertyGridPageState* pNewState )
     if ( pNewState == m_pState )
         return;
 
-    wxPGProperty* oldSelection = m_selected;
+    wxArrayPGProperty oldSelection = m_pState->m_selection;
 
-    ClearSelection(false);
+    // Call ClearSelection() instead of DoClearSelection()
+    // so that selection clear events are not sent.
+    ClearSelection();
 
-    m_pState->m_selected = oldSelection;
+    m_pState->m_selection = oldSelection;
 
     bool orig_mode = m_pState->IsInNonCatMode();
     bool new_state_mode = pNewState->IsInNonCatMode();
@@ -2263,9 +2719,9 @@ void wxPropertyGrid::SwitchState( wxPropertyGridPageState* pNewState )
         // Refresh, if not frozen.
         m_pState->PrepareAfterItemsAdded();
 
-        // Reselect
-        if ( m_pState->m_selected )
-            DoSelectProperty( m_pState->m_selected );
+        // Reselect (Use SetSelection() instead of Do-variant so that
+        // events won't be sent).
+        SetSelection(m_pState->m_selection);
 
         RecalculateVirtualSize(0);
         Refresh();
@@ -2289,7 +2745,7 @@ void wxPropertyGrid::DoSetSplitterPosition_( int newxpos, bool refresh, int spli
 
     if ( refresh )
     {
-        if ( m_selected )
+        if ( GetSelection() )
             CorrectEditorWidgetSizeX();
 
         Refresh();
@@ -2360,14 +2816,16 @@ bool wxPropertyGrid::CommitChangesFromEditor( wxUint32 flags )
         return false;
     }
 
+    wxPGProperty* selected = GetSelection();
+
     if ( m_wndEditor &&
          IsEditorsValueModified() &&
          (m_iFlags & wxPG_FL_INITIALIZED) &&
-         m_selected )
+         selected )
     {
         m_inCommitChangesFromEditor = 1;
 
-        wxVariant variant(m_selected->GetValueRef());
+        wxVariant variant(selected->GetValueRef());
         bool valueIsPending = false;
 
         // JACS - necessary to avoid new focus being found spuriously within OnIdle
@@ -2380,10 +2838,13 @@ bool wxPropertyGrid::CommitChangesFromEditor( wxUint32 flags )
         m_chgInfo_changedProperty = NULL;
 
         // If truly modified, schedule value as pending.
-        if ( m_selected->GetEditorClass()->GetValueFromControl( variant, m_selected, GetEditorControl() ) )
+        if ( selected->GetEditorClass()->
+                GetValueFromControl( variant,
+                                     selected,
+                                     GetEditorControl() ) )
         {
             if ( DoEditorValidate() &&
-                 PerformValidation(m_selected, variant) )
+                 PerformValidation(selected, variant) )
             {
                 valueIsPending = true;
             }
@@ -2409,18 +2870,18 @@ bool wxPropertyGrid::CommitChangesFromEditor( wxUint32 flags )
                 m_curFocused = oldFocus;
             }
 
-            res = OnValidationFailure(m_selected, variant);
+            res = OnValidationFailure(selected, variant);
 
             // Now prevent further validation failure messages
             if ( res )
             {
                 EditorsValueWasNotModified();
-                OnValidationFailureReset(m_selected);
+                OnValidationFailureReset(selected);
             }
         }
         else if ( valueIsPending )
         {
-            DoPropertyChanged( m_selected, flags );
+            DoPropertyChanged( selected, flags );
             EditorsValueWasNotModified();
         }
 
@@ -2523,7 +2984,7 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue
 
         if ( evtChangingProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) )
         {
-            if ( changedProperty == m_selected )
+            if ( changedProperty == GetSelection() )
             {
                 wxWindow* editor = GetEditorControl();
                 wxASSERT( editor->IsKindOf(CLASSINFO(wxTextCtrl)) );
@@ -2557,7 +3018,8 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue
     if ( flags & SendEvtChanging )
     {
         // SendEvent returns true if event was vetoed
-        if ( SendEvent( wxEVT_PG_CHANGING, evtChangingProperty, &evtChangingValue, 0 ) )
+        if ( SendEvent( wxEVT_PG_CHANGING, evtChangingProperty,
+                        &evtChangingValue ) )
             return false;
     }
 
@@ -2617,7 +3079,7 @@ bool wxPropertyGrid::OnValidationFailure( wxPGProperty* property,
     //
     // For non-wxTextCtrl editors, we do need to revert the value
     if ( !editor->IsKindOf(CLASSINFO(wxTextCtrl)) &&
-         property == m_selected )
+         property == GetSelection() )
     {
         property->GetEditorClass()->UpdateControl(property, editor);
     }
@@ -2656,7 +3118,7 @@ bool wxPropertyGrid::DoOnValidationFailure( wxPGProperty* property, wxVariant& W
 
         DrawItemAndChildren(property);
 
-        if ( property == m_selected )
+        if ( property == GetSelection() )
         {
             SetInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL);
 
@@ -2695,7 +3157,7 @@ void wxPropertyGrid::DoOnValidationFailureReset( wxPGProperty* property )
 
         ClearInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL);
 
-        if ( property == m_selected && GetEditorControl() )
+        if ( property == GetSelection() && GetEditorControl() )
         {
             // Calling this will recreate the control, thus resetting its colour
             RefreshProperty(property);
@@ -2716,6 +3178,7 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags )
         return true;
 
     wxWindow* editor = GetEditorControl();
+    wxPGProperty* selected = GetSelection();
 
     m_pState->m_anyModified = 1;
 
@@ -2742,7 +3205,7 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags )
     if ( !(p->m_flags & wxPG_PROP_MODIFIED) )
     {
         p->m_flags |= wxPG_PROP_MODIFIED;
-        if ( p == m_selected && (m_windowStyle & wxPG_BOLD_MODIFIED) )
+        if ( p == selected && (m_windowStyle & wxPG_BOLD_MODIFIED) )
         {
             if ( editor )
                 SetCurControlBoldFont();
@@ -2759,7 +3222,7 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags )
     {
         pwc->m_flags |= wxPG_PROP_MODIFIED;
 
-        if ( pwc == m_selected && (m_windowStyle & wxPG_BOLD_MODIFIED) )
+        if ( pwc == selected && (m_windowStyle & wxPG_BOLD_MODIFIED) )
         {
             if ( editor )
                 SetCurControlBoldFont();
@@ -2798,12 +3261,12 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags )
 
         while ( pwc != changedProperty )
         {
-            SendEvent( wxEVT_PG_CHANGED, pwc, NULL, selFlags );
+            SendEvent( wxEVT_PG_CHANGED, pwc, NULL );
             pwc = pwc->GetParent();
         }
     }
 
-    SendEvent( wxEVT_PG_CHANGED, changedProperty, NULL, selFlags );
+    SendEvent( wxEVT_PG_CHANGED, changedProperty, NULL );
 
     m_inDoPropertyChanged = 0;
 
@@ -2867,11 +3330,16 @@ bool wxPropertyGrid::DoEditorValidate()
 
 void wxPropertyGrid::HandleCustomEditorEvent( wxEvent &event )
 {
-    wxPGProperty* selected = m_selected;
+    wxPGProperty* selected = GetSelection();
 
     // Somehow, event is handled after property has been deselected.
     // Possibly, but very rare.
-    if ( !selected )
+    if ( !selected ||
+          selected->HasFlag(wxPG_PROP_BEING_DELETED) ||
+          // Also don't handle editor event if wxEVT_PG_CHANGED or
+          // similar is currently doing something (showing a
+          // message box, for instance).
+          m_processedEvent )
         return;
 
     if ( m_iFlags & wxPG_FL_IN_HANDLECUSTOMEDITOREVENT )
@@ -2939,7 +3407,7 @@ void wxPropertyGrid::HandleCustomEditorEvent( wxEvent &event )
                 if ( DoEditorValidate() )
                 {
                     if ( editor->GetValueFromControl( pendingValue,
-                                                      m_selected,
+                                                      selected,
                                                       wnd ) )
                         valueIsPending = true;
                 }
@@ -2966,7 +3434,7 @@ void wxPropertyGrid::HandleCustomEditorEvent( wxEvent &event )
     }
 
     if ( !validationFailure && valueIsPending )
-        if ( !PerformValidation(m_selected, pendingValue) )
+        if ( !PerformValidation(selected, pendingValue) )
             validationFailure = true;
 
     if ( validationFailure)
@@ -3199,6 +3667,17 @@ void wxPropertyGrid::SetupChildEventHandling( wxWindow* argWnd )
         NULL, this);
 }
 
+void wxPropertyGrid::DestroyEditorWnd( wxWindow* wnd )
+{
+    if ( !wnd )
+        return;
+
+    wnd->Hide();
+
+    // Do not free editors immediately (for sake of processing events)
+    wxPendingDelete.Append(wnd);
+}
+
 void wxPropertyGrid::FreeEditors()
 {
     //
@@ -3226,7 +3705,7 @@ void wxPropertyGrid::FreeEditors()
         wxEvtHandler* handler = m_wndEditor2->PopEventHandler(false);
         m_wndEditor2->Hide();
         wxPendingDelete.Append( handler );
-        wxPendingDelete.Append( m_wndEditor2 );
+        DestroyEditorWnd(m_wndEditor2);
         m_wndEditor2 = NULL;
     }
 
@@ -3235,7 +3714,7 @@ void wxPropertyGrid::FreeEditors()
         wxEvtHandler* handler = m_wndEditor->PopEventHandler(false);
         m_wndEditor->Hide();
         wxPendingDelete.Append( handler );
-        wxPendingDelete.Append( m_wndEditor );
+        DestroyEditorWnd(m_wndEditor);
         m_wndEditor = NULL;
     }
 }
@@ -3260,17 +3739,29 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
     m_inDoSelectProperty = 1;
 
-    wxPGProperty* prev = m_selected;
-
     if ( !m_pState )
     {
         m_inDoSelectProperty = 0;
         return false;
     }
 
+    wxArrayPGProperty prevSelection = m_pState->m_selection;
+    wxPGProperty* prevFirstSel;
+
+    if ( prevSelection.size() > 0 )
+        prevFirstSel = prevSelection[0];
+    else
+        prevFirstSel = NULL;
+
+    if ( prevFirstSel && prevFirstSel->HasFlag(wxPG_PROP_BEING_DELETED) )
+        prevFirstSel = NULL;
+
+    // Always send event, as this is indirect call
+    DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE);
+
 /*
-    if (m_selected)
-        wxPrintf( "Selected %s\n", m_selected->GetClassInfo()->GetClassName() );
+    if ( prevFirstSel )
+        wxPrintf( "Selected %s\n", prevFirstSel->GetClassInfo()->GetClassName() );
     else
         wxPrintf( "None selected\n" );
 
@@ -3285,9 +3776,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
     {
         m_iFlags &= ~(wxPG_FL_ABNORMAL_EDITOR);
         m_editorFocused = 0;
-        m_selected = p;
-        m_selColumn = 1;
-        m_pState->m_selected = p;
+        m_pState->DoSetSelection(p);
 
         // If frozen, always free controls. But don't worry, as Thaw will
         // recall SelectProperty to recreate them.
@@ -3299,7 +3788,9 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
     else
     {
         // Is it the same?
-        if ( m_selected == p && !(flags & wxPG_SEL_FORCE) )
+        if ( prevFirstSel == p &&
+             prevSelection.size() <= 1 &&
+             !(flags & wxPG_SEL_FORCE) )
         {
             // Only set focus if not deselecting
             if ( p )
@@ -3324,13 +3815,12 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
         //
         // First, deactivate previous
-        if ( m_selected )
+        if ( prevFirstSel )
         {
-
-            OnValidationFailureReset(m_selected);
+            OnValidationFailureReset(prevFirstSel);
 
             // Must double-check if this is an selected in case of forceswitch
-            if ( p != prev )
+            if ( p != prevFirstSel )
             {
                 if ( !CommitChangesFromEditor(flags) )
                 {
@@ -3343,13 +3833,6 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
             }
 
             FreeEditors();
-            m_selColumn = -1;
-
-            m_selected = NULL;
-            m_pState->m_selected = NULL;
-
-            // We need to always fully refresh the grid here
-            Refresh(false);
 
             m_iFlags &= ~(wxPG_FL_ABNORMAL_EDITOR);
             EditorsValueWasNotModified();
@@ -3357,6 +3840,14 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
         SetInternalFlag(wxPG_FL_IN_SELECT_PROPERTY);
 
+        m_pState->DoSetSelection(p);
+
+        // Redraw unselected
+        for ( unsigned int i=0; i<prevSelection.size(); i++ )
+        {
+            DrawItem(prevSelection[i]);
+        }
+
         //
         // Then, activate the one given.
         if ( p )
@@ -3365,10 +3856,8 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
             int splitterX = GetSplitterPosition();
             m_editorFocused = 0;
-            m_selected = p;
-            m_pState->m_selected = p;
             m_iFlags |= wxPG_FL_PRIMARY_FILLS_ENTIRE;
-            if ( p != prev )
+            if ( p != prevFirstSel )
                 m_iFlags &= ~(wxPG_FL_VALIDATION_FAILED);
 
             wxASSERT( m_wndEditor == NULL );
@@ -3390,10 +3879,6 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
                 wxRect grect = GetEditorWidgetRect(p, m_selColumn);
                 wxPoint goodPos = grect.GetPosition();
-            #if wxPG_CREATE_CONTROLS_HIDDEN
-                int coord_adjust = m_height - goodPos.y;
-                goodPos.y += coord_adjust;
-            #endif
 
                 const wxPGEditor* editor = p->GetEditorClass();
                 wxCHECK_MSG(editor, false,
@@ -3439,18 +3924,6 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
                     if ( (p->m_flags & wxPG_PROP_MODIFIED) && (m_windowStyle & wxPG_BOLD_MODIFIED) )
                         SetCurControlBoldFont();
 
-                    //
-                    // Fix TextCtrl indentation
-                #if defined(__WXMSW__) && !defined(__WXWINCE__)
-                    wxTextCtrl* tc = NULL;
-                    if ( primaryCtrl->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) )
-                        tc = ((wxOwnerDrawnComboBox*)primaryCtrl)->GetTextCtrl();
-                    else
-                        tc = wxDynamicCast(primaryCtrl, wxTextCtrl);
-                    if ( tc )
-                        ::SendMessage(GetHwndOf(tc), EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0));
-                #endif
-
                     // Store x relative to splitter (we'll need it).
                     m_ctrlXAdjust = m_wndEditor->GetPosition().x - splitterX;
 
@@ -3463,15 +3936,6 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
                     m_wndEditor->SetSizeHints(3, 3);
 
-                #if wxPG_CREATE_CONTROLS_HIDDEN
-                    m_wndEditor->Show(false);
-                    m_wndEditor->Freeze();
-
-                    goodPos = m_wndEditor->GetPosition();
-                    goodPos.y -= coord_adjust;
-                    m_wndEditor->Move( goodPos );
-                #endif
-
                     SetupChildEventHandling(primaryCtrl);
 
                     // Focus and select all (wxTextCtrl, wxComboBox etc)
@@ -3497,19 +3961,6 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
                     m_wndEditor2->SetSizeHints(3,3);
 
-                #if wxPG_CREATE_CONTROLS_HIDDEN
-                    wxRect sec_rect = m_wndEditor2->GetRect();
-                    sec_rect.y -= coord_adjust;
-
-                    // Fine tuning required to fix "oversized"
-                    // button disappearance bug.
-                    if ( sec_rect.y < 0 )
-                    {
-                        sec_rect.height += sec_rect.y;
-                        sec_rect.y = 0;
-                    }
-                    m_wndEditor2->SetSize( sec_rect );
-                #endif
                     m_wndEditor2->Show();
 
                     SetupChildEventHandling(m_wndEditor2);
@@ -3543,13 +3994,11 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
             if ( m_wndEditor )
             {
-            #if wxPG_CREATE_CONTROLS_HIDDEN
-                m_wndEditor->Thaw();
-            #endif
                 m_wndEditor->Show(true);
             }
 
-            DrawItems(p, p);
+            if ( !(flags & wxPG_SEL_NO_REFRESH) )
+                DrawItem(p);
         }
         else
         {
@@ -3608,7 +4057,8 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
     m_inDoSelectProperty = 0;
 
     // call wx event handler (here so that it also occurs on deselection)
-    SendEvent( wxEVT_PG_SELECTED, m_selected, NULL, flags );
+    if ( !(flags & wxPG_SEL_DONT_SEND_EVENT) )
+        SendEvent( wxEVT_PG_SELECTED, p, NULL );
 
     return true;
 }
@@ -3617,14 +4067,16 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
 bool wxPropertyGrid::UnfocusEditor()
 {
-    if ( !m_selected || !m_wndEditor || m_frozen )
+    wxPGProperty* selected = GetSelection();
+
+    if ( !selected || !m_wndEditor || m_frozen )
         return true;
 
     if ( !CommitChangesFromEditor(0) )
         return false;
 
     SetFocusOnCanvas();
-    DrawItem(m_selected);
+    DrawItem(selected);
 
     return true;
 }
@@ -3633,8 +4085,8 @@ bool wxPropertyGrid::UnfocusEditor()
 
 void wxPropertyGrid::RefreshEditor()
 {
-    wxPGProperty* p = m_selected;
-    if ( !p ) 
+    wxPGProperty* p = GetSelection();
+    if ( !p )
         return;
 
     wxWindow* wnd = GetEditorControl();
@@ -3661,11 +4113,15 @@ void wxPropertyGrid::RefreshEditor()
 
 // -----------------------------------------------------------------------
 
-// This method is not inline because it called dozens of times
-// (i.e. two-arg function calls create smaller code size).
-bool wxPropertyGrid::DoClearSelection()
+bool wxPropertyGrid::SelectProperty( wxPGPropArg id, bool focus )
 {
-    return DoSelectProperty(NULL);
+    wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
+
+    int flags = wxPG_SEL_DONT_SEND_EVENT;
+    if ( focus )
+        flags |= wxPG_SEL_FOCUS;
+
+    return DoSelectProperty(p, flags);
 }
 
 // -----------------------------------------------------------------------
@@ -3675,11 +4131,12 @@ bool wxPropertyGrid::DoClearSelection()
 bool wxPropertyGrid::DoCollapse( wxPGProperty* p, bool sendEvents )
 {
     wxPGProperty* pwc = wxStaticCast(p, wxPGProperty);
+    wxPGProperty* selected = GetSelection();
 
     // If active editor was inside collapsed section, then disable it
-    if ( m_selected && m_selected->IsSomeParent(p) )
+    if ( selected && selected->IsSomeParent(p) )
     {
-        ClearSelection(false);
+        DoClearSelection();
     }
 
     // Store dont-center-splitter flag 'cause we need to temporarily set it
@@ -3760,12 +4217,18 @@ bool wxPropertyGrid::DoHideProperty( wxPGProperty* p, bool hide, int flags )
     if ( m_frozen )
         return m_pState->DoHideProperty(p, hide, flags);
 
-    if ( m_selected &&
-         ( m_selected == p || m_selected->IsSomeParent(p) )
-       )
+    wxArrayPGProperty selection = m_pState->m_selection;  // Must use a copy
+    int selRemoveCount = 0;
+    for ( unsigned int i=0; i<selection.size(); i++ )
+    {
+        wxPGProperty* selected = selection[i];
+        if ( selected == p || selected->IsSomeParent(p) )
         {
-            ClearSelection(false);
+            if ( !DoRemoveFromSelection(p, flags) )
+                return false;
+            selRemoveCount += 1;
         }
+    }
 
     m_pState->DoHideProperty(p, hide, flags);
 
@@ -3843,11 +4306,14 @@ void wxPropertyGrid::RecalculateVirtualSize( int forceXPos )
     m_width = width;
     m_height = height;
 
-    m_canvas->SetSize( x, y );
+    // Explicitly pass the position - works around a bug in wxWidgets when the property grid
+    // has a native XP border and a contained window creeps up-and-left when size is set without
+    // the position.
+    m_canvas->SetSize( 0, 0, x, y );
 
     m_pState->CheckColumnWidths();
 
-    if ( m_selected )
+    if ( GetSelection() )
         CorrectEditorWidgetSizeX();
 
     m_iFlags &= ~wxPG_FL_RECALCULATING_VIRTUAL_SIZE;
@@ -3941,22 +4407,36 @@ void wxPropertyGrid::SetFocusOnCanvas()
 
 // selFlags uses same values DoSelectProperty's flags
 // Returns true if event was vetoed.
-bool wxPropertyGrid::SendEvent( int eventType, wxPGProperty* p, wxVariant* pValue, unsigned int WXUNUSED(selFlags) )
+bool wxPropertyGrid::SendEvent( int eventType, wxPGProperty* p,
+                                wxVariant* pValue,
+                                unsigned int selFlags,
+                                unsigned int column )
 {
     // Send property grid event of specific type and with specific property
     wxPropertyGridEvent evt( eventType, m_eventObject->GetId() );
     evt.SetPropertyGrid(this);
     evt.SetEventObject(m_eventObject);
     evt.SetProperty(p);
-    if ( pValue )
+    evt.SetColumn(column);
+    if ( eventType == wxEVT_PG_CHANGING )
     {
+        wxASSERT( pValue );
         evt.SetCanVeto(true);
-        evt.SetupValidationInfo();
         m_validationInfo.m_pValue = pValue;
+        evt.SetupValidationInfo();
+    }
+    else
+    {
+        if ( p )
+            evt.SetPropertyValue(p->GetValue());
+
+        if ( !(selFlags & wxPG_SEL_NOVALIDATE) )
+            evt.SetCanVeto(true);
     }
-    wxEvtHandler* evtHandler = m_eventObject->GetEventHandler();
 
-    evtHandler->ProcessEvent(evt);
+    m_processedEvent = &evt;
+    m_eventObject->HandleWindowEvent(evt);
+    m_processedEvent = NULL;
 
     return evt.WasVetoed();
 }
@@ -4006,7 +4486,9 @@ bool wxPropertyGrid::HandleMouseClick( int x, unsigned int y, wxMouseEvent &even
                      )
                     )
                 {
-                    if ( !DoSelectProperty( p ) )
+                    if ( !AddToSelectionFromInputEvent( p,
+                                                        columnHit,
+                                                        &event ) )
                         return res;
 
                     // On double-click, expand/collapse.
@@ -4026,7 +4508,10 @@ bool wxPropertyGrid::HandleMouseClick( int x, unsigned int y, wxMouseEvent &even
                     m_iFlags |= wxPG_FL_ACTIVATION_BY_CLICK;
                     selFlag = wxPG_SEL_FOCUS;
                 }
-                if ( !DoSelectProperty( p, selFlag ) )
+                if ( !AddToSelectionFromInputEvent( p,
+                                                    columnHit,
+                                                    &event,
+                                                    selFlag ) )
                     return res;
 
                 m_iFlags &= ~(wxPG_FL_ACTIVATION_BY_CLICK);
@@ -4054,9 +4539,13 @@ bool wxPropertyGrid::HandleMouseClick( int x, unsigned int y, wxMouseEvent &even
                     }
                     else if ( m_dragStatus == 0 )
                     {
-                    //
-                    // Begin draggin the splitter
-                    //
+                        //
+                        // Begin draggin the splitter
+                        //
+
+                        // send event
+                        DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE);
+
                         if ( m_wndEditor )
                         {
                             // Changes must be committed here or the
@@ -4117,15 +4606,15 @@ bool wxPropertyGrid::HandleMouseClick( int x, unsigned int y, wxMouseEvent &even
 
 // -----------------------------------------------------------------------
 
-bool wxPropertyGrid::HandleMouseRightClick( int WXUNUSED(x), unsigned int WXUNUSED(y),
-                                            wxMouseEvent& WXUNUSED(event) )
+bool wxPropertyGrid::HandleMouseRightClick( int WXUNUSED(x),
+                                            unsigned int WXUNUSED(y),
+                                            wxMouseEvent& event )
 {
     if ( m_propHover )
     {
         // Select property here as well
         wxPGProperty* p = m_propHover;
-        if ( p != m_selected )
-            DoSelectProperty( p );
+        AddToSelectionFromInputEvent(p, m_colHover, &event);
 
         // Send right click event.
         SendEvent( wxEVT_PG_RIGHT_CLICK, p );
@@ -4137,16 +4626,16 @@ bool wxPropertyGrid::HandleMouseRightClick( int WXUNUSED(x), unsigned int WXUNUS
 
 // -----------------------------------------------------------------------
 
-bool wxPropertyGrid::HandleMouseDoubleClick( int WXUNUSED(x), unsigned int WXUNUSED(y),
-                                             wxMouseEvent& WXUNUSED(event) )
+bool wxPropertyGrid::HandleMouseDoubleClick( int WXUNUSED(x),
+                                             unsigned int WXUNUSED(y),
+                                             wxMouseEvent& event )
 {
     if ( m_propHover )
     {
         // Select property here as well
         wxPGProperty* p = m_propHover;
 
-        if ( p != m_selected )
-            DoSelectProperty( p );
+        AddToSelectionFromInputEvent(p, m_colHover, &event);
 
         // Send double-click event.
         SendEvent( wxEVT_PG_DOUBLE_CLICK, m_propHover );
@@ -4196,6 +4685,8 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, wxMouseEvent &event
     int columnHit = state->HitTestH( x, &splitterHit, &splitterHitOffset );
     int splitterX = x - splitterHitOffset;
 
+    m_colHover = columnHit;
+
     if ( m_dragStatus > 0 )
     {
         if ( x > (m_marginWidth + wxPG_DRAG_MARGIN) &&
@@ -4213,7 +4704,7 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, wxMouseEvent &event
                 state->DoSetSplitterPosition( newSplitterX, m_draggedSplitter, false );
                 state->m_fSplitterX = (float) newSplitterX;
 
-                if ( m_selected )
+                if ( GetSelection() )
                     CorrectEditorWidgetSizeX();
 
                 Update();
@@ -4372,6 +4863,38 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, wxMouseEvent &event
                     CustomSetCursor( wxCURSOR_ARROW );
             }
         }
+
+        //
+        // Multi select by dragging
+        //
+        if ( (GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION) &&
+             event.LeftIsDown() &&
+             m_propHover &&
+             GetSelection() &&
+             columnHit != 1 &&
+             !state->DoIsPropertySelected(m_propHover) )
+        {
+            // Additional requirement is that the hovered property
+            // is adjacent to edges of selection.
+            const wxArrayPGProperty& selection = GetSelectedProperties();
+
+            // Since categories cannot be selected along with 'other'
+            // properties, exclude them from iterator flags.
+            int iterFlags = wxPG_ITERATE_VISIBLE & (~wxPG_PROP_CATEGORY);
+
+            for ( int i=(selection.size()-1); i>=0; i-- )
+            {
+                // TODO: This could be optimized by keeping track of
+                //       which properties are at the edges of selection.
+                wxPGProperty* selProp = selection[i];
+                if ( state->ArePropertiesAdjacent(m_propHover, selProp,
+                                                  iterFlags) )
+                {
+                    DoAddToSelection(m_propHover);
+                    break;
+                }
+            }
+        }
     }
     return true;
 }
@@ -4421,8 +4944,9 @@ bool wxPropertyGrid::HandleMouseUp( int x, unsigned int WXUNUSED(y),
         m_dragStatus = 0;
 
         // Control background needs to be cleared
-        if ( !(m_iFlags & wxPG_FL_PRIMARY_FILLS_ENTIRE) && m_selected )
-            DrawItem( m_selected );
+        wxPGProperty* selected = GetSelection();
+        if ( !(m_iFlags & wxPG_FL_PRIMARY_FILLS_ENTIRE) && selected )
+            DrawItem( selected );
 
         if ( m_wndEditor )
         {
@@ -4646,8 +5170,10 @@ void wxPropertyGrid::OnMouseRightClickChild( wxMouseEvent &event )
     // but that should not matter (right click is about item, not position).
     wxPoint pt = m_wndEditor->GetPosition();
     CalcUnscrolledPosition( event.m_x + pt.x, event.m_y + pt.y, &x, &y );
-    wxASSERT( m_selected );
-    m_propHover = m_selected;
+
+    // FIXME: Used to set m_propHover to selection here. Was it really
+    //        necessary?
+
     bool res = HandleMouseRightClick(x,y,event);
     if ( !res ) event.Skip();
 }
@@ -4726,14 +5252,25 @@ void wxPropertyGrid::AddActionTrigger( int action, int keycode, int modifiers )
 void wxPropertyGrid::ClearActionTriggers( int action )
 {
     wxPGHashMapI2I::iterator it;
+    bool didSomething;
 
-    for ( it = m_actionTriggers.begin(); it != m_actionTriggers.end(); ++it )
+    do
     {
-        if ( it->second == action )
+        didSomething = false;
+
+        for ( it = m_actionTriggers.begin();
+              it != m_actionTriggers.end();
+              it++ )
         {
-            m_actionTriggers.erase(it);
+            if ( it->second == action )
+            {
+                m_actionTriggers.erase(it);
+                didSomething = true;
+                break;
+            }
         }
     }
+    while ( didSomething );
 }
 
 void wxPropertyGrid::HandleKeyEvent( wxKeyEvent &event, bool fromChild )
@@ -4745,6 +5282,7 @@ void wxPropertyGrid::HandleKeyEvent( wxKeyEvent &event, bool fromChild )
     wxCHECK2(!m_frozen, return);
 
     // Travelsal between items, collapsing/expanding, etc.
+    wxPGProperty* selected = GetSelection();
     int keycode = event.GetKeyCode();
     bool editorFocused = IsEditorFocused();
 
@@ -4761,7 +5299,7 @@ void wxPropertyGrid::HandleKeyEvent( wxKeyEvent &event, bool fromChild )
         {
             if ( !editorFocused && m_wndEditor )
             {
-                DoSelectProperty( m_selected, wxPG_SEL_FOCUS );
+                DoSelectProperty( selected, wxPG_SEL_FOCUS );
             }
             else
             {
@@ -4820,12 +5358,13 @@ void wxPropertyGrid::HandleKeyEvent( wxKeyEvent &event, bool fromChild )
             EditorsValueWasNotModified();
 
             // Update the control as well
-            m_selected->GetEditorClass()->SetControlStringValue( m_selected,
-                                                                 GetEditorControl(),
-                                                                 m_selected->GetDisplayedString() );
+            selected->GetEditorClass()->
+                SetControlStringValue( selected,
+                                       GetEditorControl(),
+                                       selected->GetDisplayedString() );
         }
 
-        OnValidationFailureReset(m_selected);
+        OnValidationFailureReset(selected);
 
         UnfocusEditor();
         return;
@@ -4845,13 +5384,13 @@ void wxPropertyGrid::HandleKeyEvent( wxKeyEvent &event, bool fromChild )
 
     bool wasHandled = false;
 
-    if ( m_selected )
+    if ( selected )
     {
         // Show dialog?
         if ( ButtonTriggerKeyTest(action, event) )
             return;
 
-        wxPGProperty* p = m_selected;
+        wxPGProperty* p = selected;
 
         // Travel and expand/collapse
         int selectDir = -2;
@@ -4970,10 +5509,11 @@ void wxPropertyGrid::OnIdle( wxIdleEvent& WXUNUSED(event) )
 
     //
     // Check if top-level parent has changed
-    wxWindow* tlp = ::wxGetTopLevelParent(this);
-    if ( tlp != m_tlp )
+    if ( GetExtraStyle() & wxPG_EX_ENABLE_TLP_TRACKING )
     {
-        OnTLPChanging(tlp);
+        wxWindow* tlp = ::wxGetTopLevelParent(this);
+        if ( tlp != m_tlp )
+            OnTLPChanging(tlp);
     }
 }
 
@@ -5052,8 +5592,9 @@ void wxPropertyGrid::HandleFocusChange( wxWindow* newFocused )
         }
 
         // Redraw selected
-        if ( m_selected && (m_iFlags & wxPG_FL_INITIALIZED) )
-            DrawItem( m_selected );
+        wxPGProperty* selected = GetSelection();
+        if ( selected && (m_iFlags & wxPG_FL_INITIALIZED) )
+            DrawItem( selected );
     }
 }
 
@@ -5309,13 +5850,15 @@ wxDEFINE_EVENT( wxEVT_PG_PAGE_CHANGED, wxPropertyGridEvent );
 wxDEFINE_EVENT( wxEVT_PG_ITEM_EXPANDED, wxPropertyGridEvent );
 wxDEFINE_EVENT( wxEVT_PG_ITEM_COLLAPSED, wxPropertyGridEvent );
 wxDEFINE_EVENT( wxEVT_PG_DOUBLE_CLICK, wxPropertyGridEvent );
-
+wxDEFINE_EVENT( wxEVT_PG_LABEL_EDIT_BEGIN, wxPropertyGridEvent );
+wxDEFINE_EVENT( wxEVT_PG_LABEL_EDIT_ENDING, wxPropertyGridEvent );
 
 // -----------------------------------------------------------------------
 
 void wxPropertyGridEvent::Init()
 {
     m_validationInfo = NULL;
+    m_column = 1;
     m_canVeto = false;
     m_wasVetoed = false;
 }
@@ -5337,6 +5880,7 @@ wxPropertyGridEvent::wxPropertyGridEvent(const wxPropertyGridEvent& event)
     m_eventType = event.GetEventType();
     m_eventObject = event.m_eventObject;
     m_pg = event.m_pg;
+    OnPropertyGridSet();
     m_property = event.m_property;
     m_validationInfo = event.m_validationInfo;
     m_canVeto = event.m_canVeto;
@@ -5345,8 +5889,40 @@ wxPropertyGridEvent::wxPropertyGridEvent(const wxPropertyGridEvent& event)
 
 // -----------------------------------------------------------------------
 
+void wxPropertyGridEvent::OnPropertyGridSet()
+{
+    if ( !m_pg )
+        return;
+
+#if wxUSE_THREADS
+    wxCriticalSectionLocker(wxPGGlobalVars->m_critSect);
+#endif
+    m_pg->m_liveEvents.push_back(this);
+}
+
+// -----------------------------------------------------------------------
+
 wxPropertyGridEvent::~wxPropertyGridEvent()
 {
+    if ( m_pg )
+    {
+    #if wxUSE_THREADS
+        wxCriticalSectionLocker(wxPGGlobalVars->m_critSect);
+    #endif
+
+        // Use iterate from the back since it is more likely that the event
+        // being desroyed is at the end of the array.
+        wxVector<wxPropertyGridEvent*>& liveEvents = m_pg->m_liveEvents;
+
+        for ( int i = liveEvents.size()-1; i >= 0; i-- )
+        {
+            if ( liveEvents[i] == this )
+            {
+                liveEvents.erase(liveEvents.begin() + i);
+                break;
+            }
+        }
+    }
 }
 
 // -----------------------------------------------------------------------