]> git.saurik.com Git - wxWidgets.git/commitdiff
Added multiple selection feature to wxPropertyGrid (enabled by setting wxPG_EX_MULTIP...
authorJaakko Salli <jaakko.salli@dnainternet.net>
Mon, 17 Aug 2009 18:36:00 +0000 (18:36 +0000)
committerJaakko Salli <jaakko.salli@dnainternet.net>
Mon, 17 Aug 2009 18:36:00 +0000 (18:36 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@61681 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

15 files changed:
include/wx/propgrid/manager.h
include/wx/propgrid/property.h
include/wx/propgrid/propgrid.h
include/wx/propgrid/propgridiface.h
include/wx/propgrid/propgridpagestate.h
interface/wx/propgrid/manager.h
interface/wx/propgrid/propgrid.h
interface/wx/propgrid/propgridiface.h
samples/propgrid/propgrid.cpp
samples/propgrid/tests.cpp
src/propgrid/editors.cpp
src/propgrid/manager.cpp
src/propgrid/propgrid.cpp
src/propgrid/propgridiface.cpp
src/propgrid/propgridpagestate.cpp

index 3371c5695e2900769754da18beabe4a69dad20aa..75db8dafdf916b98c6ac8639c2a2323942b13950 100644 (file)
@@ -491,6 +491,12 @@ public:
      */
     bool IsPageModified( size_t index ) const;
 
      */
     bool IsPageModified( size_t index ) const;
 
+    /**
+        Returns true if property is selected. Since selection is page
+        based, this function checks every page in the manager.
+    */
+    virtual bool IsPropertySelected( wxPGPropArg id ) const;
+
     virtual void Refresh( bool eraseBackground = true,
                           const wxRect* rect = (const wxRect*) NULL );
 
     virtual void Refresh( bool eraseBackground = true,
                           const wxRect* rect = (const wxRect*) NULL );
 
index 49205999448d47fb1510d7d12caa8a86dd16a000..a6a55f0bc252984f5fc5755ce7c03823c8c65e40 100644 (file)
@@ -435,7 +435,11 @@ wxPG_PROP_CLASS_SPECIFIC_1          = 0x00080000,
 
 /** Indicates the bit useable by derived properties.
 */
 
 /** Indicates the bit useable by derived properties.
 */
-wxPG_PROP_CLASS_SPECIFIC_2          = 0x00100000
+wxPG_PROP_CLASS_SPECIFIC_2          = 0x00100000,
+
+/** Indicates that the property is being deleted and should be ignored.
+*/
+wxPG_PROP_BEING_DELETED             = 0x00200000
 
 };
 
 
 };
 
index 974fd034cd2c15c20c18ebd1a5e84651808f6236..120c6b308bad5ea54ea7b64ce2060255b7b96d52 100644 (file)
@@ -247,7 +247,20 @@ wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES    = 0x00400000,
 
 /** Hides page selection buttons from toolbar.
 */
 
 /** Hides page selection buttons from toolbar.
 */
-wxPG_EX_HIDE_PAGE_BUTTONS               = 0x01000000
+wxPG_EX_HIDE_PAGE_BUTTONS               = 0x01000000,
+/** Allows multiple properties to be selected by user (by pressing SHIFT
+    when clicking on a property, or by dragging with left mouse button
+    down).
+
+    You can get array of selected properties with
+    wxPropertyGridInterface::GetSelectedProperties(). In multiple selection
+    mode wxPropertyGridInterface::GetSelection() returns
+    property which has editor active (usually the first one
+    selected). Other useful member functions are ClearSelection(),
+    AddToSelection() and RemoveFromSelection().
+*/
+wxPG_EX_MULTIPLE_SELECTION              = 0x02000000
 
 };
 
 
 };
 
@@ -839,12 +852,6 @@ public:
     /** Returns currently selected property. */
     wxPGProperty* GetSelectedProperty() const { return GetSelection(); }
 
     /** Returns currently selected property. */
     wxPGProperty* GetSelectedProperty() const { return GetSelection(); }
 
-    /** Returns currently selected property. */
-    wxPGProperty* GetSelection() const
-    {
-        return m_selected;
-    }
-
     /** Returns current selection background colour. */
     wxColour GetSelectionBackgroundColour() const { return m_colSelBack; }
 
     /** Returns current selection background colour. */
     wxColour GetSelectionBackgroundColour() const { return m_colSelBack; }
 
@@ -953,10 +960,46 @@ public:
                  wxEVT_PG_SELECTED. In wxWidgets 2.9 and later, it no longer
                  does that.
 
                  wxEVT_PG_SELECTED. In wxWidgets 2.9 and later, it no longer
                  does that.
 
-        @see wxPropertyGrid::Unselect
+        @remarks This clears any previous selection.
     */
     bool SelectProperty( wxPGPropArg id, bool focus = false );
 
     */
     bool SelectProperty( wxPGPropArg id, bool focus = false );
 
+    /**
+        Set entire new selection from given list of properties.
+    */
+    void SetSelection( const wxArrayPGProperty& newSelection )
+    {
+        DoSetSelection( newSelection, wxPG_SEL_DONT_SEND_EVENT );
+    }
+
+    /**
+        Adds given property into selection. If wxPG_EX_MULTIPLE_SELECTION
+        extra style is not used, then this has same effect as
+        calling SelectProperty().
+
+        @remarks Multiple selection is not supported for categories. This
+                 means that if you have properties selected, you cannot
+                 add category to selection, and also if you have category
+                 selected, you cannot add other properties to selection.
+                 This member function will fail silently in these cases,
+                 even returning true.
+    */
+    bool AddToSelection( wxPGPropArg id )
+    {
+        wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
+        return DoAddToSelection(p, wxPG_SEL_DONT_SEND_EVENT);
+    }
+
+    /**
+        Removes given property from selection. If property is not selected,
+        an assertion failure will occur.
+    */
+    bool RemoveFromSelection( wxPGPropArg id )
+    {
+        wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
+        return DoRemoveFromSelection(p, wxPG_SEL_DONT_SEND_EVENT);
+    }
+
     /** Sets category caption background colour. */
     void SetCaptionBackgroundColour(const wxColour& col);
 
     /** Sets category caption background colour. */
     void SetCaptionBackgroundColour(const wxColour& col);
 
@@ -1443,7 +1486,6 @@ public:
 
     //
     // Public methods for semi-public use
 
     //
     // Public methods for semi-public use
-    // (not protected for optimization)
     //
     bool DoSelectProperty( wxPGProperty* p, unsigned int flags = 0 );
 
     //
     bool DoSelectProperty( wxPGProperty* p, unsigned int flags = 0 );
 
@@ -1635,12 +1677,6 @@ protected:
     /** When drawing next time, clear this many item slots at the end. */
     int                 m_clearThisMany;
 
     /** When drawing next time, clear this many item slots at the end. */
     int                 m_clearThisMany;
 
-    /** Pointer to selected property. Note that this is duplicated in
-        m_state for better transiency between pages so that the selected
-        item can be retained.
-    */
-    wxPGProperty*       m_selected;
-
     // pointer to property that has mouse hovering
     wxPGProperty*       m_propHover;
 
     // pointer to property that has mouse hovering
     wxPGProperty*       m_propHover;
 
@@ -1767,6 +1803,10 @@ protected:
 
 protected:
 
 
 protected:
 
+    bool AddToSelectionFromInputEvent( wxPGProperty* prop,
+                                       wxMouseEvent* event = NULL,
+                                       int selFlags = 0 );
+
     /**
         Adjust the centering of the bitmap icons (collapse / expand) when the
         caption font changes.
     /**
         Adjust the centering of the bitmap icons (collapse / expand) when the
         caption font changes.
@@ -1786,14 +1826,6 @@ protected:
     */
     void CorrectEditorWidgetPosY();
 
     */
     void CorrectEditorWidgetPosY();
 
-    /** Deselect current selection, if any. Returns true if success
-        (ie. validator did not intercept).
-
-        Unlike ClearSelection(), DoClearSelection() sends the
-        wxEVT_PG_SELECTED event.
-    */
-    bool DoClearSelection();
-
     int DoDrawItems( wxDC& dc,
                      const wxRect* clipRect,
                      bool isBuffered ) const;
     int DoDrawItems( wxDC& dc,
                      const wxRect* clipRect,
                      bool isBuffered ) const;
@@ -1826,6 +1858,15 @@ protected:
 
     bool DoEditorValidate();
 
 
     bool DoEditorValidate();
 
