]> git.saurik.com Git - wxWidgets.git/blobdiff - src/propgrid/propgrid.cpp
Add samples files missing from distribution.
[wxWidgets.git] / src / propgrid / propgrid.cpp
index 8c6e80d786e36263cfd2768670935c73d520bfaa..b323f7f4cf6158fc8aa875d7ca97832c9153a8ab 100644 (file)
@@ -63,8 +63,6 @@
 
 #include "wx/timer.h"
 #include "wx/dcbuffer.h"
-#include "wx/clipbrd.h"
-#include "wx/dataobj.h"
 
 #ifdef __WXMSW__
     #include "wx/msw/private.h"
@@ -154,6 +152,15 @@ public:
 IMPLEMENT_DYNAMIC_CLASS(wxPGGlobalVarsClassManager, wxModule)
 
 
+// When wxPG is loaded dynamically after the application is already running
+// then the built-in module system won't pick this one up.  Add it manually.
+void wxPGInitResourceModule()
+{
+    wxModule* module = new wxPGGlobalVarsClassManager;
+    module->Init();
+    wxModule::RegisterModule(module);
+}
+
 wxPGGlobalVarsClass* wxPGGlobalVars = NULL;
 
 
@@ -188,6 +195,7 @@ wxPGGlobalVarsClass::wxPGGlobalVarsClass()
     m_strlong = wxS("long");
     m_strbool = wxS("bool");
     m_strlist = wxS("list");
+    m_strDefaultValue = wxS("DefaultValue");
     m_strMin = wxS("Min");
     m_strMax = wxS("Max");
     m_strUnits = wxS("Units");
@@ -229,46 +237,6 @@ void wxPropertyGridInitGlobalsIfNeeded()
 {
 }
 
-// -----------------------------------------------------------------------
-// wxPGTLWHandler
-//   Intercepts Close-events sent to wxPropertyGrid's top-level parent,
-//   and tries to commit property value.
-// -----------------------------------------------------------------------
-
-class wxPGTLWHandler : public wxEvtHandler
-{
-public:
-
-    wxPGTLWHandler( wxPropertyGrid* pg )
-        : wxEvtHandler()
-    {
-        m_pg = pg;
-    }
-
-protected:
-
-    void OnClose( wxCloseEvent& event )
-    {
-        // ClearSelection forces value validation/commit.
-        if ( event.CanVeto() && !m_pg->ClearSelection() )
-        {
-            event.Veto();
-            return;
-        }
-
-        event.Skip();
-    }
-
-private:
-    wxPropertyGrid*     m_pg;
-
-    DECLARE_EVENT_TABLE()
-};
-
-BEGIN_EVENT_TABLE(wxPGTLWHandler, wxEvtHandler)
-    EVT_CLOSE(wxPGTLWHandler::OnClose)
-END_EVENT_TABLE()
-
 // -----------------------------------------------------------------------
 // wxPGCanvas
 // -----------------------------------------------------------------------
@@ -465,7 +433,6 @@ void wxPropertyGrid::Init1()
     m_propHover = NULL;
     m_eventObject = this;
     m_curFocused = NULL;
-    m_tlwHandler = NULL;
     m_sortFunction = NULL;
     m_inDoPropertyChanged = 0;
     m_inCommitChangesFromEditor = 0;
@@ -582,11 +549,11 @@ void wxPropertyGrid::Init2()
     // This helps with flicker
     SetBackgroundStyle( wxBG_STYLE_CUSTOM );
 
-    // Hook the TLW
-    wxPGTLWHandler* handler = new wxPGTLWHandler(this);
-    m_tlp = ::wxGetTopLevelParent(this);
-    m_tlwHandler = handler;
-    m_tlp->PushEventHandler(handler);
+    // Hook the top-level parent
+    m_tlp = NULL;
+    m_tlpClosed = NULL;
+    m_tlpClosedTime = 0;
+    OnTLPChanging(::wxGetTopLevelParent(this));
 
     // set virtual size to this window size
     wxSize wndsize = GetSize();
@@ -623,15 +590,13 @@ wxPropertyGrid::~wxPropertyGrid()
     if ( m_iFlags & wxPG_FL_MOUSE_CAPTURED )
         m_canvas->ReleaseMouse();
 
-    wxPGTLWHandler* handler = (wxPGTLWHandler*) m_tlwHandler;
-    m_tlp->RemoveEventHandler(handler);
-    delete handler;
+    // Call with NULL to disconnect event handling
+    OnTLPChanging(NULL);
 
-#ifdef __WXDEBUG__
-    if ( IsEditorsValueModified() )
-        ::wxMessageBox(wxS("Most recent change in property editor was lost!!!\n\n(if you don't want this to happen, close your frames and dialogs using Close(false).)"),
-                       wxS("wxPropertyGrid Debug Warning") );
-#endif
+    wxASSERT_MSG( !IsEditorsValueModified(),
+                  wxS("Most recent change in property editor was lost!!! ")
+                  wxS("(if you don't want this to happen, close your frames ")
+                  wxS("and dialogs using Close(false).)") );
 
 #if wxPG_DOUBLE_BUFFER
     if ( m_doubleBuffer )
