]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/pickerbase.cpp
fixing overrelease and out-of-bounds write, fixes #13725
[wxWidgets.git] / src / common / pickerbase.cpp
index 68ff4a88ee0e9754c9e00772524b87bf20315fb0..fa3532995222f2e35437fb3611078c246142e25e 100644 (file)
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////////
-// Name:        common/pickerbase.cpp
+// Name:        src/common/pickerbase.cpp
 // Purpose:     wxPickerBase class implementation
 // Author:      Francesco Montorsi
 // Modified by:
     #pragma hdrstop
 #endif
 
+#if wxUSE_COLOURPICKERCTRL || \
+    wxUSE_DIRPICKERCTRL    || \
+    wxUSE_FILEPICKERCTRL   || \
+    wxUSE_FONTPICKERCTRL
+
 #include "wx/pickerbase.h"
+#include "wx/tooltip.h"
+
+#ifndef WX_PRECOMP
+    #include "wx/textctrl.h"
+#endif
 
 
 // ============================================================================
 // implementation
 // ============================================================================
 
-IMPLEMENT_ABSTRACT_CLASS(wxPickerBase, wxWindow)
+IMPLEMENT_ABSTRACT_CLASS(wxPickerBase, wxControl)
 
 // ----------------------------------------------------------------------------
 // wxPickerBase
 // ----------------------------------------------------------------------------
 