+    void DoSetSelection( const wxArrayPGProperty& newSelection,
+                         int selFlags = 0 );
+
+    bool DoAddToSelection( wxPGProperty* prop,
+                           int selFlags = 0 );
+
+    bool DoRemoveFromSelection( wxPGProperty* prop,
+                                int selFlags = 0 );
+
     wxPGProperty* DoGetItemAtY( int y ) const;
 
     void DoSetSplitterPosition_( int newxpos,
     wxPGProperty* DoGetItemAtY( int y ) const;
 
     void DoSetSplitterPosition_( int newxpos,
index e7bbd29a0a568fa6e0416b09a62baada4dfd3ff2..a110518c0402ff6e103a4d62ffc8718ad18b9fb2 100644 (file)
@@ -591,10 +591,23 @@ public:
     }
 #endif
 
     }
 #endif
 
-    /** Returns currently selected property. */
-    wxPGProperty* GetSelection() const
+    /**
+        Returns currently selected property. NULL if none.
+
+        @remarks When wxPG_EX_MULTIPLE_SELECTION extra style is used, this
+                 member function returns the focused property, that is the
+                 one which can have active editor.
+    */
+    wxPGProperty* GetSelection() const;
+
+    /**
+        Returns list of currently selected properties.
+
+        @remarks wxArrayPGProperty should be compatible with std::vector API.
+    */
+    const wxArrayPGProperty& GetSelectedProperties() const
     {
     {
-        return m_pState->GetSelection();
+        return m_pState->m_selection;
     }
 
 #ifndef SWIG
     }
 
 #ifndef SWIG
@@ -724,10 +737,19 @@ public:
         return ( (p->GetFlags() & wxPG_PROP_MODIFIED) ? true : false );
     }
 
         return ( (p->GetFlags() & wxPG_PROP_MODIFIED) ? true : false );
     }
 