@@ -826,15 +791,89 @@ void wxPropertyGrid::SetExtraStyle( long exStyle )
 // returns the best acceptable minimal size
 wxSize wxPropertyGrid::DoGetBestSize() const
 {
-    int hei = 15;
-    if ( m_lineHeight > hei )
-        hei = m_lineHeight;
-    wxSize sz = wxSize( 60, hei+40 );
+    int lineHeight = wxMax(15, m_lineHeight);
+
+    // don't make the grid too tall (limit height to 10 items) but don't
+    // make it too small neither
+    int numLines = wxMin
+                   (
+                    wxMax(m_pState->m_properties->GetChildCount(), 3),
+                    10
+                   );
 
+    const wxSize sz = wxSize(60, lineHeight*numLines + 40);
     CacheBestSize(sz);
     return sz;
 }
 
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::OnTLPChanging( wxWindow* newTLP )
+{
+    wxLongLong currentTime = ::wxGetLocalTimeMillis();
+
+    //
+    // Parent changed so let's redetermine and re-hook the
+    // correct top-level window.
+    if ( m_tlp )
+    {
+        m_tlp->Disconnect( wxEVT_CLOSE_WINDOW,
+                           wxCloseEventHandler(wxPropertyGrid::OnTLPClose),
+                           NULL, this );
+        m_tlpClosed = m_tlp;
+        m_tlpClosedTime = currentTime;
+    }
+
+    if ( newTLP )
+    {
+        // Only accept new tlp if same one was not just dismissed.
+        if ( newTLP != m_tlpClosed ||
+             m_tlpClosedTime+250 < currentTime )
+        {
+            newTLP->Connect( wxEVT_CLOSE_WINDOW,
+                             wxCloseEventHandler(wxPropertyGrid::OnTLPClose),
+                             NULL, this );
+            m_tlpClosed = NULL;
+        }
+        else
+        {
+            newTLP = NULL;
+        }
+    }
+
+    m_tlp = newTLP;
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::OnTLPClose( wxCloseEvent& event )
+{
+    // ClearSelection forces value validation/commit.
+    if ( event.CanVeto() && !DoClearSelection() )
+    {
+        event.Veto();
+        return;
+    }
+
+    // Ok, it can close, set tlp pointer to NULL. Some other event
+    // handler can of course veto the close, but our OnIdle() should
+    // then be able to regain the tlp pointer.
+    OnTLPChanging(NULL);
+
+    event.Skip();
+}
+
+// -----------------------------------------------------------------------
+
+bool wxPropertyGrid::Reparent( wxWindowBase *newParent )
+{
+    OnTLPChanging((wxWindow*)newParent);
+
+    bool res = wxScrolledWindow::Reparent(newParent);
+
+    return res;
+}
+
 // -----------------------------------------------------------------------
 // wxPropertyGrid Font and Colour Methods
 // -----------------------------------------------------------------------
@@ -1032,10 +1071,10 @@ void wxPropertyGrid::ResetColours()
 bool wxPropertyGrid::SetFont( const wxFont& font )
 {
     // Must disable active editor.
-    ClearSelection(false);
+    DoClearSelection();
 
     bool res = wxScrolledWindow::SetFont( font );
-    if ( res )
+    if ( res && GetParent()) // may not have been Create()ed yet
     {
         CalculateFontAndBitmapStuff( m_vspacing );
         Refresh();
@@ -2129,7 +2168,7 @@ void wxPropertyGrid::Clear()
 
 bool wxPropertyGrid::EnableCategories( bool enable )
 {
-    ClearSelection(false);
+    DoClearSelection();
 
     if ( enable )
     {
@@ -2181,7 +2220,7 @@ void wxPropertyGrid::SwitchState( wxPropertyGridPageState* pNewState )
 
     wxPGProperty* oldSelection = m_selected;
 
-    ClearSelection(false);
+    DoClearSelection();
 
     m_pState->m_selected = oldSelection;
 
@@ -2560,7 +2599,7 @@ void wxPropertyGrid::DoShowPropertyError( wxPGProperty* WXUNUSED(property), cons
     }
 #endif
 
-    ::wxMessageBox(msg, _T("Property Error"));
+    ::wxMessageBox(msg, wxT("Property Error"));
 }
 
 // -----------------------------------------------------------------------
@@ -2635,7 +2674,7 @@ bool wxPropertyGrid::DoOnValidationFailure( wxPGProperty* property, wxVariant& W
         wxString msg = m_validationInfo.m_failureMessage;
 
         if ( !msg.length() )
-            msg = _T("You have entered invalid value. Press ESC to cancel editing.");
+            msg = wxT("You have entered invalid value. Press ESC to cancel editing.");
 
         DoShowPropertyError(property, msg);
     }
@@ -3206,10 +3245,14 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
 {
     /*
     if (p)
+    {
         wxLogDebug(wxT("SelectProperty( %s (%s[%i]) )"),p->m_label.c_str(),
             p->m_parent->m_label.c_str(),p->GetIndexInParent());
+    }
     else
+    {
         wxLogDebug(wxT("SelectProperty( NULL, -1 )"));
+    }
     */
 
     if ( m_inDoSelectProperty )
@@ -3565,7 +3608,8 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
     m_inDoSelectProperty = 0;
 
     // call wx event handler (here so that it also occurs on deselection)
-    SendEvent( wxEVT_PG_SELECTED, m_selected, NULL, flags );
+    if ( !(flags & wxPG_SEL_DONT_SEND_EVENT) )
+        SendEvent( wxEVT_PG_SELECTED, m_selected, NULL, flags );
 
     return true;
 }
@@ -3618,11 +3662,23 @@ void wxPropertyGrid::RefreshEditor()
 
 // -----------------------------------------------------------------------
 
-// This method is not inline because it called dozens of times
-// (i.e. two-arg function calls create smaller code size).
+bool wxPropertyGrid::SelectProperty( wxPGPropArg id, bool focus )
+{
+    wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
+
+    int flags = wxPG_SEL_DONT_SEND_EVENT;
+    if ( focus )
+        flags |= wxPG_SEL_FOCUS;
+
+    return DoSelectProperty(p, flags);
+}
+
+// -----------------------------------------------------------------------
+
 bool wxPropertyGrid::DoClearSelection()
 {
-    return DoSelectProperty(NULL);
+    // Unlike ClearSelection(), here we send the wxEVT_PG_SELECTED event.
+    return DoSelectProperty(NULL, 0);
 }
 
 // -----------------------------------------------------------------------
@@ -3636,7 +3692,7 @@ bool wxPropertyGrid::DoCollapse( wxPGProperty* p, bool sendEvents )
     // If active editor was inside collapsed section, then disable it
     if ( m_selected && m_selected->IsSomeParent(p) )
     {
-        ClearSelection(false);
+        DoClearSelection();
     }
 
     // Store dont-center-splitter flag 'cause we need to temporarily set it
@@ -3721,7 +3777,7 @@ bool wxPropertyGrid::DoHideProperty( wxPGProperty* p, bool hide, int flags )
          ( m_selected == p || m_selected->IsSomeParent(p) )
        )
         {
-            ClearSelection(false);
+            DoClearSelection();
         }
 
     m_pState->DoHideProperty(p, hide, flags);
@@ -3749,16 +3805,10 @@ void wxPropertyGrid::RecalculateVirtualSize( int forceXPos )
 
     m_pState->EnsureVirtualHeight();
 
-#ifdef __WXDEBUG__
-    int by1 = m_pState->GetVirtualHeight();
-    int by2 = m_pState->GetActualVirtualHeight();
-    if ( by1 != by2 )
-    {
-        wxString s = wxString::Format(wxT("VirtualHeight=%i, ActualVirtualHeight=%i, should match!"), by1, by2);
-        wxFAIL_MSG(s.c_str());
-        wxLogDebug(s);
-    }
-#endif
+    wxASSERT_LEVEL_2_MSG(
+        m_pState->GetVirtualHeight() == m_pState->GetActualVirtualHeight(),
+        "VirtualHeight and ActualVirtualHeight should match"
+    );
 
     m_iFlags |= wxPG_FL_RECALCULATING_VIRTUAL_SIZE;
 
@@ -4930,6 +4980,14 @@ void wxPropertyGrid::OnIdle( wxIdleEvent& WXUNUSED(event) )
 
     if ( newFocused != m_curFocused )
         HandleFocusChange( newFocused );
+
+    //
+    // Check if top-level parent has changed
+    wxWindow* tlp = ::wxGetTopLevelParent(this);
+    if ( tlp != m_tlp )
+    {
+        OnTLPChanging(tlp);
+    }
 }
 
 bool wxPropertyGrid::IsEditorFocused() const
@@ -5056,15 +5114,18 @@ void wxPropertyGrid::OnCaptureChange( wxMouseCaptureChangedEvent& WXUNUSED(event
 // -----------------------------------------------------------------------
 
 // noDefCheck = true prevents infinite recursion.
-wxPGEditor* wxPropertyGrid::RegisterEditorClass( wxPGEditor* editorClass,
-                                                 bool noDefCheck )
+wxPGEditor* wxPropertyGrid::DoRegisterEditorClass( wxPGEditor* editorClass,
+                                                   const wxString& editorName,
+                                                   bool noDefCheck )
 {
     wxASSERT( editorClass );
 
     if ( !noDefCheck && wxPGGlobalVars->m_mapEditorClasses.empty() )
         RegisterDefaultEditors();
 
-    wxString name = editorClass->GetName();
+    wxString name = editorName;
+    if ( name.length() == 0 )
+        name = editorClass->GetName();
 
     // Existing editor under this name?
     wxPGHashMapS2P::iterator vt_it = wxPGGlobalVars->m_mapEditorClasses.find(name);
@@ -5201,7 +5262,6 @@ wxPGChoiceEntry::wxPGChoiceEntry()
 
 wxPGChoicesData::wxPGChoicesData()
 {
-    m_refCount = 1;
 }
 
 wxPGChoicesData::~wxPGChoicesData()