]> git.saurik.com Git - wxWidgets.git/blobdiff - src/propgrid/propgridpagestate.cpp
Raise the scrollbars on reparenting (part of patch #9076)
[wxWidgets.git] / src / propgrid / propgridpagestate.cpp
index 59c3a88a39d4bb15afc8698bde6d7c0aa1455fe6..b1dd806885cad145b0baccc847c4fc29afe75e6b 100644 (file)
@@ -107,7 +107,8 @@ void wxPropertyGridIteratorBase::Assign( const wxPropertyGridIteratorBase& it )
 void wxPropertyGridIteratorBase::Prev()
 {
     wxPGProperty* property = m_property;
-    wxASSERT( property );
+    if ( !property )
+        return;
 
     wxPGProperty* parent = property->GetParent();
     wxASSERT( parent );
@@ -152,7 +153,8 @@ void wxPropertyGridIteratorBase::Prev()
 void wxPropertyGridIteratorBase::Next( bool iterateChildren )
 {
     wxPGProperty* property = m_property;
-    wxASSERT( property );
+    if ( !property )
+        return;
 
     if ( property->GetChildCount() &&
          wxPG_ITERATOR_PARENTEXMASK_TEST(property, m_parentExMask) &&
@@ -206,7 +208,6 @@ wxPropertyGridPageState::wxPropertyGridPageState()
     m_properties = &m_regularArray;
     m_abcArray = NULL;
     m_currentCategory = NULL;
-    m_selected = NULL;
     m_width = 0;
     m_virtualHeight = 0;
     m_lastCaptionBottomnest = 1;
@@ -216,6 +217,9 @@ wxPropertyGridPageState::wxPropertyGridPageState()
     m_colWidths.push_back( wxPG_DEFAULT_SPLITTERX );
     m_colWidths.push_back( wxPG_DEFAULT_SPLITTERX );
     m_fSplitterX = wxPG_DEFAULT_SPLITTERX;
+
+    // By default, we only have the 'value' column editable
+    m_editableColumns.push_back(1);
 }
 
 // -----------------------------------------------------------------------
@@ -255,7 +259,7 @@ void wxPropertyGridPageState::InitNonCatMode()
             wxPGProperty* parent = p->GetParent();
             if ( parent->IsCategory() || parent->IsRoot() )
             {
-                m_abcArray->AddChild2(p);
+                m_abcArray->DoAddChild(p);
                 p->m_parent = &m_regularArray;
             }
         }
@@ -268,6 +272,15 @@ void wxPropertyGridPageState::InitNonCatMode()
 
 void wxPropertyGridPageState::DoClear()
 {
+    if ( m_pPropGrid && m_pPropGrid->GetState() == this  )
+    {
+        m_pPropGrid->ClearSelection(false);
+    }
+    else
+    {
+        m_selection.clear();
+    }
+
     m_regularArray.Empty();
     if ( m_abcArray )
         m_abcArray->Empty();
@@ -280,8 +293,6 @@ void wxPropertyGridPageState::DoClear()
 
     m_virtualHeight = 0;
     m_vhCalcPending = 0;
-
-    m_selected = NULL;
 }
 
 // -----------------------------------------------------------------------
@@ -346,9 +357,9 @@ void wxPropertyGridPageState::OnClientWidthChange( int newWidth, int widthChange
             long timeSinceCreation = (::wxGetLocalTimeMillis() - GetGrid()->m_timeCreated).ToLong();
 
             // If too long, don't set splitter
-            if ( timeSinceCreation < 3000 )
+            if ( timeSinceCreation < 250 )
             {
-                if ( m_properties->GetChildCount() || timeSinceCreation > 750 )
+                if ( m_properties->GetChildCount() )
                 {
                     SetSplitterLeft( false );
                 }
@@ -599,23 +610,6 @@ bool wxPropertyGridPageState::EnableCategories( bool enable )
 
 // -----------------------------------------------------------------------
 
-#if wxUSE_STL
-#include <algorithm>
-
-static bool wxPG_SortFunc_ByFunction(wxPGProperty *p1, wxPGProperty *p2)
-{
-    wxPropertyGrid* pg = p1->GetGrid();
-    wxPGSortCallback sortFunction = pg->GetSortFunction();
-    return sortFunction(pg, p1, p2) < 0;
-}
-
-static bool wxPG_SortFunc_ByLabel(wxPGProperty *p1, wxPGProperty *p2)
-{
-    return p1->GetLabel().CmpNoCase( p2->GetLabel() ) < 0;
-}
-
-#else
-
 static int wxPG_SortFunc_ByFunction(wxPGProperty **pp1, wxPGProperty **pp2)
 {
     wxPGProperty *p1 = *pp1;
@@ -632,6 +626,24 @@ static int wxPG_SortFunc_ByLabel(wxPGProperty **pp1, wxPGProperty **pp2)
     return p1->GetLabel().CmpNoCase( p2->GetLabel() );
 }
 
+#if 0
+//
+// For wxVector w/ wxUSE_STL=1, you would use code like this instead:
+//
+
+#include <algorithm>
+
+static bool wxPG_SortFunc_ByFunction(wxPGProperty *p1, wxPGProperty *p2)
+{
+    wxPropertyGrid* pg = p1->GetGrid();
+    wxPGSortCallback sortFunction = pg->GetSortFunction();
+    return sortFunction(pg, p1, p2) < 0;
+}
+
+static bool wxPG_SortFunc_ByLabel(wxPGProperty *p1, wxPGProperty *p2)
+{
+    return p1->GetLabel().CmpNoCase( p2->GetLabel() ) < 0;
+}
 #endif
 
 void wxPropertyGridPageState::DoSortChildren( wxPGProperty* p,
@@ -652,18 +664,21 @@ void wxPropertyGridPageState::DoSortChildren( wxPGProperty* p,
          && !p->IsCategory() && !p->IsRoot() )
         return;
 
-#if wxUSE_STL
+    if ( GetGrid()->GetSortFunction() )
+        p->m_children.Sort( wxPG_SortFunc_ByFunction );
+    else
+        p->m_children.Sort( wxPG_SortFunc_ByLabel );
+
+#if 0
+    //
+    // For wxVector w/ wxUSE_STL=1, you would use code like this instead:
+    //
     if ( GetGrid()->GetSortFunction() )
         std::sort(p->m_children.begin(), p->m_children.end(),
                   wxPG_SortFunc_ByFunction);
     else
         std::sort(p->m_children.begin(), p->m_children.end(),
                   wxPG_SortFunc_ByLabel);
-#else
-    if ( GetGrid()->GetSortFunction() )
-        p->m_children.Sort( wxPG_SortFunc_ByFunction );
-    else
-        p->m_children.Sort( wxPG_SortFunc_ByLabel );
 #endif
 
     // Fix indices
@@ -720,11 +735,13 @@ wxPGProperty* wxPropertyGridPageState::DoGetItemAtY( int y ) const
 
 // -----------------------------------------------------------------------
 
-wxPropertyGridHitTestResult wxPropertyGridPageState::HitTest( const wxPoint&pt ) const
+wxPropertyGridHitTestResult
+wxPropertyGridPageState::HitTest( const wxPoint&pt ) const
 {
     wxPropertyGridHitTestResult result;
-    result.column = HitTestH( pt.x, &result.splitter, &result.splitterHitOffset );
-    result.property = DoGetItemAtY( pt.y );
+    result.m_column = HitTestH( pt.x, &result.m_splitter,
+                                &result.m_splitterHitOffset );
+    result.m_property = DoGetItemAtY( pt.y );
     return result;
 }
 
@@ -753,8 +770,10 @@ int wxPropertyGridPageState::GetColumnFitWidth(wxClientDC& dc,
             if ( col == 0 )
                 w += ( ((int)p->m_depth-1) * pg->m_subgroup_extramargin );
 
-            //
-            // TODO: Add bitmap support.
+            // account for the bitmap
+            if ( col == 1 )
+                w += p->GetImageOffset(pg->GetImageRect(p, -1).GetWidth());
+
 
             w += (wxPG_XBEFORETEXT*2);
 
@@ -863,7 +882,7 @@ void wxPropertyGridPageState::SetSplitterLeft( bool subProps )
 {
     wxPropertyGrid* pg = GetGrid();
     wxClientDC dc(pg);
-    dc.SetFont(pg->m_font);
+    dc.SetFont(pg->GetFont());
 
     int maxW = GetColumnFitWidth(dc, m_properties, 0, subProps);
 
@@ -880,7 +899,7 @@ wxSize wxPropertyGridPageState::DoFitColumns( bool WXUNUSED(allowGridResize) )
 {
     wxPropertyGrid* pg = GetGrid();
     wxClientDC dc(pg);
-    dc.SetFont(pg->m_font);
+    dc.SetFont(pg->GetFont());
 
     int marginWidth = pg->m_marginWidth;
     int accWid = marginWidth;
@@ -929,10 +948,6 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
 
     wxPropertyGrid* pg = GetGrid();
 
-#ifdef __WXDEBUG__
-    const bool debug = false;
-#endif
-
     unsigned int i;
     unsigned int lastColumn = m_colWidths.size() - 1;
     int width = m_width;
@@ -940,14 +955,11 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
 
     //
     // Column to reduce, if needed. Take last one that exceeds minimum width.
-    // Except if auto splitter centering is used, in which case use widest.
     int reduceCol = -1;
-    int highestColWidth = 0;
 
-#ifdef __WXDEBUG__
-    if ( debug )
-        wxLogDebug(wxT("ColumnWidthCheck (virtualWidth: %i, clientWidth: %i)"), width, clientWidth);
-#endif
+    wxLogTrace("propgrid",
+               wxS("ColumnWidthCheck (virtualWidth: %i, clientWidth: %i)"),
+               width, clientWidth);
 
     //
     // Check min sizes
@@ -960,18 +972,9 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
         }
         else
         {
-            if ( pg->HasFlag(wxPG_SPLITTER_AUTO_CENTER) )
-            {
-                if ( m_colWidths[i] >= highestColWidth )
-                {
-                    highestColWidth = m_colWidths[i];
-                    reduceCol = i;
-                }
-            }
-            else
-            {
-                reduceCol = i;
-            }
+            // Always reduce the last column that is larger than minimum size
+            // (looks nicer, even with auto-centering enabled).
+            reduceCol = i;
         }
     }
 
@@ -979,10 +982,9 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
     for ( i=0; i<m_colWidths.size(); i++ )
         colsWidth += m_colWidths[i];
 
-#ifdef __WXDEBUG__
-    if ( debug )
-        wxLogDebug(wxT("  HasVirtualWidth: %i  colsWidth: %i"),(int)pg->HasVirtualWidth(),colsWidth);
-#endif
+    wxLogTrace("propgrid",
+               wxS("  HasVirtualWidth: %i  colsWidth: %i"),
+               (int)pg->HasVirtualWidth(), colsWidth);
 
     // Then mode-based requirement
     if ( !pg->HasVirtualWidth() )
@@ -993,10 +995,9 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
         if ( colsWidth < width )
         {
             // Increase column
-#ifdef __WXDEBUG__
-            if ( debug )
-                wxLogDebug(wxT("  Adjust last column to %i"), m_colWidths[lastColumn] + widthHigher);
-#endif
+            wxLogTrace("propgrid",
+                       wxS("  Adjust last column to %i"),
+                       m_colWidths[lastColumn] + widthHigher);
             m_colWidths[lastColumn] = m_colWidths[lastColumn] + widthHigher;
         }
         else if ( colsWidth > width )
@@ -1004,10 +1005,10 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
             // Reduce column
             if ( reduceCol != -1 )
             {
-            #ifdef __WXDEBUG__
-                if ( debug )
-                    wxLogDebug(wxT("  Reduce column %i (by %i)"), reduceCol, -widthHigher);
-            #endif
+                wxLogTrace("propgrid",
+                           wxT("  Reduce column %i (by %i)"),
+                           reduceCol, -widthHigher);
+
                 // Reduce widest column, and recheck
                 m_colWidths[reduceCol] = m_colWidths[reduceCol] + widthHigher;
                 CheckColumnWidths();
@@ -1029,11 +1030,10 @@ void wxPropertyGridPageState::CheckColumnWidths( int widthChange )
             pg->RecalculateVirtualSize();
     }
 
-#ifdef __WXDEBUG__
-    if ( debug )
-        for ( i=0; i<m_colWidths.size(); i++ )
-            wxLogDebug(wxT("col%i: %i"),i,m_colWidths[i]);
-#endif
+    for ( i=0; i<m_colWidths.size(); i++ )
+    {
+        wxLogTrace("propgrid", wxS("col%i: %i"), i, m_colWidths[i]);
+    }
 
     // Auto center splitter
     if ( !(pg->GetInternalFlags() & wxPG_FL_DONT_CENTER_SPLITTER) &&
@@ -1141,6 +1141,29 @@ int wxPropertyGridPageState::HitTestH( int x, int* pSplitterHit, int* pSplitterH
     return col;
 }
 
+bool wxPropertyGridPageState::ArePropertiesAdjacent( wxPGProperty* prop1,
+                                                     wxPGProperty* prop2,
+                                                     int iterFlags ) const
+{
+    const wxPGProperty* ap1 =
+        wxPropertyGridConstIterator::OneStep(this,
+                                             iterFlags,
+                                             prop1,
+                                             1);
+    if ( ap1 && ap1 == prop2 )
+        return true;
+
+    const wxPGProperty* ap2 =
+        wxPropertyGridConstIterator::OneStep(this,
+                                             iterFlags,
+                                             prop1,
+                                             -1);
+    if ( ap2 && ap2 == prop2 )
+        return true;
+
+    return false;
+}
+
 // -----------------------------------------------------------------------
 // wxPropertyGridPageState property value setting and getting
 // -----------------------------------------------------------------------
@@ -1162,7 +1185,8 @@ bool wxPropertyGridPageState::DoSetPropertyValueString( wxPGProperty* p, const w
         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();
         }
 
@@ -1178,7 +1202,8 @@ bool wxPropertyGridPageState::DoSetPropertyValue( wxPGProperty* p, wxVariant& va
     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;
@@ -1204,6 +1229,59 @@ bool wxPropertyGridPageState::DoSetPropertyValueWxObjectPtr( wxPGProperty* p, wx
 // 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;
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGridPageState::DoRemoveFromSelection( wxPGProperty* prop )
+{
+    for ( unsigned int i=0; i<m_selection.size(); i++ )
+    {
+        if ( m_selection[i] == prop )
+        {
+            wxPropertyGrid* pg = m_pPropGrid;
+            if ( i == 0 && pg->GetState() == this )
+            {
+                // If first item (ie. one with the active editor) was
+                // deselected, then we need to take some extra measures.
+                wxArrayPGProperty sel = m_selection;
+                sel.erase( sel.begin() + i );
+
+                wxPGProperty* newFirst;
+                if ( sel.size() )
+                    newFirst = sel[0];
+                else
+                    newFirst = NULL;
+
+                pg->DoSelectProperty(newFirst,
+                                     wxPG_SEL_DONT_SEND_EVENT);
+
+                m_selection = sel;
+
+                pg->Refresh();
+            }
+            else
+            {
+                m_selection.erase( m_selection.begin() + i );
+            }
+            return;
+        }
+    }
+}
+
+// -----------------------------------------------------------------------
+
 bool wxPropertyGridPageState::DoCollapse( wxPGProperty* p )
 {
     wxCHECK_MSG( p, false, wxT("invalid property id") );
@@ -1243,7 +1321,7 @@ bool wxPropertyGridPageState::DoSelectProperty( wxPGProperty* p, unsigned int fl
     if ( this == m_pPropGrid->GetState() )
         return m_pPropGrid->DoSelectProperty( p, flags );
 
-    m_selected = p;
+    DoSetSelection(p);
     return true;
 }
 
@@ -1428,13 +1506,12 @@ void wxPropertyGridPageState::DoSetPropertyValues( const wxVariantList& list, wx
                     }
                     else
                     {
-                #ifdef __WXDEBUG__
-                        if ( wxStrcmp(current->GetType(), p->GetValue().GetType()) != 0)
-                        {
-                            wxLogDebug(wxT("wxPropertyGridPageState::DoSetPropertyValues Warning: Setting value of property \"%s\" from variant"),
-                                p->GetName().c_str());
-                        }
-                #endif
+                        wxASSERT_LEVEL_2_MSG(
+                            wxStrcmp(current->GetType(), p->GetValue().GetType()) == 0,
+                            wxString::Format(
+                                wxS("setting value of property \"%s\" from variant"),
+                                p->GetName().c_str())
+                        );
 
                         p->SetValue(*current);
                     }
@@ -1570,16 +1647,18 @@ bool wxPropertyGridPageState::PrepareToAddItem( wxPGProperty* property,
         }
     }
 
-#ifdef __WXDEBUG__
+#if wxDEBUG_LEVEL
     // Warn for identical names in debug mode.
     if ( BaseGetPropertyByName(property->GetName()) &&
          (!scheduledParent || scheduledParent->IsCategory()) )
     {
-        wxLogError(wxT("wxPropertyGrid: Warning - item with name \"%s\" already exists."),
-            property->GetName().c_str());
+        wxFAIL_MSG(wxString::Format(
+            "wxPropertyGrid item with name \"%s\" already exists",
+            property->GetName()));
+
         wxPGGlobalVars->m_warnings++;
     }
-#endif
+#endif // wxDEBUG_LEVEL
 
     // Make sure nothing is selected.
     if ( propGrid )
@@ -1659,11 +1738,11 @@ wxPGProperty* wxPropertyGridPageState::DoInsert( wxPGProperty* parent, int index
         if ( m_abcArray && !property->IsCategory() &&
              (parentIsCategory || parentIsRoot) )
         {
-            m_abcArray->AddChild2( property, -1, false );
+            m_abcArray->DoAddChild( property, -1, false );
         }
 
         // Add to current mode.
-        parent->AddChild2( property, index, true );
+        parent->DoAddChild( property, index, true );
     }
     else
     {
@@ -1671,14 +1750,14 @@ wxPGProperty* wxPropertyGridPageState::DoInsert( wxPGProperty* parent, int index
 
         if ( parentIsCategory )
             // Parent is category.
-            parent->AddChild2( property, index, false );
+            parent->DoAddChild( property, index, false );
         else if ( parentIsRoot )
             // Parent is root.
-            m_regularArray.AddChild2( property, -1, false );
+            m_regularArray.DoAddChild( property, -1, false );
 
         // Add to current mode
         if ( !property->IsCategory() )
-            m_abcArray->AddChild2( property, index, true );
+            m_abcArray->DoAddChild( property, index, true );
     }
 
     // category stuff
@@ -1722,6 +1801,25 @@ void wxPropertyGridPageState::DoDelete( wxPGProperty* item, bool doDelete )
     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
+        {
+            DoRemoveFromSelection(item);
+        }
+    }
+
+    item->SetFlag(wxPG_PROP_BEING_DELETED);
+
     // Delete children
     if ( item->GetChildCount() && !item->HasFlag(wxPG_PROP_AGGREGATE) )
     {
@@ -1787,10 +1885,14 @@ void wxPropertyGridPageState::DoDelete( wxPGProperty* item, bool doDelete )
         }
     }
 
-    if ( item->GetBaseName().length() && 
+    if ( item->GetBaseName().length() &&
          (parent->IsCategory() || parent->IsRoot()) )
         m_dictName.erase(item->GetBaseName());
 
+    // We need to clear parent grid's m_propHover, if it matches item
+    if ( pg && pg->m_propHover == item )
+        pg->m_propHover = NULL;
+
     // We can actually delete it now
     if ( doDelete )
         delete item;