+    /**
+        Returns true if property is selected.
+    */
+    bool IsPropertySelected( wxPGPropArg id ) const
+    {
+        wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
+        return m_pState->DoIsPropertySelected(p);
+    }
+
     /**
         Returns true if property is shown (ie hideproperty with true not
         called for it).
     /**
         Returns true if property is shown (ie hideproperty with true not
         called for it).
-     */
+    */
     bool IsPropertyShown( wxPGPropArg id ) const
     {
         wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
     bool IsPropertyShown( wxPGPropArg id ) const
     {
         wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
@@ -1269,6 +1291,9 @@ public:
 
 protected:
 
 
 protected:
 
+    bool DoClearSelection( bool validation = false,
+                           int selFlags = 0 );
+
     /**
         In derived class, implement to set editable state component with
         given name to given value.
     /**
         In derived class, implement to set editable state component with
         given name to given value.
index c6d8cde900fbfef97ae9448d5448a4aad8e4c5f2..9aa0c11335aa659aafc08c9f652a223d3a819999 100644 (file)
@@ -475,11 +475,6 @@ public:
         return (unsigned int) m_colWidths.size();
     }
 
         return (unsigned int) m_colWidths.size();
     }
 
-    wxPGProperty* GetSelection() const
-    {
-        return m_selected;
-    }
-
     int GetColumnMinWidth( int column ) const;
 
     int GetColumnWidth( unsigned int column ) const
     int GetColumnMinWidth( int column ) const;
 
     int GetColumnWidth( unsigned int column ) const
@@ -500,6 +495,28 @@ public:
         return ((wxPropertyGridPageState*)this)->GetLastItem(flags);
     }
 
         return ((wxPropertyGridPageState*)this)->GetLastItem(flags);
     }
 
+    /**
+        Returns currently selected property.
+    */
+    wxPGProperty* GetSelection() const
+    {
+        if ( m_selection.size() == 0 )
+            return NULL;
+        return m_selection[0];
+    }
+
+    void DoSetSelection( wxPGProperty* prop )
+    {
+        m_selection.clear();
+        if ( prop )
+            m_selection.push_back(prop);
+    }
+
+    bool DoClearSelection()
+    {
+        return DoSelectProperty(NULL);
+    }
+
     wxPropertyCategory* GetPropertyCategory( const wxPGProperty* p ) const;
 
     wxPGProperty* GetPropertyByLabel( const wxString& name,
     wxPropertyCategory* GetPropertyCategory( const wxPGProperty* p ) const;
 
     wxPGProperty* GetPropertyByLabel( const wxString& name,
@@ -590,8 +607,6 @@ public:
 
     bool PrepareAfterItemsAdded();
 
 
     bool PrepareAfterItemsAdded();
 
-    void SetSelection( wxPGProperty* p ) { m_selected = p; }
-
     /** Called after virtual height needs to be recalculated.
     */
     void VirtualHeightChanged()
     /** Called after virtual height needs to be recalculated.
     */
     void VirtualHeightChanged()
@@ -605,14 +620,11 @@ public:
     /** Returns property by its name. */
     wxPGProperty* BaseGetPropertyByName( const wxString& name ) const;
 
     /** Returns property by its name. */
     wxPGProperty* BaseGetPropertyByName( const wxString& name ) const;
 
-    void DoClearSelection()
-    {
-        m_selected = NULL;
-    }
-
     /** Called in, for example, wxPropertyGrid::Clear. */
     void DoClear();
 
     /** Called in, for example, wxPropertyGrid::Clear. */
     void DoClear();
 
+    bool DoIsPropertySelected( wxPGProperty* prop ) const;
+
     bool DoCollapse( wxPGProperty* p );
 
     bool DoExpand( wxPGProperty* p );
     bool DoCollapse( wxPGProperty* p );
 
     bool DoExpand( wxPGProperty* p );
@@ -659,8 +671,8 @@ protected:
     /** Most recently added category. */
     wxPropertyCategory*         m_currentCategory;
 
     /** Most recently added category. */
     wxPropertyCategory*         m_currentCategory;
 
-    /** Pointer to selected property. */
-    wxPGProperty*               m_selected;
+    /** Array of selected property. */
+    wxArrayPGProperty           m_selection;
 
     /** Virtual width. */
     int                         m_width;
 
     /** Virtual width. */
     int                         m_width;
index ff4a39314a5445b58e4e6345208e16bc0113a399..3aa7e9746cee5136167da6b27916a5fdc31b79c9 100644 (file)
@@ -388,6 +388,12 @@ public:
     */
     bool IsPageModified( size_t index ) const;
 
     */
     bool IsPageModified( size_t index ) const;
 
+    /**
+        Returns true if property is selected. Since selection is page
+        based, this function checks every page in the manager.
+    */
+    virtual bool IsPropertySelected( wxPGPropArg id ) const;
+
     /**
         Removes a page.
 
     /**
         Removes a page.
 
index 42366a011c000bd7cfa194c5dda92f1852ede305..0872e5775d1bf4e75cbf260d99c54fc5591a20d0 100644 (file)
@@ -152,7 +152,20 @@ wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES    = 0x00400000,
 /**
     Hides page selection buttons from tool bar.
 */
 /**
     Hides page selection buttons from tool bar.
 */
-wxPG_EX_HIDE_PAGE_BUTTONS               = 0x01000000
+wxPG_EX_HIDE_PAGE_BUTTONS               = 0x01000000,
+
+/** Allows multiple properties to be selected by user (by pressing SHIFT
+    when clicking on a property, or by dragging with left mouse button
+    down).
+
+    You can get array of selected properties with
+    wxPropertyGridInterface::GetSelectedProperties(). In multiple selection
+    mode wxPropertyGridInterface::GetSelection() returns
+    property which has editor active (usually the first one
+    selected). Other useful member functions are ClearSelection(),
+    AddToSelection() and RemoveFromSelection().
+*/
+wxPG_EX_MULTIPLE_SELECTION              = 0x02000000
 
 };
 
 
 };
 
@@ -394,6 +407,20 @@ public:
     */
     void AddActionTrigger( int action, int keycode, int modifiers = 0 );
 
     */
     void AddActionTrigger( int action, int keycode, int modifiers = 0 );
 
+    /**
+        Adds given property into selection. If wxPG_EX_MULTIPLE_SELECTION
+        extra style is not used, then this has same effect as
+        calling SelectProperty().
+
+        @remarks Multiple selection is not supported for categories. This
+                 means that if you have properties selected, you cannot
+                 add category to selection, and also if you have category
+                 selected, you cannot add other properties to selection.
+                 This member function will fail silently in these cases,
+                 even returning true.
+    */
+    bool AddToSelection( wxPGPropArg id );
+
     /**
         This static function enables or disables automatic use of
         wxGetTranslation() for following strings: wxEnumProperty list labels,
     /**
         This static function enables or disables automatic use of
         wxGetTranslation() for following strings: wxEnumProperty list labels,
@@ -708,6 +735,12 @@ public:
     */
     void ResetColours();
 
     */
     void ResetColours();
 
+    /**
+        Removes given property from selection. If property is not selected,
+        an assertion failure will occur.
+    */
+    bool RemoveFromSelection( wxPGPropArg id );
+
     /**
         Selects a property. Editor widget is automatically created, but
         not focused unless focus is true.
     /**
         Selects a property. Editor widget is automatically created, but
         not focused unless focus is true.
@@ -725,6 +758,8 @@ public:
                  wxEVT_PG_SELECTED. In wxWidgets 2.9 and later, it no longer
                  does that.
 
                  wxEVT_PG_SELECTED. In wxWidgets 2.9 and later, it no longer
                  does that.
 
+        @remarks This clears any previous selection.
+
         @see wxPropertyGridInterface::ClearSelection()
     */
     bool SelectProperty( wxPGPropArg id, bool focus = false );
         @see wxPropertyGridInterface::ClearSelection()
     */
     bool SelectProperty( wxPGPropArg id, bool focus = false );
@@ -790,6 +825,11 @@ public:
     */
     void SetMarginColour(const wxColour& col);
 
     */
     void SetMarginColour(const wxColour& col);
 
+    /**
+        Set entire new selection from given list of properties.
+    */
+    void SetSelection( const wxArrayPGProperty& newSelection );
+
     /**
         Sets selection background colour - applies to selected property name
         background.
     /**
         Sets selection background colour - applies to selected property name
         background.
index 512411ec5924b951e866d8bdf795d6a16c12b835..3289ee5aeca1cd9805229f15dc2e3a27d6fbd357 100644 (file)
@@ -418,7 +418,20 @@ public:
     wxVariant GetPropertyValues( const wxString& listname = wxEmptyString,
                                  wxPGProperty* baseparent = NULL, long flags = 0 ) const;
 
     wxVariant GetPropertyValues( const wxString& listname = wxEmptyString,
                                  wxPGProperty* baseparent = NULL, long flags = 0 ) const;
 
-    /** Returns currently selected property. */
+    /**
+        Returns list of currently selected properties.
+
+        @remarks wxArrayPGProperty should be compatible with std::vector API.
+    */
+    const wxArrayPGProperty& GetSelectedProperties() const;
+
+    /**
+        Returns currently selected property. NULL if none.
+
+        @remarks When wxPG_EX_MULTIPLE_SELECTION extra style is used, this
+                 member function returns the focused property, that is the
+                 one which can have active editor.
+    */
     wxPGProperty* GetSelection() const;
 
     /**
     wxPGProperty* GetSelection() const;
 
     /**
@@ -538,6 +551,11 @@ public:
     */
     bool IsPropertyModified( wxPGPropArg id ) const;
 
     */
     bool IsPropertyModified( wxPGPropArg id ) const;
 
+    /**
+        Returns true if property is selected.
+    */
+    virtual bool IsPropertySelected( wxPGPropArg id ) const;
+
     /**
         Returns @true if property is shown (ie. HideProperty() with @true not
         called for it).
     /**
         Returns @true if property is shown (ie. HideProperty() with @true not
         called for it).
index f2b0a821d2cf76f50537e62e020df1df50dc8f8f..41ab8716ab83c1a9e007674eaab4e3ae7637520f 100644 (file)
@@ -2045,7 +2045,8 @@ void FormMain::CreateGrid( int style, int extraStyle )
 
     if ( extraStyle == -1 )
         // default extra style
 
     if ( extraStyle == -1 )
         // default extra style
-        extraStyle = wxPG_EX_MODE_BUTTONS;
+        extraStyle = wxPG_EX_MODE_BUTTONS |
+                     wxPG_EX_MULTIPLE_SELECTION;
                 //| wxPG_EX_AUTO_UNSPECIFIED_VALUES
                 //| wxPG_EX_GREY_LABEL_WHEN_DISABLED
                 //| wxPG_EX_NATIVE_DOUBLE_BUFFERING
                 //| wxPG_EX_AUTO_UNSPECIFIED_VALUES
                 //| wxPG_EX_GREY_LABEL_WHEN_DISABLED
                 //| wxPG_EX_NATIVE_DOUBLE_BUFFERING
@@ -2140,7 +2141,8 @@ FormMain::FormMain(const wxString& title, const wxPoint& pos, const wxSize& size
                 wxPG_TOOLBAR |
                 wxPG_DESCRIPTION,
                 // extra style
                 wxPG_TOOLBAR |
                 wxPG_DESCRIPTION,
                 // extra style
-                wxPG_EX_MODE_BUTTONS
+                wxPG_EX_MODE_BUTTONS |
+                wxPG_EX_MULTIPLE_SELECTION
                 //| wxPG_EX_AUTO_UNSPECIFIED_VALUES
                 //| wxPG_EX_GREY_LABEL_WHEN_DISABLED
                 //| wxPG_EX_NATIVE_DOUBLE_BUFFERING
                 //| wxPG_EX_AUTO_UNSPECIFIED_VALUES
                 //| wxPG_EX_GREY_LABEL_WHEN_DISABLED
                 //| wxPG_EX_NATIVE_DOUBLE_BUFFERING
@@ -2928,6 +2930,8 @@ void FormMain::OnSelectStyle( wxCommandEvent& WXUNUSED(event) )
         ADD_FLAG(wxPG_EX_NATIVE_DOUBLE_BUFFERING)
         ADD_FLAG(wxPG_EX_AUTO_UNSPECIFIED_VALUES)
         ADD_FLAG(wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES)
         ADD_FLAG(wxPG_EX_NATIVE_DOUBLE_BUFFERING)
         ADD_FLAG(wxPG_EX_AUTO_UNSPECIFIED_VALUES)
         ADD_FLAG(wxPG_EX_WRITEONLY_BUILTIN_ATTRIBUTES)
+        ADD_FLAG(wxPG_EX_HIDE_PAGE_BUTTONS)
+        ADD_FLAG(wxPG_EX_MULTIPLE_SELECTION)
         wxMultiChoiceDialog dlg( this, wxT("Select extra window styles to use"),
                                  wxT("wxPropertyGrid Extra Style"), chs );
         dlg.SetSelections(sel);
         wxMultiChoiceDialog dlg( this, wxT("Select extra window styles to use"),
                                  wxT("wxPropertyGrid Extra Style"), chs );
         dlg.SetSelections(sel);
index a6b700dbf60280e4d87ac5f5f1ad12eccfbaee8a..c2b5e5b953bf6891d12390dc5b9421e2610750da 100644 (file)
@@ -249,6 +249,10 @@ protected:
         failures++; \
     }
 
         failures++; \
     }
 
+#define RT_ASSERT(COND) \
+    if (!(COND)) \
+        RT_FAILURE()
+
 #define RT_FAILURE_MSG(MSG) \
     { \
         wxString s1 = wxString::Format(wxT("Test failure in tests.cpp, line %i."),__LINE__-1); \
 #define RT_FAILURE_MSG(MSG) \
     { \
         wxString s1 = wxString::Format(wxT("Test failure in tests.cpp, line %i."),__LINE__-1); \
@@ -714,6 +718,63 @@ bool FormMain::RunTests( bool fullTest, bool interactive )
 #endif
     }
 
 #endif
     }
 
+    {
+        //
+        // Test multiple selection
+        RT_START_TEST(MULTIPLE_SELECTION)
+        if ( !(pgman->GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION) )
+            CreateGrid( -1, wxPG_EX_MULTIPLE_SELECTION);
+        pgman = m_pPropGridManager;
+
+        wxPropertyGrid* pg = pgman->GetGrid();
+
+        wxPGProperty* prop1 = pg->GetProperty(wxT("Label"));
+        wxPGProperty* prop2 = pg->GetProperty(wxT("Cell Text Colour"));
+        wxPGProperty* prop3 = pg->GetProperty(wxT("Height"));
+        wxPGProperty* catProp = pg->GetProperty(wxT("Appearance"));
+
+        RT_ASSERT( prop1 && prop2 && prop3 );
+
+        pg->ClearSelection();
+        pg->AddToSelection(prop1);
+        pg->AddToSelection(prop2);
+        pg->AddToSelection(prop3);
+
+        // Adding category to selection should fail silently
+        pg->AddToSelection(catProp);
+
+        wxArrayPGProperty selectedProperties = pg->GetSelectedProperties();
+
+        RT_ASSERT( selectedProperties.size() == 3 )
+        RT_ASSERT( pg->IsPropertySelected(prop1) )
+        RT_ASSERT( pg->IsPropertySelected(prop2) )
+        RT_ASSERT( pg->IsPropertySelected(prop3) )
+        RT_ASSERT( !pg->IsPropertySelected(catProp) )
+
+        pg->RemoveFromSelection(prop1);
+        wxArrayPGProperty selectedProperties2 = pg->GetSelectedProperties();
+
+        RT_ASSERT( selectedProperties2.size() == 2 )
+        RT_ASSERT( !pg->IsPropertySelected(prop1) )
+        RT_ASSERT( pg->IsPropertySelected(prop2) )
+        RT_ASSERT( pg->IsPropertySelected(prop3) )
+
+        pg->ClearSelection();
+
+        wxArrayPGProperty selectedProperties3 = pg->GetSelectedProperties();
+
+        RT_ASSERT( selectedProperties3.size() == 0 )
+        RT_ASSERT( !pg->IsPropertySelected(prop1) )
+        RT_ASSERT( !pg->IsPropertySelected(prop2) )
+        RT_ASSERT( !pg->IsPropertySelected(prop3) )
+
+        pg->SelectProperty(prop2);
+
+        RT_ASSERT( !pg->IsPropertySelected(prop1) )
+        RT_ASSERT( pg->IsPropertySelected(prop2) )
+        RT_ASSERT( !pg->IsPropertySelected(prop3) )
+    }
+
     {
         RT_START_TEST(Attributes)
 
     {
         RT_START_TEST(Attributes)
 
@@ -985,8 +1046,7 @@ bool FormMain::RunTests( bool fullTest, bool interactive )
         pgman = m_pPropGridManager;
     }
 
         pgman = m_pPropGridManager;
     }
 
-    /*
-    {
+    /*{
         // TODO: This test fails.
         RT_START_TEST(SetSplitterPosition)
 
         // TODO: This test fails.
         RT_START_TEST(SetSplitterPosition)
 
@@ -1023,8 +1083,7 @@ bool FormMain::RunTests( bool fullTest, bool interactive )
         // Recreate the original grid
         CreateGrid( -1, -1 );
         pgman = m_pPropGridManager;
         // Recreate the original grid
         CreateGrid( -1, -1 );
         pgman = m_pPropGridManager;
-    }
-    */
+    }*/
 
     {
         RT_START_TEST(HideProperty)
 
     {
         RT_START_TEST(HideProperty)
@@ -1034,7 +1093,7 @@ bool FormMain::RunTests( bool fullTest, bool interactive )
         srand(0x1234);
 
         wxArrayPGProperty arr1;
         srand(0x1234);
 
         wxArrayPGProperty arr1;
-        
+
         arr1 = GetPropertiesInRandomOrder(page);
 
         if ( !_failed_ )
         arr1 = GetPropertiesInRandomOrder(page);
 
         if ( !_failed_ )
@@ -1178,7 +1237,7 @@ bool FormMain::RunTests( bool fullTest, bool interactive )
 
         wxASSERT(wxPG_EX_INIT_NOCAT == 0x00001000);
 
 
         wxASSERT(wxPG_EX_INIT_NOCAT == 0x00001000);
 
-        for ( i=12; i<24; i++ )
+        for ( i=12; i<26; i++ )
         {
             int flag = 1<<i;
             RT_MSG(wxString::Format(wxT("ExStyle: 0x%X"),flag));
         {
             int flag = 1<<i;
             RT_MSG(wxString::Format(wxT("ExStyle: 0x%X"),flag));
index 2c1518147d6ec04a9030a8ff0ad30a9136766aff..dfc6fdf8172d6c53715be351d1236e31a6a09264 100644 (file)
@@ -608,7 +608,7 @@ void wxPropertyGrid::OnComboItemPaint( const wxPGComboBox* pCb,
     // Sanity check
     wxASSERT( IsKindOf(CLASSINFO(wxPropertyGrid)) );
 
     // Sanity check
     wxASSERT( IsKindOf(CLASSINFO(wxPropertyGrid)) );
 
-    wxPGProperty* p = m_selected;
+    wxPGProperty* p = GetSelection();
     wxString text;
 
     const wxPGChoices& choices = p->GetChoices();
     wxString text;
 
     const wxPGChoices& choices = p->GetChoices();
@@ -1576,9 +1576,9 @@ void wxPropertyGrid::CorrectEditorWidgetPosY()
     if ( m_selColumn == -1 )
         return;
 
     if ( m_selColumn == -1 )
         return;
 
-    if ( m_selected && (m_wndEditor || m_wndEditor2) ) 
+    if ( GetSelection() && (m_wndEditor || m_wndEditor2) ) 
     {
     {
-        wxRect r = GetEditorWidgetRect(m_selected, m_selColumn);
+        wxRect r = GetEditorWidgetRect(GetSelection(), m_selColumn);
 
         if ( m_wndEditor )
         {
 
         if ( m_wndEditor )
         {
@@ -1637,7 +1637,7 @@ wxWindow* wxPropertyGrid::GenerateEditorTextCtrl( const wxPoint& pos,
                                                   int maxLen )
 {
     wxWindowID id = wxPG_SUBID1;
                                                   int maxLen )
 {
     wxWindowID id = wxPG_SUBID1;
-    wxPGProperty* prop = m_selected;
+    wxPGProperty* prop = GetSelection();
     wxASSERT(prop);
 
     int tcFlags = wxTE_PROCESS_ENTER | extraStyle;
     wxASSERT(prop);
 
     int tcFlags = wxTE_PROCESS_ENTER | extraStyle;
@@ -1708,7 +1708,7 @@ wxWindow* wxPropertyGrid::GenerateEditorTextCtrl( const wxPoint& pos,
 wxWindow* wxPropertyGrid::GenerateEditorButton( const wxPoint& pos, const wxSize& sz )
 {
     wxWindowID id = wxPG_SUBID2;
 wxWindow* wxPropertyGrid::GenerateEditorButton( const wxPoint& pos, const wxSize& sz )
 {
     wxWindowID id = wxPG_SUBID2;
-    wxPGProperty* selected = m_selected;
+    wxPGProperty* selected = GetSelection();
     wxASSERT(selected);
 
 #ifdef __WXMAC__
     wxASSERT(selected);
 
 #ifdef __WXMAC__
index 444902899c880c5c32ae1bfeb7e99e8c8bd07ecf..735f18fc75b822aa41c26db962d817d9440e7dcc 100644 (file)
@@ -423,8 +423,9 @@ wxPropertyGridManager::~wxPropertyGridManager()
 {
     END_MOUSE_CAPTURE
 
 {
     END_MOUSE_CAPTURE
 
-    m_pPropGrid->DoSelectProperty(NULL);
-    m_pPropGrid->m_pState = NULL;
+    //m_pPropGrid->ClearSelection();
+    delete m_pPropGrid;
+    m_pPropGrid = NULL;
 
     size_t i;
     for ( i=0; i<m_arrPages.size(); i++ )
 
     size_t i;
     for ( i=0; i<m_arrPages.size(); i++ )
@@ -553,7 +554,7 @@ bool wxPropertyGridManager::DoSelectPage( int index )
     if ( m_selPage == index )
         return true;
 
     if ( m_selPage == index )
         return true;
 
-    if ( m_pPropGrid->m_selected )
+    if ( m_pPropGrid->GetSelection() )
     {
         if ( !m_pPropGrid->ClearSelection() )
             return false;
     {
         if ( !m_pPropGrid->ClearSelection() )
             return false;
@@ -883,6 +884,19 @@ bool wxPropertyGridManager::IsPageModified( size_t index ) const
 
 // -----------------------------------------------------------------------
 
 
 // -----------------------------------------------------------------------
 
+bool wxPropertyGridManager::IsPropertySelected( wxPGPropArg id ) const
+{
+    wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
+    for ( unsigned int i=0; i<GetPageCount(); i++ )
+    {
+        if ( GetPageState(i)->DoIsPropertySelected(p) )
+            return true;
+    }
+    return false;
+}
+
+// -----------------------------------------------------------------------
+
 wxPGProperty* wxPropertyGridManager::GetPageRoot( int index ) const
 {
     wxASSERT( index >= 0 );
 wxPGProperty* wxPropertyGridManager::GetPageRoot( int index ) const
 {
     wxASSERT( index >= 0 );
index b323f7f4cf6158fc8aa875d7ca97832c9153a8ab..5f3801518a72b120dc4c449818a1cd06015c86a4 100644 (file)
@@ -428,7 +428,6 @@ void wxPropertyGrid::Init1()
     m_iFlags = 0;
     m_pState = NULL;
     m_wndEditor = m_wndEditor2 = NULL;
     m_iFlags = 0;
     m_pState = NULL;
     m_wndEditor = m_wndEditor2 = NULL;
-    m_selected = NULL;
     m_selColumn = -1;
     m_propHover = NULL;
     m_eventObject = this;
     m_selColumn = -1;
     m_propHover = NULL;
     m_eventObject = this;
@@ -582,7 +581,7 @@ wxPropertyGrid::~wxPropertyGrid()
 {
     size_t i;
 
 {
     size_t i;
 
-    DoSelectProperty(NULL);
+    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);
 
     // This should do prevent things from going too badly wrong
     m_iFlags &= ~(wxPG_FL_INITIALIZED);
@@ -603,8 +602,6 @@ wxPropertyGrid::~wxPropertyGrid()
         delete m_doubleBuffer;
 #endif
 
         delete m_doubleBuffer;
 #endif
 
-    //m_selected = NULL;
-
     if ( m_iFlags & wxPG_FL_CREATEDSTATE )
         delete m_pState;
 
     if ( m_iFlags & wxPG_FL_CREATEDSTATE )
         delete m_pState;
 
@@ -731,9 +728,149 @@ void wxPropertyGrid::Thaw()
     #endif
 
         // Force property re-selection
     #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, selFlags );
+        }
+
+        // For some reason, if we use RefreshProperty(prop) here,
+        // we may go into infinite drawing loop.
+        Refresh();
+    }
+
+    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
+    {
+        selection.Remove(prop);
+        RefreshProperty(prop);
+        res = true;
+    }
+
+    return res;
+}
+
+// -----------------------------------------------------------------------
+
+bool wxPropertyGrid::AddToSelectionFromInputEvent( wxPGProperty* prop,
+                                                   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 DoSelectProperty(prop, 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 = DoSelectProperty(prop, 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();
 }
 
 // -----------------------------------------------------------------------
 }
 
 // -----------------------------------------------------------------------
@@ -1684,7 +1821,7 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
 
     bool reallyFocused = (m_iFlags & wxPG_FL_FOCUSED) != 0;
 
 
     bool reallyFocused = (m_iFlags & wxPG_FL_FOCUSED) != 0;
 
-    bool isEnabled = IsEnabled();
+    bool isPgEnabled = IsEnabled();
 
     //
     // Prepare some pens and brushes that are often changed to.
 
     //
     // Prepare some pens and brushes that are often changed to.
@@ -1695,6 +1832,12 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
     wxBrush capbgbrush(m_colCapBack,wxSOLID);
     wxPen linepen(m_colLine,1,wxSOLID);
 
     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);
 
     // pen that has same colour as text
     wxPen outlinepen(m_colPropFore,1,wxSOLID);
 
@@ -1708,7 +1851,7 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
         dc.DrawRectangle(-1-xRelMod,firstItemTopY-1,x+2,lastItemBottomY-firstItemTopY+2);
     }
 
         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
     const wxPropertyGridPageState* state = m_pState;
 
 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
@@ -1808,7 +1951,9 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
         wxColour rowFgCol;
         wxColour rowBgCol;
 
         wxColour rowFgCol;
         wxColour rowBgCol;
 
-        if ( p != selected )
+        bool isSelected = state->DoIsPropertySelected(p);
+
+        if ( !isSelected )
         {
             // Disabled may get different colour.
             if ( !p->IsEnabled() )
         {
             // Disabled may get different colour.
             if ( !p->IsEnabled() )
@@ -1820,6 +1965,11 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
         }
         else
         {
         }
         else
         {
+#if wxPG_REFRESH_CONTROLS_AFTER_REPAINT
+            if ( p == firstSelected )
+                wasSelectedPainted = true;
+#endif
+
             renderFlags |= wxPGCellRenderer::Selected;
 
             if ( !p->IsCategory() )
             renderFlags |= wxPGCellRenderer::Selected;
 
             if ( !p->IsCategory() )
@@ -1827,25 +1977,23 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
                 renderFlags |= wxPGCellRenderer::DontUseCellFgCol |
                                wxPGCellRenderer::DontUseCellBgCol;
 
                 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;
                 {
                     rowFgCol = m_colSelFore;
-                    rowBgCol = m_colSelBack;
+                    rowBgCol = selBackCol;
                 }
                 }
-                else if ( isEnabled )
+                else if ( isPgEnabled )
                 {
                     rowFgCol = m_colPropFore;
                 {
                     rowFgCol = m_colPropFore;
-                    rowBgCol = m_colMargin;
+                    if ( p == firstSelected )
+                        rowBgCol = m_colMargin;
+                    else
+                        rowBgCol = selBackCol;
                 }
                 else
                 {
                     rowFgCol = m_colDisPropFore;
                 }
                 else
                 {
                     rowFgCol = m_colDisPropFore;
-                    rowBgCol = m_colSelBack;
+                    rowBgCol = selBackCol;
                 }
             }
         }
                 }
             }
         }
@@ -1934,16 +2082,31 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc,
                     DrawExpanderButton( dc, butRect, p );
 
                 // Background
                     DrawExpanderButton( dc, butRect, p );
 
                 // Background
-                if ( p == selected && m_wndEditor && ci == 1 )
+                if ( isSelected && ci == 1 )
                 {
                 {
-                    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 && m_wndEditor )
+                    {
+                        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;
+                    }
+                    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
                 {
                 }
                 else
                 {
@@ -2038,7 +2201,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.
 
     // 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();
     if ( selected )
     {
         int selectedY = selected->GetY();
@@ -2078,8 +2241,12 @@ void wxPropertyGrid::DrawItems( const wxPGProperty* p1, const wxPGProperty* p2 )
 
 void wxPropertyGrid::RefreshProperty( wxPGProperty* p )
 {
 
 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);
 }
 
     DrawItemAndChildren(p);
 }
@@ -2118,7 +2285,8 @@ void wxPropertyGrid::DrawItemAndChildren( wxPGProperty* p )
         return;
 
     // Update child control.
         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();
         RefreshEditor();
 
     const wxPGProperty* lastDrawn = p->GetLastVisibleSubItem();
@@ -2218,11 +2386,13 @@ void wxPropertyGrid::SwitchState( wxPropertyGridPageState* pNewState )
     if ( pNewState == m_pState )
         return;
 
     if ( pNewState == m_pState )
         return;
 
-    wxPGProperty* oldSelection = m_selected;
+    wxArrayPGProperty oldSelection = m_pState->m_selection;
 
 
-    DoClearSelection();
+    // 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();
 
     bool orig_mode = m_pState->IsInNonCatMode();
     bool new_state_mode = pNewState->IsInNonCatMode();
@@ -2263,9 +2433,9 @@ void wxPropertyGrid::SwitchState( wxPropertyGridPageState* pNewState )
         // Refresh, if not frozen.
         m_pState->PrepareAfterItemsAdded();
 
         // 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();
 
         RecalculateVirtualSize(0);
         Refresh();
@@ -2289,7 +2459,7 @@ void wxPropertyGrid::DoSetSplitterPosition_( int newxpos, bool refresh, int spli
 
     if ( refresh )
     {
 
     if ( refresh )
     {
-        if ( m_selected )
+        if ( GetSelection() )
             CorrectEditorWidgetSizeX();
 
         Refresh();
             CorrectEditorWidgetSizeX();
 
         Refresh();
@@ -2360,14 +2530,16 @@ bool wxPropertyGrid::CommitChangesFromEditor( wxUint32 flags )
         return false;
     }
 
         return false;
     }
 
+    wxPGProperty* selected = GetSelection();
+
     if ( m_wndEditor &&
          IsEditorsValueModified() &&
          (m_iFlags & wxPG_FL_INITIALIZED) &&
     if ( m_wndEditor &&
          IsEditorsValueModified() &&
          (m_iFlags & wxPG_FL_INITIALIZED) &&
-         m_selected )
+         selected )
     {
         m_inCommitChangesFromEditor = 1;
 
     {
         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
         bool valueIsPending = false;
 
         // JACS - necessary to avoid new focus being found spuriously within OnIdle
@@ -2380,10 +2552,13 @@ bool wxPropertyGrid::CommitChangesFromEditor( wxUint32 flags )
         m_chgInfo_changedProperty = NULL;
 
         // If truly modified, schedule value as pending.
         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() &&
         {
             if ( DoEditorValidate() &&
-                 PerformValidation(m_selected, variant) )
+                 PerformValidation(selected, variant) )
             {
                 valueIsPending = true;
             }
             {
                 valueIsPending = true;
             }
@@ -2409,18 +2584,18 @@ bool wxPropertyGrid::CommitChangesFromEditor( wxUint32 flags )
                 m_curFocused = oldFocus;
             }
 
                 m_curFocused = oldFocus;
             }
 
-            res = OnValidationFailure(m_selected, variant);
+            res = OnValidationFailure(selected, variant);
 
             // Now prevent further validation failure messages
             if ( res )
             {
                 EditorsValueWasNotModified();
 
             // Now prevent further validation failure messages
             if ( res )
             {
                 EditorsValueWasNotModified();
-                OnValidationFailureReset(m_selected);
+                OnValidationFailureReset(selected);
             }
         }
         else if ( valueIsPending )
         {
             }
         }
         else if ( valueIsPending )
         {
-            DoPropertyChanged( m_selected, flags );
+            DoPropertyChanged( selected, flags );
             EditorsValueWasNotModified();
         }
 
             EditorsValueWasNotModified();
         }
 
@@ -2523,7 +2698,7 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue
 
         if ( evtChangingProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) )
         {
 
         if ( evtChangingProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) )
         {
-            if ( changedProperty == m_selected )
+            if ( changedProperty == GetSelection() )
             {
                 wxWindow* editor = GetEditorControl();
                 wxASSERT( editor->IsKindOf(CLASSINFO(wxTextCtrl)) );
             {
                 wxWindow* editor = GetEditorControl();
                 wxASSERT( editor->IsKindOf(CLASSINFO(wxTextCtrl)) );
@@ -2617,7 +2792,7 @@ bool wxPropertyGrid::OnValidationFailure( wxPGProperty* property,
     //
     // For non-wxTextCtrl editors, we do need to revert the value
     if ( !editor->IsKindOf(CLASSINFO(wxTextCtrl)) &&
     //
     // 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);
     }
     {
         property->GetEditorClass()->UpdateControl(property, editor);
     }
@@ -2656,7 +2831,7 @@ bool wxPropertyGrid::DoOnValidationFailure( wxPGProperty* property, wxVariant& W
 
         DrawItemAndChildren(property);
 
 
         DrawItemAndChildren(property);
 
-        if ( property == m_selected )
+        if ( property == GetSelection() )
         {
             SetInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL);
 
         {
             SetInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL);
 
@@ -2695,7 +2870,7 @@ void wxPropertyGrid::DoOnValidationFailureReset( wxPGProperty* property )
 
         ClearInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL);
 
 
         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);
         {
             // Calling this will recreate the control, thus resetting its colour
             RefreshProperty(property);
@@ -2716,6 +2891,7 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags )
         return true;
 
     wxWindow* editor = GetEditorControl();
         return true;
 
     wxWindow* editor = GetEditorControl();
+    wxPGProperty* selected = GetSelection();
 
     m_pState->m_anyModified = 1;
 
 
     m_pState->m_anyModified = 1;
 
@@ -2742,7 +2918,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_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();
         {
             if ( editor )
                 SetCurControlBoldFont();
@@ -2759,7 +2935,7 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags )
     {
         pwc->m_flags |= wxPG_PROP_MODIFIED;
 
     {
         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();
         {
             if ( editor )
                 SetCurControlBoldFont();
@@ -2867,11 +3043,11 @@ bool wxPropertyGrid::DoEditorValidate()
 
 void wxPropertyGrid::HandleCustomEditorEvent( wxEvent &event )
 {
 
 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.
 
     // Somehow, event is handled after property has been deselected.
     // Possibly, but very rare.
-    if ( !selected )
+    if ( !selected || selected->HasFlag(wxPG_PROP_BEING_DELETED) )
         return;
 
     if ( m_iFlags & wxPG_FL_IN_HANDLECUSTOMEDITOREVENT )
         return;
 
     if ( m_iFlags & wxPG_FL_IN_HANDLECUSTOMEDITOREVENT )
@@ -2939,7 +3115,7 @@ void wxPropertyGrid::HandleCustomEditorEvent( wxEvent &event )
                 if ( DoEditorValidate() )
                 {
                     if ( editor->GetValueFromControl( pendingValue,
                 if ( DoEditorValidate() )
                 {
                     if ( editor->GetValueFromControl( pendingValue,
-                                                      m_selected,
+                                                      selected,
                                                       wnd ) )
                         valueIsPending = true;
                 }
                                                       wnd ) )
                         valueIsPending = true;
                 }
@@ -2966,7 +3142,7 @@ void wxPropertyGrid::HandleCustomEditorEvent( wxEvent &event )
     }
 
     if ( !validationFailure && valueIsPending )
     }
 
     if ( !validationFailure && valueIsPending )
-        if ( !PerformValidation(m_selected, pendingValue) )
+        if ( !PerformValidation(selected, pendingValue) )
             validationFailure = true;
 
     if ( validationFailure)
             validationFailure = true;
 
     if ( validationFailure)
@@ -3260,17 +3436,26 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
     m_inDoSelectProperty = 1;
 
 
     m_inDoSelectProperty = 1;
 
-    wxPGProperty* prev = m_selected;
-
     if ( !m_pState )
     {
         m_inDoSelectProperty = 0;
         return false;
     }
 
     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;
+
 /*
 /*
-    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" );
 
     else
         wxPrintf( "None selected\n" );
 
@@ -3285,9 +3470,8 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
     {
         m_iFlags &= ~(wxPG_FL_ABNORMAL_EDITOR);
         m_editorFocused = 0;
     {
         m_iFlags &= ~(wxPG_FL_ABNORMAL_EDITOR);
         m_editorFocused = 0;
-        m_selected = p;
         m_selColumn = 1;
         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.
 
         // If frozen, always free controls. But don't worry, as Thaw will
         // recall SelectProperty to recreate them.
@@ -3299,7 +3483,9 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
     else
     {
         // Is it the same?
     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 )
         {
             // Only set focus if not deselecting
             if ( p )
@@ -3324,13 +3510,12 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
         //
         // First, deactivate previous
 
         //
         // 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
 
             // Must double-check if this is an selected in case of forceswitch
-            if ( p != prev )
+            if ( p != prevFirstSel )
             {
                 if ( !CommitChangesFromEditor(flags) )
                 {
             {
                 if ( !CommitChangesFromEditor(flags) )
                 {
@@ -3345,9 +3530,6 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
             FreeEditors();
             m_selColumn = -1;
 
             FreeEditors();
             m_selColumn = -1;
 
-            m_selected = NULL;
-            m_pState->m_selected = NULL;
-
             // We need to always fully refresh the grid here
             Refresh(false);
 
             // We need to always fully refresh the grid here
             Refresh(false);
 
@@ -3357,6 +3539,8 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
         SetInternalFlag(wxPG_FL_IN_SELECT_PROPERTY);
 
 
         SetInternalFlag(wxPG_FL_IN_SELECT_PROPERTY);
 
+        m_pState->DoSetSelection(p);
+
         //
         // Then, activate the one given.
         if ( p )
         //
         // Then, activate the one given.
         if ( p )
@@ -3365,10 +3549,8 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
             int splitterX = GetSplitterPosition();
             m_editorFocused = 0;
 
             int splitterX = GetSplitterPosition();
             m_editorFocused = 0;
-            m_selected = p;
-            m_pState->m_selected = p;
             m_iFlags |= wxPG_FL_PRIMARY_FILLS_ENTIRE;
             m_iFlags |= wxPG_FL_PRIMARY_FILLS_ENTIRE;
-            if ( p != prev )
+            if ( p != prevFirstSel )
                 m_iFlags &= ~(wxPG_FL_VALIDATION_FAILED);
 
             wxASSERT( m_wndEditor == NULL );
                 m_iFlags &= ~(wxPG_FL_VALIDATION_FAILED);
 
             wxASSERT( m_wndEditor == NULL );
@@ -3609,7 +3791,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
     // call wx event handler (here so that it also occurs on deselection)
     if ( !(flags & wxPG_SEL_DONT_SEND_EVENT) )
 
     // call wx event handler (here so that it also occurs on deselection)
     if ( !(flags & wxPG_SEL_DONT_SEND_EVENT) )
-        SendEvent( wxEVT_PG_SELECTED, m_selected, NULL, flags );
+        SendEvent( wxEVT_PG_SELECTED, p, NULL, flags );
 
     return true;
 }
 
     return true;
 }
@@ -3618,14 +3800,16 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 
 bool wxPropertyGrid::UnfocusEditor()
 {
 
 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();
         return true;
 
     if ( !CommitChangesFromEditor(0) )
         return false;
 
     SetFocusOnCanvas();
-    DrawItem(m_selected);
+    DrawItem(selected);
 
     return true;
 }
 
     return true;
 }
@@ -3634,7 +3818,7 @@ bool wxPropertyGrid::UnfocusEditor()
 
 void wxPropertyGrid::RefreshEditor()
 {
 
 void wxPropertyGrid::RefreshEditor()
 {
-    wxPGProperty* p = m_selected;
+    wxPGProperty* p = GetSelection();
     if ( !p ) 
         return;
 
     if ( !p ) 
         return;
 
@@ -3673,14 +3857,6 @@ bool wxPropertyGrid::SelectProperty( wxPGPropArg id, bool focus )
     return DoSelectProperty(p, flags);
 }
 
     return DoSelectProperty(p, flags);
 }
 
-// -----------------------------------------------------------------------
-
-bool wxPropertyGrid::DoClearSelection()
-{
-    // Unlike ClearSelection(), here we send the wxEVT_PG_SELECTED event.
-    return DoSelectProperty(NULL, 0);
-}
-
 // -----------------------------------------------------------------------
 // wxPropertyGrid expand/collapse state
 // -----------------------------------------------------------------------
 // -----------------------------------------------------------------------
 // wxPropertyGrid expand/collapse state
 // -----------------------------------------------------------------------
@@ -3688,9 +3864,10 @@ bool wxPropertyGrid::DoClearSelection()
 bool wxPropertyGrid::DoCollapse( wxPGProperty* p, bool sendEvents )
 {
     wxPGProperty* pwc = wxStaticCast(p, wxPGProperty);
 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 active editor was inside collapsed section, then disable it
-    if ( m_selected && m_selected->IsSomeParent(p) )
+    if ( selected && selected->IsSomeParent(p) )
     {
         DoClearSelection();
     }
     {
         DoClearSelection();
     }
@@ -3773,12 +3950,18 @@ bool wxPropertyGrid::DoHideProperty( wxPGProperty* p, bool hide, int flags )
     if ( m_frozen )
         return m_pState->DoHideProperty(p, hide, 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) )
         {
         {
-            DoClearSelection();
+            if ( !DoRemoveFromSelection(p, flags) )
+                return false;
+            selRemoveCount += 1;
         }
         }
+    }
 
     m_pState->DoHideProperty(p, hide, flags);
 
 
     m_pState->DoHideProperty(p, hide, flags);
 
@@ -3860,7 +4043,7 @@ void wxPropertyGrid::RecalculateVirtualSize( int forceXPos )
 
     m_pState->CheckColumnWidths();
 
 
     m_pState->CheckColumnWidths();
 
-    if ( m_selected )
+    if ( GetSelection() )
         CorrectEditorWidgetSizeX();
 
     m_iFlags &= ~wxPG_FL_RECALCULATING_VIRTUAL_SIZE;
         CorrectEditorWidgetSizeX();
 
     m_iFlags &= ~wxPG_FL_RECALCULATING_VIRTUAL_SIZE;
@@ -4019,7 +4202,7 @@ bool wxPropertyGrid::HandleMouseClick( int x, unsigned int y, wxMouseEvent &even
                      )
                     )
                 {
                      )
                     )
                 {
-                    if ( !DoSelectProperty( p ) )
+                    if ( !AddToSelectionFromInputEvent( p, &event ) )
                         return res;
 
                     // On double-click, expand/collapse.
                         return res;
 
                     // On double-click, expand/collapse.
@@ -4039,7 +4222,7 @@ bool wxPropertyGrid::HandleMouseClick( int x, unsigned int y, wxMouseEvent &even
                     m_iFlags |= wxPG_FL_ACTIVATION_BY_CLICK;
                     selFlag = wxPG_SEL_FOCUS;
                 }
                     m_iFlags |= wxPG_FL_ACTIVATION_BY_CLICK;
                     selFlag = wxPG_SEL_FOCUS;
                 }
-                if ( !DoSelectProperty( p, selFlag ) )
+                if ( !AddToSelectionFromInputEvent( p, &event, selFlag ) )
                     return res;
 
                 m_iFlags &= ~(wxPG_FL_ACTIVATION_BY_CLICK);
                     return res;
 
                 m_iFlags &= ~(wxPG_FL_ACTIVATION_BY_CLICK);
@@ -4130,15 +4313,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 ( m_propHover )
     {
         // Select property here as well
         wxPGProperty* p = m_propHover;
-        if ( p != m_selected )
-            DoSelectProperty( p );
+        AddToSelectionFromInputEvent(p, &event);
 
         // Send right click event.
         SendEvent( wxEVT_PG_RIGHT_CLICK, p );
 
         // Send right click event.
         SendEvent( wxEVT_PG_RIGHT_CLICK, p );
@@ -4150,16 +4333,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 ( m_propHover )
     {
         // Select property here as well
         wxPGProperty* p = m_propHover;
 
-        if ( p != m_selected )
-            DoSelectProperty( p );
+        AddToSelectionFromInputEvent(p, &event);
 
         // Send double-click event.
         SendEvent( wxEVT_PG_DOUBLE_CLICK, m_propHover );
 
         // Send double-click event.
         SendEvent( wxEVT_PG_DOUBLE_CLICK, m_propHover );
@@ -4226,7 +4409,7 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, wxMouseEvent &event
                 state->DoSetSplitterPosition( newSplitterX, m_draggedSplitter, false );
                 state->m_fSplitterX = (float) newSplitterX;
 
                 state->DoSetSplitterPosition( newSplitterX, m_draggedSplitter, false );
                 state->m_fSplitterX = (float) newSplitterX;
 
-                if ( m_selected )
+                if ( GetSelection() )
                     CorrectEditorWidgetSizeX();
 
                 Update();
                     CorrectEditorWidgetSizeX();
 
                 Update();
@@ -4385,6 +4568,18 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, wxMouseEvent &event
                     CustomSetCursor( wxCURSOR_ARROW );
             }
         }
                     CustomSetCursor( wxCURSOR_ARROW );
             }
         }
+
+        //
+        // Multi select by dragging
+        //
+        if ( GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION &&
+             event.LeftIsDown() &&
+             m_propHover &&
+             GetSelection() &&
+             !state->DoIsPropertySelected(m_propHover) )
+        {
+            DoAddToSelection(m_propHover);
+        }
     }
     return true;
 }
     }
     return true;
 }
@@ -4434,8 +4629,9 @@ bool wxPropertyGrid::HandleMouseUp( int x, unsigned int WXUNUSED(y),
         m_dragStatus = 0;
 
         // Control background needs to be cleared
         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 )
         {
 
         if ( m_wndEditor )
         {
@@ -4659,8 +4855,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 );
     // 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();
 }
     bool res = HandleMouseRightClick(x,y,event);
     if ( !res ) event.Skip();
 }
@@ -4758,6 +4956,7 @@ void wxPropertyGrid::HandleKeyEvent( wxKeyEvent &event, bool fromChild )
     wxCHECK2(!m_frozen, return);
 
     // Travelsal between items, collapsing/expanding, etc.
     wxCHECK2(!m_frozen, return);
 
     // Travelsal between items, collapsing/expanding, etc.
+    wxPGProperty* selected = GetSelection();
     int keycode = event.GetKeyCode();
     bool editorFocused = IsEditorFocused();
 
     int keycode = event.GetKeyCode();
     bool editorFocused = IsEditorFocused();
 
@@ -4774,7 +4973,7 @@ void wxPropertyGrid::HandleKeyEvent( wxKeyEvent &event, bool fromChild )
         {
             if ( !editorFocused && m_wndEditor )
             {
         {
             if ( !editorFocused && m_wndEditor )
             {
-                DoSelectProperty( m_selected, wxPG_SEL_FOCUS );
+                DoSelectProperty( selected, wxPG_SEL_FOCUS );
             }
             else
             {
             }
             else
             {
@@ -4833,12 +5032,13 @@ void wxPropertyGrid::HandleKeyEvent( wxKeyEvent &event, bool fromChild )
             EditorsValueWasNotModified();
 
             // Update the control as well
             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;
 
         UnfocusEditor();
         return;
@@ -4858,13 +5058,13 @@ void wxPropertyGrid::HandleKeyEvent( wxKeyEvent &event, bool fromChild )
 
     bool wasHandled = false;
 
 
     bool wasHandled = false;
 
-    if ( m_selected )
+    if ( selected )
     {
         // Show dialog?
         if ( ButtonTriggerKeyTest(action, event) )
             return;
 
     {
         // Show dialog?
         if ( ButtonTriggerKeyTest(action, event) )
             return;
 
-        wxPGProperty* p = m_selected;
+        wxPGProperty* p = selected;
 
         // Travel and expand/collapse
         int selectDir = -2;
 
         // Travel and expand/collapse
         int selectDir = -2;
@@ -5065,8 +5265,9 @@ void wxPropertyGrid::HandleFocusChange( wxWindow* newFocused )
         }
 
         // Redraw selected
         }
 
         // 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 );
     }
 }
 
     }
 }
 
index ff891b9f4fdfcc326dc17dfab69ea1b71671f2b6..a1c037756d95a37bb93e7a7ecb65b0a601ddf95f 100644 (file)
@@ -147,10 +147,6 @@ void wxPropertyGridInterface::DeleteProperty( wxPGPropArg id )
     wxPG_PROP_ARG_CALL_PROLOG()
 
     wxPropertyGridPageState* state = p->GetParentState();
     wxPG_PROP_ARG_CALL_PROLOG()
 
     wxPropertyGridPageState* state = p->GetParentState();
-    wxPropertyGrid* grid = state->GetGrid();
-
-    if ( grid->GetState() == state )
-        grid->DoSelectProperty(NULL, wxPG_SEL_DELETING|wxPG_SEL_NOVALIDATE);
 
     state->DoDelete( p, true );
 
 
     state->DoDelete( p, true );
 
@@ -167,13 +163,6 @@ wxPGProperty* wxPropertyGridInterface::RemoveProperty( wxPGPropArg id )
              wxNullProperty);
 
     wxPropertyGridPageState* state = p->GetParentState();
              wxNullProperty);
 
     wxPropertyGridPageState* state = p->GetParentState();
-    wxPropertyGrid* grid = state->GetGrid();
-
-    if ( grid->GetState() == state )
-    {
-        grid->DoSelectProperty(NULL,
-            wxPG_SEL_DELETING|wxPG_SEL_NOVALIDATE);
-    }
 
     state->DoDelete( p, false );
 
 
     state->DoDelete( p, false );
 
@@ -218,11 +207,25 @@ wxPGProperty* wxPropertyGridInterface::ReplaceProperty( wxPGPropArg id, wxPGProp
 // wxPropertyGridInterface property operations
 // -----------------------------------------------------------------------
 
 // wxPropertyGridInterface property operations
 // -----------------------------------------------------------------------
 
+wxPGProperty* wxPropertyGridInterface::GetSelection() const
+{
+    return m_pState->GetSelection();
+}
+
+// -----------------------------------------------------------------------
+
 bool wxPropertyGridInterface::ClearSelection( bool validation )
 {
 bool wxPropertyGridInterface::ClearSelection( bool validation )
 {
-    int flags = wxPG_SEL_DONT_SEND_EVENT;
+    return DoClearSelection(validation, wxPG_SEL_DONT_SEND_EVENT);
+}
+
+// -----------------------------------------------------------------------
+
+bool wxPropertyGridInterface::DoClearSelection( bool validation,
+                                                int selFlags )
+{
     if ( !validation )
     if ( !validation )
-        flags |= wxPG_SEL_NOVALIDATE;
+        selFlags |= wxPG_SEL_NOVALIDATE;
 
     wxPropertyGridPageState* state = m_pState;
 
 
     wxPropertyGridPageState* state = m_pState;
 
@@ -230,9 +233,9 @@ bool wxPropertyGridInterface::ClearSelection( bool validation )
     {
         wxPropertyGrid* pg = state->GetGrid();
         if ( pg->GetState() == state )
     {
         wxPropertyGrid* pg = state->GetGrid();
         if ( pg->GetState() == state )
-            return pg->DoSelectProperty(NULL, flags);
+            return pg->DoSelectProperty(NULL, selFlags);
         else
         else
-            state->SetSelection(NULL);
+            state->DoSetSelection(NULL);
     }
 
     return true;
     }
 
     return true;
@@ -1026,7 +1029,7 @@ bool wxPropertyGridInterface::RestoreEditableState( const wxString& src, int res
                             else
                             {
                                 if ( values[0].length() )
                             else
                             {
                                 if ( values[0].length() )
-                                    pageState->SetSelection(GetPropertyByName(value));
+                                    pageState->DoSetSelection(GetPropertyByName(value));
                                 else
                                     pageState->DoClearSelection();
                             }
                                 else
                                     pageState->DoClearSelection();
                             }
index 57668950d118aa2808b3e27ceacc50a6e5220e41..966a9210023aca65b7ca91c5a6f0ecf5bd3b9912 100644 (file)
@@ -206,7 +206,6 @@ wxPropertyGridPageState::wxPropertyGridPageState()
     m_properties = &m_regularArray;
     m_abcArray = NULL;
     m_currentCategory = NULL;
     m_properties = &m_regularArray;
     m_abcArray = NULL;
     m_currentCategory = NULL;
-    m_selected = NULL;
     m_width = 0;
     m_virtualHeight = 0;
     m_lastCaptionBottomnest = 1;
     m_width = 0;
     m_virtualHeight = 0;
     m_lastCaptionBottomnest = 1;
@@ -274,7 +273,7 @@ void wxPropertyGridPageState::DoClear()
     }
     else
     {
     }
     else
     {
-        m_selected = NULL;
+        m_selection.clear();
     }
 
     m_regularArray.Empty();
     }
 
     m_regularArray.Empty();
@@ -1150,7 +1149,8 @@ bool wxPropertyGridPageState::DoSetPropertyValueString( wxPGProperty* p, const w
         if ( res )
         {
             p->SetValue(variant);
         if ( res )
         {
             p->SetValue(variant);
-            if ( m_selected==p && this==m_pPropGrid->GetState() )
+            if ( p == m_pPropGrid->GetSelection() &&
+                 this == m_pPropGrid->GetState() )
                 m_pPropGrid->RefreshEditor();
         }
 
                 m_pPropGrid->RefreshEditor();
         }
 
@@ -1166,7 +1166,8 @@ bool wxPropertyGridPageState::DoSetPropertyValue( wxPGProperty* p, wxVariant& va
     if ( p )
     {
         p->SetValue(value);
     if ( p )
     {
         p->SetValue(value);
-        if ( m_selected==p && this==m_pPropGrid->GetState() )
+        if ( p == m_pPropGrid->GetSelection() &&
+             this == m_pPropGrid->GetState() )
             m_pPropGrid->RefreshEditor();
 
         return true;
             m_pPropGrid->RefreshEditor();
 
         return true;
@@ -1192,6 +1193,21 @@ bool wxPropertyGridPageState::DoSetPropertyValueWxObjectPtr( wxPGProperty* p, wx
 // wxPropertyGridPageState property operations
 // -----------------------------------------------------------------------
 
 // wxPropertyGridPageState property operations
 // -----------------------------------------------------------------------
 
+bool wxPropertyGridPageState::DoIsPropertySelected( wxPGProperty* prop ) const
+{
+    const wxArrayPGProperty& selection = m_selection;
+
+    for ( unsigned int i=0; i<selection.size(); i++ )
+    {
+        if ( selection[i] == prop )
+            return true;
+    }
+
+    return false;
+}
+
+// -----------------------------------------------------------------------
+
 bool wxPropertyGridPageState::DoCollapse( wxPGProperty* p )
 {
     wxCHECK_MSG( p, false, wxT("invalid property id") );
 bool wxPropertyGridPageState::DoCollapse( wxPGProperty* p )
 {
     wxCHECK_MSG( p, false, wxT("invalid property id") );
@@ -1231,7 +1247,7 @@ bool wxPropertyGridPageState::DoSelectProperty( wxPGProperty* p, unsigned int fl
     if ( this == m_pPropGrid->GetState() )
         return m_pPropGrid->DoSelectProperty( p, flags );
 
     if ( this == m_pPropGrid->GetState() )
         return m_pPropGrid->DoSelectProperty( p, flags );
 
-    m_selected = p;
+    DoSetSelection(p);
     return true;
 }
 
     return true;
 }
 
@@ -1711,6 +1727,25 @@ void wxPropertyGridPageState::DoDelete( wxPGProperty* item, bool doDelete )
     wxCHECK_RET( !parent->HasFlag(wxPG_PROP_AGGREGATE),
         wxT("wxPropertyGrid: Do not attempt to remove sub-properties.") );
 
     wxCHECK_RET( !parent->HasFlag(wxPG_PROP_AGGREGATE),
         wxT("wxPropertyGrid: Do not attempt to remove sub-properties.") );
 
+    wxASSERT( item->GetParentState() == this );
+
+       wxPropertyGrid* pg = GetGrid();
+
+    if ( DoIsPropertySelected(item) )
+    {
+        if ( pg && pg->GetState() == this )
+        {
+            pg->DoRemoveFromSelection(item,
+                wxPG_SEL_DELETING|wxPG_SEL_NOVALIDATE);
+        }
+        else
+        {
+            m_selection.Remove(item);
+        }
+    }
+
+    item->SetFlag(wxPG_PROP_BEING_DELETED);
+
     // Delete children
     if ( item->GetChildCount() && !item->HasFlag(wxPG_PROP_AGGREGATE) )
     {
     // Delete children
     if ( item->GetChildCount() && !item->HasFlag(wxPG_PROP_AGGREGATE) )
     {
@@ -1780,8 +1815,6 @@ void wxPropertyGridPageState::DoDelete( wxPGProperty* item, bool doDelete )
          (parent->IsCategory() || parent->IsRoot()) )
         m_dictName.erase(item->GetBaseName());
 
          (parent->IsCategory() || parent->IsRoot()) )
         m_dictName.erase(item->GetBaseName());
 
-       wxPropertyGrid* pg = GetGrid();
-
        // We need to clear parent grid's m_propHover, if it matches item
        if ( pg && pg->m_propHover == item )
                pg->m_propHover = NULL;
        // We need to clear parent grid's m_propHover, if it matches item
        if ( pg && pg->m_propHover == item )
                pg->m_propHover = NULL;