From: Jaakko Salli <jaakko.salli@dnainternet.net> Date: Wed, 7 Jan 2009 18:53:09 +0000 (+0000) Subject: Added wxPropertyGrid::SetSortFunction(); moved Sort() and SortChildren() to wxPropert... X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/433969811ec21a6036347f1be157e08f8f4720ec Added wxPropertyGrid::SetSortFunction(); moved Sort() and SortChildren() to wxPropertyGridInterface; default sorting is now case-insensitive git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@57894 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/propgrid/propgrid.h b/include/wx/propgrid/propgrid.h index 4456641a4a..2146da9de1 100644 --- a/include/wx/propgrid/propgrid.h +++ b/include/wx/propgrid/propgrid.h @@ -1008,6 +1008,45 @@ public: m_iFlags |= wxPG_FL_SPLITTER_PRE_SET; } + /** + Sets the property sorting function. + + @param sortFunction + The sorting function to be used. It should return a value greater + than 0 if position of p1 is after p2. So, for instance, when + comparing property names, you can use following implementation: + + @code + int MyPropertySortFunction(wxPropertyGrid* propGrid, + wxPGProperty* p1, + wxPGProperty* p2) + { + return p1->GetBaseName().compare( p2->GetBaseName() ); + } + @endcode + + @remarks + Default property sort function sorts properties by their labels + (case-insensitively). + + @see GetSortFunction, wxPropertyGridInterface::Sort, + wxPropertyGridInterface::SortChildren + */ + void SetSortFunction( wxPGSortCallback sortFunction ) + { + m_sortFunction = sortFunction; + } + + /** + Returns the property sort function (default is @NULL). + + @see SetSortFunction + */ + wxPGSortCallback GetSortFunction() const + { + return m_sortFunction; + } + /** Set virtual width for this particular page. Width -1 indicates that the virtual width should be disabled. */ void SetVirtualWidth( int width ); @@ -1041,13 +1080,6 @@ public: DoShowPropertyError(p, msg); } - /** Sorts all items at all levels (except sub-properties). */ - void Sort(); - - /** Sorts children of a category. - */ - void SortChildren( wxPGPropArg id ); - ///////////////////////////////////////////////////////////////// // // Following methods do not need to be (currently) documented @@ -1577,6 +1609,9 @@ protected: // Top level parent wxWindow* m_tlp; + // Sort function + wxPGSortCallback m_sortFunction; + // y coordinate of property that mouse hovering int m_propHoverY; // Which column's editor is selected (usually 1)? diff --git a/include/wx/propgrid/propgriddefs.h b/include/wx/propgrid/propgriddefs.h index 02e4fc0f2d..996823d03b 100644 --- a/include/wx/propgrid/propgriddefs.h +++ b/include/wx/propgrid/propgriddefs.h @@ -301,6 +301,29 @@ class wxPGValidationInfo; #define wxPG_DEFAULT_IMAGE_SIZE wxSize(-1, -1) +/** This callback function is used for sorting properties. + + Call wxPropertyGrid::SetSortFunction() to set it. + + Sort function should return a value greater than 0 if position of p1 is + after p2. So, for instance, when comparing property names, you can use + following implementation: + + @code + int MyPropertySortFunction(wxPropertyGrid* propGrid, + wxPGProperty* p1, + wxPGProperty* p2) + { + return p1->GetBaseName().compare( p2->GetBaseName() ); + } + @endcode +*/ +typedef int (*wxPGSortCallback)(wxPropertyGrid* propGrid, + wxPGProperty* p1, + wxPGProperty* p2); + + + typedef wxString wxPGCachedString; /** @} diff --git a/include/wx/propgrid/propgridiface.h b/include/wx/propgrid/propgridiface.h index 8d8c010f41..8c8b39d47d 100644 --- a/include/wx/propgrid/propgridiface.h +++ b/include/wx/propgrid/propgridiface.h @@ -1226,6 +1226,30 @@ public: */ void SetValidationFailureBehavior( int vfbFlags ); + /** + Sorts all properties. + + @see SortChildren, wxPropertyGrid::SetSortFunction + */ + void Sort(); + + /** + Sorts children of a property. + + @param id + Name or pointer to a property. + + @param recursively + If @true, then children are sorted recursively. + + @see Sort, wxPropertyGrid::SetSortFunction + */ + void SortChildren( wxPGPropArg id, bool recursively = false ) + { + wxPG_PROP_ARG_CALL_PROLOG() + m_pState->DoSortChildren(p, recursively); + } + #ifdef SWIG %pythoncode { def MapType(class_,factory): diff --git a/include/wx/propgrid/propgridpagestate.h b/include/wx/propgrid/propgridpagestate.h index 65c45f2d29..4c9172de82 100644 --- a/include/wx/propgrid/propgridpagestate.h +++ b/include/wx/propgrid/propgridpagestate.h @@ -613,8 +613,8 @@ public: /** Set virtual width for this particular page. */ void SetVirtualWidth( int width ); - void SortChildren( wxPGProperty* p ); - void Sort(); + void DoSortChildren( wxPGProperty* p, bool recursively = false ); + void DoSort(); void SetSelection( wxPGProperty* p ) { m_selected = p; } diff --git a/interface/wx/propgrid/propgrid.h b/interface/wx/propgrid/propgrid.h index aa33796266..16c785c43d 100644 --- a/interface/wx/propgrid/propgrid.h +++ b/interface/wx/propgrid/propgrid.h @@ -271,6 +271,27 @@ enum wxPG_KEYBOARD_ACTIONS /** @} */ +/** This callback function is used for sorting properties. + + Call wxPropertyGrid::SetSortFunction() to set it. + + Sort function should return a value greater than 0 if position of p1 is + after p2. So, for instance, when comparing property names, you can use + following implementation: + + @code + int MyPropertySortFunction(wxPropertyGrid* propGrid, + wxPGProperty* p1, + wxPGProperty* p2) + { + return p1->GetBaseName().compare( p2->GetBaseName() ); + } + @endcode +*/ +typedef int (*wxPGSortCallback)(wxPropertyGrid* propGrid, + wxPGProperty* p1, + wxPGProperty* p2); + // ----------------------------------------------------------------------- /** @@ -621,6 +642,13 @@ public: */ wxColour GetSelectionForegroundColour() const; + /** + Returns the property sort function (default is @NULL). + + @see SetSortFunction + */ + wxPGSortCallback GetSortFunction() const; + /** Returns current splitter x position. */ @@ -772,6 +800,33 @@ public: */ void SetSelectionTextColour(const wxColour& col); + + /** + Sets the property sorting function. + + @param sortFunction + The sorting function to be used. It should return a value greater + than 0 if position of p1 is after p2. So, for instance, when + comparing property names, you can use following implementation: + + @code + int MyPropertySortFunction(wxPropertyGrid* propGrid, + wxPGProperty* p1, + wxPGProperty* p2) + { + return p1->GetBaseName().compare( p2->GetBaseName() ); + } + @endcode + + @remarks + Default property sort function sorts properties by their labels + (case-insensitively). + + @see GetSortFunction, wxPropertyGridInterface::Sort, + wxPropertyGridInterface::SortChildren + */ + void SetSortFunction( wxPGSortCallback sortFunction ); + /** Sets x coordinate of the splitter. @@ -801,24 +856,6 @@ public: Shows an brief error message that is related to a property. */ void ShowPropertyError( wxPGPropArg id, const wxString& msg ); - - /** - Sorts all items at all levels (except private children). - - @remarks This functions deselects selected property, if any. Validation - failure option wxPG_VFB_STAY_IN_PROPERTY is not respected, ie. - selection is cleared even if editor had invalid value. - */ - void Sort(); - - /** - Sorts children of a property. - - @remarks This functions deselects selected property, if any. Validation - failure option wxPG_VFB_STAY_IN_PROPERTY is not respected, ie. - selection is cleared even if editor had invalid value. - */ - void SortChildren( wxPGPropArg id ); }; diff --git a/interface/wx/propgrid/propgridiface.h b/interface/wx/propgrid/propgridiface.h index 021954c63d..97725fad6c 100644 --- a/interface/wx/propgrid/propgridiface.h +++ b/interface/wx/propgrid/propgridiface.h @@ -901,6 +901,26 @@ public: */ void SetValidationFailureBehavior( int vfbFlags ); + /** + Sorts all properties. + + @see SortChildren, wxPropertyGrid::SetSortFunction + */ + void Sort(); + + /** + Sorts children of a property. + + @param id + Name or pointer to a property. + + @param recursively + If @true, then children are sorted recursively. + + @see Sort, wxPropertyGrid::SetSortFunction + */ + void SortChildren( wxPGPropArg id, bool recursively = false ); + /** Returns editor pointer of editor with given name; */ diff --git a/samples/propgrid/tests.cpp b/samples/propgrid/tests.cpp index 1c066ca0d9..c4c7de94b3 100644 --- a/samples/propgrid/tests.cpp +++ b/samples/propgrid/tests.cpp @@ -306,6 +306,15 @@ wxArrayPGProperty GetPropertiesInRandomOrder( wxPropertyGridInterface* props, in return arr; } +// Callback for testing property sorting +int MyPropertySortFunction(wxPropertyGrid* WXUNUSED(propGrid), + wxPGProperty* p1, + wxPGProperty* p2) +{ + // Reverse alphabetical order + return p2->GetLabel().CmpNoCase( p1->GetBaseName() ); +} + bool FormMain::RunTests( bool fullTest, bool interactive ) { wxString t; @@ -935,6 +944,51 @@ bool FormMain::RunTests( bool fullTest, bool interactive ) pgman->Update(); } + { + RT_START_TEST(SortFunction) + + wxPGProperty* p; + + // Make sure indexes are as supposed + + p = pgman->GetProperty(wxT("User Name")); + if ( p->GetIndexInParent() != 3 ) + RT_FAILURE(); + + p = pgman->GetProperty(wxT("User Id")); + if ( p->GetIndexInParent() != 2 ) + RT_FAILURE(); + + p = pgman->GetProperty(wxT("User Home")); + if ( p->GetIndexInParent() != 1 ) + RT_FAILURE(); + + p = pgman->GetProperty(wxT("Operating System")); + if ( p->GetIndexInParent() != 0 ) + RT_FAILURE(); + + pgman->GetGrid()->SetSortFunction(MyPropertySortFunction); + + pgman->GetGrid()->SortChildren(wxT("Environment")); + + // Make sure indexes have been reversed + p = pgman->GetProperty(wxT("User Name")); + if ( p->GetIndexInParent() != 0 ) + RT_FAILURE(); + + p = pgman->GetProperty(wxT("User Id")); + if ( p->GetIndexInParent() != 1 ) + RT_FAILURE(); + + p = pgman->GetProperty(wxT("User Home")); + if ( p->GetIndexInParent() != 2 ) + RT_FAILURE(); + + p = pgman->GetProperty(wxT("Operating System")); + if ( p->GetIndexInParent() != 3 ) + RT_FAILURE(); + } + { RT_START_TEST(SetPropertyBackgroundColour) wxCommandEvent evt; diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index a424df5033..4eaae9aedd 100644 --- a/src/propgrid/propgrid.cpp +++ b/src/propgrid/propgrid.cpp @@ -462,6 +462,7 @@ void wxPropertyGrid::Init1() m_eventObject = this; m_curFocused = (wxWindow*) NULL; m_tlwHandler = NULL; + m_sortFunction = NULL; m_inDoPropertyChanged = 0; m_inCommitChangesFromEditor = 0; m_inDoSelectProperty = 0; @@ -2292,24 +2293,6 @@ void wxPropertyGrid::SwitchState( wxPropertyGridPageState* pNewState ) // ----------------------------------------------------------------------- -void wxPropertyGrid::SortChildren( wxPGPropArg id ) -{ - wxPG_PROP_ARG_CALL_PROLOG() - - m_pState->SortChildren( p ); -} - -// ----------------------------------------------------------------------- - -void wxPropertyGrid::Sort() -{ - ClearSelection(false); // This must be before state clear - - m_pState->Sort(); -} - -// ----------------------------------------------------------------------- - // Call to SetSplitterPosition will always disable splitter auto-centering // if parent window is shown. void wxPropertyGrid::DoSetSplitterPosition_( int newxpos, bool refresh, int splitterIndex, bool allPages ) diff --git a/src/propgrid/propgridiface.cpp b/src/propgrid/propgridiface.cpp index 603fc34ec0..033f061213 100644 --- a/src/propgrid/propgridiface.cpp +++ b/src/propgrid/propgridiface.cpp @@ -762,6 +762,25 @@ bool wxPropertyGridInterface::Expand( wxPGPropArg id ) // ----------------------------------------------------------------------- +void wxPropertyGridInterface::Sort() +{ + wxPropertyGrid* pg = GetPropertyGrid(); + + pg->ClearSelection(false); + + unsigned int pageIndex = 0; + + for (;;) + { + wxPropertyGridPageState* page = GetPageState(pageIndex); + if ( !page ) break; + page->DoSort(); + pageIndex++; + } +} + +// ----------------------------------------------------------------------- + void wxPropertyGridInterface::SetPropertyLabel( wxPGPropArg id, const wxString& newproplabel ) { wxPG_PROP_ARG_CALL_PROLOG() diff --git a/src/propgrid/propgridpagestate.cpp b/src/propgrid/propgridpagestate.cpp index 802f05ee77..db836d605d 100644 --- a/src/propgrid/propgridpagestate.cpp +++ b/src/propgrid/propgridpagestate.cpp @@ -602,54 +602,82 @@ bool wxPropertyGridPageState::EnableCategories( bool enable ) #if wxUSE_STL #include <algorithm> -static bool wxPG_SortFunc(wxPGProperty *p1, wxPGProperty *p2) +static bool wxPG_SortFunc_ByFunction(wxPGProperty *p1, wxPGProperty *p2) { - return p1->GetLabel() < p2->GetLabel(); + wxPropertyGrid* pg = p1->GetGrid(); + wxPGSortCallback sortFunction = pg->GetSortFunction(); + return sortFunction(pg, p1, p2) < 0; +} + +static bool wxPG_SortFunc_ByLabel(wxPGProperty *p1, wxPGProperty *p2) +{ + return p1->GetLabel().CmpNoCase( p2->GetLabel() ) < 0; } #else -static int wxPG_SortFunc(wxPGProperty **p1, wxPGProperty **p2) +static int wxPG_SortFunc_ByFunction(wxPGProperty **pp1, wxPGProperty **pp2) +{ + wxPGProperty *p1 = *pp1; + wxPGProperty *p2 = *pp2; + wxPropertyGrid* pg = p1->GetGrid(); + wxPGSortCallback sortFunction = pg->GetSortFunction(); + return sortFunction(pg, p1, p2); +} + +static int wxPG_SortFunc_ByLabel(wxPGProperty **pp1, wxPGProperty **pp2) { - wxPGProperty *pp1 = *p1; - wxPGProperty *pp2 = *p2; - return pp1->GetLabel().compare( pp2->GetLabel() ); + wxPGProperty *p1 = *pp1; + wxPGProperty *p2 = *pp2; + return p1->GetLabel().CmpNoCase( p2->GetLabel() ); } #endif -void wxPropertyGridPageState::SortChildren( wxPGProperty* p ) +void wxPropertyGridPageState::DoSortChildren( wxPGProperty* p, + bool recursively ) { if ( !p ) - p = (wxPGProperty*)m_properties; + p = m_properties; if ( !p->GetChildCount() ) return; - wxPGProperty* pwc = (wxPGProperty*)p; - // Can only sort items with children - if ( pwc->GetChildCount() < 1 ) + if ( p->GetChildCount() < 1 ) return; #if wxUSE_STL - std::sort(pwc->m_children.begin(), pwc->m_children.end(), wxPG_SortFunc); + if ( GetGrid()->GetSortFunction() ) + std::sort(p->m_children.begin(), p->m_children.end(), + wxPG_SortFunc_ByFunction); + else + std::sort(p->m_children.begin(), p->m_children.end(), + wxPG_SortFunc_ByLabel); #else - pwc->m_children.Sort( wxPG_SortFunc ); + if ( GetGrid()->GetSortFunction() ) + p->m_children.Sort( wxPG_SortFunc_ByFunction ); + else + p->m_children.Sort( wxPG_SortFunc_ByLabel ); #endif // Fix indexes - pwc->FixIndicesOfChildren(); + p->FixIndicesOfChildren(); + if ( recursively && !p->HasFlag(wxPG_PROP_AGGREGATE) ) + { + for ( unsigned int i=0; i<p->GetChildCount(); i++ ) + DoSortChildren(p->Item(i)); + } } // ----------------------------------------------------------------------- -void wxPropertyGridPageState::Sort() +void wxPropertyGridPageState::DoSort() { - SortChildren( m_properties ); + DoSortChildren( m_properties, true ); - // Sort categories as well + // Sort categories as well (but we need not do it recursively) if ( !IsInNonCatMode() ) { size_t i; @@ -657,7 +685,7 @@ void wxPropertyGridPageState::Sort() { wxPGProperty* p = m_properties->Item(i); if ( p->IsCategory() ) - SortChildren( p ); + DoSortChildren( p ); } } }