-wxPickerBase::~wxPickerBase()
-{
-    // destroy the windows we are managing: these are not automatically
-    // destroyed by wxWindow because they are not built as our children
-    // but rather as children of the parent of the wxPickerBase class
-    // (since wxPickerBase does not represent a real window)
-    if (m_text) m_text->Destroy();
-    if (m_picker) m_picker->Destroy();
-}
-
 bool wxPickerBase::CreateBase(wxWindow *parent,
                          wxWindowID id,
                          const wxString &text,
@@ -59,24 +59,30 @@ bool wxPickerBase::CreateBase(wxWindow *parent,
     // remove any border style from our style as wxPickerBase's window must be
     // invisible (user styles must be set on the textctrl or the platform-dependent picker)
     style &= ~wxBORDER_MASK;
-    if (!wxControl::Create(parent, id, pos, size, style | wxNO_BORDER | wxTAB_TRAVERSAL, 
-                            validator, name))
+
+    if (!wxControl::Create(parent, id, pos, size, style | wxNO_BORDER | wxTAB_TRAVERSAL,
+                           validator, name))
         return false;
 
+    SetMinSize( size );
+
+    m_sizer = new wxBoxSizer(wxHORIZONTAL);
+
     if (HasFlag(wxPB_USE_TEXTCTRL))
     {
         // NOTE: the style of this class (wxPickerBase) and the style of the
         //       attached text control are different: GetTextCtrlStyle() extracts
         //       the styles related to the textctrl from the styles passed here
-        m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxPoint(0, 0),
-                                wxSize(40, size.GetHeight()), GetTextCtrlStyle(style));
+        m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString,
+                                wxDefaultPosition, wxDefaultSize,
+                                GetTextCtrlStyle(style));
         if (!m_text)
         {
             wxFAIL_MSG( wxT("wxPickerBase's textctrl creation failed") );
             return false;
         }
 
-        // set the maximum lenght allowed for this textctrl.
+        // set the maximum length allowed for this textctrl.
         // This is very important since any change to it will trigger an update in
         // the m_picker; for very long strings, this real-time synchronization could
         // become a CPU-blocker and thus should be avoided.
@@ -86,109 +92,89 @@ bool wxPickerBase::CreateBase(wxWindow *parent,
         // set the initial contents of the textctrl
         m_text->SetValue(text);
 
-        m_text->Connect(wxEVT_COMMAND_TEXT_UPDATED,
+        m_text->Connect(m_text->GetId(), wxEVT_COMMAND_TEXT_UPDATED,
                 wxCommandEventHandler(wxPickerBase::OnTextCtrlUpdate),
                 NULL, this);
-        m_text->Connect(wxEVT_KILL_FOCUS,
+        m_text->Connect(m_text->GetId(), wxEVT_KILL_FOCUS,
                 wxFocusEventHandler(wxPickerBase::OnTextCtrlKillFocus),
                 NULL, this);
 
-        m_text->Connect(wxEVT_DESTROY,
+        m_text->Connect(m_text->GetId(), wxEVT_DESTROY,
                 wxWindowDestroyEventHandler(wxPickerBase::OnTextCtrlDelete),
                 NULL, this);
+
+        // the text control's proportion values defaults to 2
+        m_sizer->Add(m_text, 2, GetDefaultTextCtrlFlag(), 5);
     }
 
     return true;
 }
 
-void wxPickerBase::OnTextCtrlKillFocus(wxFocusEvent &)
+void wxPickerBase::PostCreation()
 {
-    wxASSERT(m_text);
+    // the picker's proportion value defaults to 1 when there's no text control
+    // associated with it - in that case it defaults to 0
+    m_sizer->Add(m_picker, HasTextCtrl() ? 0 : 1, GetDefaultPickerCtrlFlag(), 5);
+
+    // For aesthetic reasons, make sure the picker is at least as high as the
+    // associated text control and is always at least square, unless we are
+    // explicitly using wxPB_SMALL style to force it to take as little space as
+    // possible.
+    if ( !HasFlag(wxPB_SMALL) )
+    {
+        const wxSize pickerBestSize(m_picker->GetBestSize());
+        const wxSize textBestSize( HasTextCtrl() ? m_text->GetBestSize() : wxSize());
+        wxSize pickerMinSize;
+        pickerMinSize.y = wxMax(pickerBestSize.y, textBestSize.y);
+        pickerMinSize.x = wxMax(pickerBestSize.x, pickerMinSize.y);
+        if ( pickerMinSize != pickerBestSize )
+            m_picker->SetMinSize(pickerMinSize);
+    }
 
-    // don't leave the textctrl empty
-    if (m_text->GetValue().IsEmpty())
-        UpdateTextCtrlFromPicker();
-}
+    SetSizer(m_sizer);
 
-void wxPickerBase::OnTextCtrlDelete(wxWindowDestroyEvent &)
-{
-    // the textctrl has been deleted; our pointer is invalid!
-    m_text = NULL;
+    SetInitialSize( GetMinSize() );
 }
 
-void wxPickerBase::OnTextCtrlUpdate(wxCommandEvent &)
-{
-    // for each text-change, update the picker
-    UpdatePickerFromTextCtrl();
-}
+#if wxUSE_TOOLTIPS
 
-int wxPickerBase::GetTextCtrlWidth(int given)
+void wxPickerBase::DoSetToolTip(wxToolTip *tip)
 {
-    // compute the width of m_text like a wxBoxSizer(wxHORIZONTAL) would do
-    // NOTE: the proportion of m_picker is fixed to 1
-    return ((given - m_margin) / (m_textProportion + 1)) * m_textProportion;
+    // don't set the tooltip on us but rather on our two child windows
+    // as otherwise it would appear only when the cursor is placed on the
+    // small area around the child windows which belong to wxPickerBase
+    m_picker->SetToolTip(tip);
+
+    // do a copy as wxWindow will own the pointer we pass
+    if ( m_text )
+        m_text->SetToolTip(tip ? new wxToolTip(tip->GetTip()) : NULL);
 }
 
-void wxPickerBase::DoSetSizeHints(int minW, int minH, int maxW, int maxH, int incW, int incH)
-{
-    wxControl::DoSetSizeHints(minW, minH, maxW, maxH, incW, incH);
+#endif // wxUSE_TOOLTIPS
 
-    if (m_text)
-    {
-        // compute minWidth and maxWidth of the ausiliary textctrl
-        int textCtrlMinW = -1, textCtrlMaxW = -1;
-        if (minW != -1)
-        {
-            textCtrlMinW = GetTextCtrlWidth(minW);
-            minW -= textCtrlMinW + m_margin;
-        }
-
-        if (maxW != -1)
-        {
-            textCtrlMaxW = GetTextCtrlWidth(maxW);
-            maxW -= textCtrlMaxW + m_margin;
-        }
+// ----------------------------------------------------------------------------
+// wxPickerBase - event handlers
+// ----------------------------------------------------------------------------
 
-        m_text->SetSizeHints(textCtrlMinW, minH, textCtrlMaxW, maxH, incW, incH);
-    }
+void wxPickerBase::OnTextCtrlKillFocus(wxFocusEvent& event)
+{
+    event.Skip();
 
-    if (m_picker)
-        m_picker->SetSizeHints(minW, minH, maxW, maxH, incW, incH);
+    // don't leave the textctrl empty
+    if (m_text && m_text->GetValue().empty())
+        UpdateTextCtrlFromPicker();
 }
 
-void wxPickerBase::DoSetSize(int x, int y, int width, int height, int sizeFlags)
+void wxPickerBase::OnTextCtrlDelete(wxWindowDestroyEvent &)
 {
-    wxControl::DoSetSize(x, y, width, height, sizeFlags);
-
-    int pickerx = 0;
-    if (m_text)
-    {
-        // compute width of the ausiliary textctrl
-        int textCtrlW = GetTextCtrlWidth(width);
-
-        // set the m_text's position relatively to this window
-        m_text->SetSize(0, 0, textCtrlW, height, sizeFlags);
-
-        // change position of the real picker
-        pickerx += textCtrlW + m_margin;
-        width -= textCtrlW + m_margin;
-    }
-
-    if (m_picker)
-        m_picker->SetSize(pickerx, 0, width, height, sizeFlags);
+    // the textctrl has been deleted; our pointer is invalid!
+    m_text = NULL;
 }
 
-wxSize wxPickerBase::DoGetBestSize() const
+void wxPickerBase::OnTextCtrlUpdate(wxCommandEvent &)
 {
-    wxSize ret = m_picker->GetBestSize();
-
-    if (m_text)
-    {
-        wxSize sz = m_text->GetBestSize();
-
-        ret.SetWidth( ret.GetWidth() + sz.GetWidth() + m_margin );
-        ret.SetHeight( wxMax(ret.GetHeight(), sz.GetHeight()) );
-    }
-
-    return ret;
+    // for each text-change, update the picker
+    UpdatePickerFromTextCtrl();
 }
+
+#endif // Any picker in use