]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/grideditors.cpp
Check gtk_tree_model_iter_nth_child() return value in wxChoice code.
[wxWidgets.git] / src / generic / grideditors.cpp
index abd9a3bb59bb3c189bfde1027a121b12417b684a..939552b1803d0e2d4647b9ed28e67ce4122eb3e8 100644 (file)
     #include "wx/textctrl.h"
     #include "wx/checkbox.h"
     #include "wx/combobox.h"
-    #include "wx/valtext.h"
     #include "wx/intl.h"
     #include "wx/math.h"
     #include "wx/listbox.h"
 #endif
 
+#include "wx/valnum.h"
 #include "wx/textfile.h"
 #include "wx/spinctrl.h"
 #include "wx/tokenzr.h"
     #define WXUNUSED_GTK(identifier)    identifier
 #endif
 
+#ifdef __WXOSX__
+#include "wx/osx/private.h"
+#endif
+
 // Required for wxIs... functions
 #include <ctype.h>
 
@@ -242,21 +246,14 @@ void wxGridCellEditor::Create(wxWindow* WXUNUSED(parent),
         m_control->PushEventHandler(evtHandler);
 }
 
-void wxGridCellEditor::PaintBackground(const wxRect& rectCell,
-                                       wxGridCellAttr *attr)
+void wxGridCellEditor::PaintBackground(wxDC& dc,
+                                       const wxRect& rectCell,
+                                       const wxGridCellAttr& attr)
 {
     // erase the background because we might not fill the cell
-    wxClientDC dc(m_control->GetParent());
-    wxGridWindow* gridWindow = wxDynamicCast(m_control->GetParent(), wxGridWindow);
-    if (gridWindow)
-        gridWindow->GetOwner()->PrepareDC(dc);
-
     dc.SetPen(*wxTRANSPARENT_PEN);
-    dc.SetBrush(wxBrush(attr->GetBackgroundColour()));
+    dc.SetBrush(wxBrush(attr.GetBackgroundColour()));
     dc.DrawRectangle(rectCell);
-
-    // redraw the control we just painted over
-    m_control->Refresh();
 }
 
 void wxGridCellEditor::Destroy()
@@ -300,13 +297,13 @@ void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr)
     else
     {
         // restore the standard colours fonts
-        if ( m_colFgOld.Ok() )
+        if ( m_colFgOld.IsOk() )
         {
             m_control->SetForegroundColour(m_colFgOld);
             m_colFgOld = wxNullColour;
         }
 
-        if ( m_colBgOld.Ok() )
+        if ( m_colBgOld.IsOk() )
         {
             m_control->SetBackgroundColour(m_colBgOld);
             m_colBgOld = wxNullColour;
@@ -314,7 +311,7 @@ void wxGridCellEditor::Show(bool show, wxGridCellAttr *attr)
 
 // Workaround for GTK+1 font setting problem on some platforms
 #if !defined(__WXGTK__) || defined(__WXGTK20__)
-        if ( m_fontOld.Ok() )
+        if ( m_fontOld.IsOk() )
         {
             m_control->SetFont(m_fontOld);
             m_fontOld = wxNullFont;
@@ -338,13 +335,15 @@ void wxGridCellEditor::HandleReturn(wxKeyEvent& event)
 bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event)
 {
     bool ctrl = event.ControlDown();
-    bool alt  = event.AltDown();
+    bool alt;
 
 #ifdef __WXMAC__
     // On the Mac the Alt key is more like shift and is used for entry of
     // valid characters, so check for Ctrl and Meta instead.
     alt = event.MetaDown();
-#endif
+#else // !__WXMAC__
+    alt = event.AltDown();
+#endif // __WXMAC__/!__WXMAC__
 
     // Assume it's not a valid char if ctrl or alt is down, but if both are
     // down then it may be because of an AltGr key combination, so let them
@@ -353,14 +352,10 @@ bool wxGridCellEditor::IsAcceptedKey(wxKeyEvent& event)
         return false;
 
 #if wxUSE_UNICODE
-    // if the unicode key code is not really a unicode character (it may
-    // be a function key or etc., the platforms appear to always give us a
-    // small value in this case) then fallback to the ASCII key code but
-    // don't do anything for function keys or etc.
-    if ( event.GetUnicodeKey() > 127 && event.GetKeyCode() > 127 )
+    if ( static_cast<int>(event.GetUnicodeKey()) == WXK_NONE )
         return false;
 #else
-    if ( event.GetKeyCode() > 255 )
+    if ( event.GetKeyCode() > WXK_START )
         return false;
 #endif
 
@@ -399,12 +394,19 @@ void wxGridCellTextEditor::DoCreate(wxWindow* parent,
                                     wxEvtHandler* evtHandler,
                                     long style)
 {
-    style |= wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxNO_BORDER;
+    // Use of wxTE_RICH2 is a strange hack to work around the bug #11681: a
+    // plain text control seems to lose its caret somehow when we hide it and
+    // show it again for a different cell.
+    style |= wxTE_PROCESS_ENTER | wxTE_PROCESS_TAB | wxNO_BORDER | wxTE_RICH2;
 
     m_control = new wxTextCtrl(parent, id, wxEmptyString,
                                wxDefaultPosition, wxDefaultSize,
                                style);
 
+#ifdef __WXOSX__
+    wxWidgetImpl* impl = m_control->GetPeer();
+    impl->SetNeedsFocusRect(false);
+#endif
     // set max length allowed in the textctrl, if the parameter was set
     if ( m_maxChars != 0 )
     {
@@ -414,8 +416,9 @@ void wxGridCellTextEditor::DoCreate(wxWindow* parent,
     wxGridCellEditor::Create(parent, id, evtHandler);
 }
 
-void wxGridCellTextEditor::PaintBackground(const wxRect& WXUNUSED(rectCell),
-                                           wxGridCellAttr * WXUNUSED(attr))
+void wxGridCellTextEditor::PaintBackground(wxDC& WXUNUSED(dc),
+                                           const wxRect& WXUNUSED(rectCell),
+                                           const wxGridCellAttr& WXUNUSED(attr))
 {
     // as we fill the entire client area,
     // don't do anything here to minimize flicker
@@ -450,6 +453,12 @@ void wxGridCellTextEditor::SetSize(const wxRect& rectOrig)
 
     rect.width -= 2;
     rect.height -= 2;
+#elif defined(__WXOSX__)
+    rect.x += 1;
+    rect.y += 1;
+    
+    rect.width -= 1;
+    rect.height -= 1;
 #else
     int extra_x = ( rect.x > 2 ) ? 2 : 1;
     int extra_y = ( rect.y > 2 ) ? 2 : 1;
@@ -481,7 +490,7 @@ void wxGridCellTextEditor::DoBeginEdit(const wxString& startValue)
 {
     Text()->SetValue(startValue);
     Text()->SetInsertionPointEnd();
-    Text()->SetSelection(-1, -1);
+    Text()->SelectAll();
     Text()->SetFocus();
 }
 
@@ -527,7 +536,15 @@ void wxGridCellTextEditor::DoReset(const wxString& startValue)
 
 bool wxGridCellTextEditor::IsAcceptedKey(wxKeyEvent& event)
 {
-    return wxGridCellEditor::IsAcceptedKey(event);
+    switch ( event.GetKeyCode() )
+    {
+        case WXK_DELETE:
+        case WXK_BACK:
+            return true;
+
+        default:
+            return wxGridCellEditor::IsAcceptedKey(event);
+    }
 }
 
 void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
@@ -538,35 +555,39 @@ void wxGridCellTextEditor::StartingKey(wxKeyEvent& event)
     // a valid character, so not a whole lot of testing needs to be done.
 
     wxTextCtrl* tc = Text();
-    wxChar ch;
-    long pos;
+    int ch;
+
+    bool isPrintable;
 
 #if wxUSE_UNICODE
     ch = event.GetUnicodeKey();
-    if (ch <= 127)
-        ch = (wxChar)event.GetKeyCode();
-#else
-    ch = (wxChar)event.GetKeyCode();
-#endif
+    if ( ch != WXK_NONE )
+        isPrintable = true;
+    else
+#endif // wxUSE_UNICODE
+    {
+        ch = event.GetKeyCode();
+        isPrintable = ch >= WXK_SPACE && ch < WXK_START;
+    }
 
     switch (ch)
     {
         case WXK_DELETE:
-            // delete the character at the cursor
-            pos = tc->GetInsertionPoint();
-            if (pos < tc->GetLastPosition())
-                tc->Remove(pos, pos + 1);
+            // Delete the initial character when starting to edit with DELETE.
+            tc->Remove(0, 1);
             break;
 
         case WXK_BACK:
-            // delete the character before the cursor
-            pos = tc->GetInsertionPoint();
-            if (pos > 0)
+            // Delete the last character when starting to edit with BACKSPACE.
+            {
+                const long pos = tc->GetLastPosition();
                 tc->Remove(pos - 1, pos);
+            }
             break;
 
         default:
-            tc->WriteText(ch);
+            if ( isPrintable )
+                tc->WriteText(static_cast<wxChar>(ch));
             break;
     }
 }
@@ -604,7 +625,7 @@ void wxGridCellTextEditor::SetParameters(const wxString& params)
         }
         else
         {
-            wxLogDebug( _T("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str() );
+            wxLogDebug( wxT("Invalid wxGridCellTextEditor parameter string '%s' ignored"), params.c_str() );
         }
     }
 }
@@ -647,7 +668,7 @@ void wxGridCellNumberEditor::Create(wxWindow* parent,
         wxGridCellTextEditor::Create(parent, id, evtHandler);
 
 #if wxUSE_VALIDATORS
-        Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
+        Text()->SetValidator(wxIntegerValidator<int>());
 #endif
     }
 }
@@ -666,7 +687,7 @@ void wxGridCellNumberEditor::BeginEdit(int row, int col, wxGrid* grid)
         wxString sValue = table->GetValue(row, col);
         if (! sValue.ToLong(&m_value) && ! sValue.empty())
         {
-            wxFAIL_MSG( _T("this cell doesn't have numeric value") );
+            wxFAIL_MSG( wxT("this cell doesn't have numeric value") );
             return;
         }
     }
@@ -808,11 +829,11 @@ void wxGridCellNumberEditor::SetParameters(const wxString& params)
     else
     {
         long tmp;
-        if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
+        if ( params.BeforeFirst(wxT(',')).ToLong(&tmp) )
         {
             m_min = (int)tmp;
 
-            if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
+            if ( params.AfterFirst(wxT(',')).ToLong(&tmp) )
             {
                 m_max = (int)tmp;
 
@@ -821,7 +842,7 @@ void wxGridCellNumberEditor::SetParameters(const wxString& params)
             }
         }
 
-        wxLogDebug(_T("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params.c_str());
+        wxLogDebug(wxT("Invalid wxGridCellNumberEditor parameter string '%s' ignored"), params.c_str());
     }
 }
 
@@ -849,10 +870,13 @@ wxString wxGridCellNumberEditor::GetValue() const
 // wxGridCellFloatEditor
 // ----------------------------------------------------------------------------
 
-wxGridCellFloatEditor::wxGridCellFloatEditor(int width, int precision)
+wxGridCellFloatEditor::wxGridCellFloatEditor(int width,
+                                             int precision,
+                                             int format)
 {
     m_width = width;
     m_precision = precision;
+    m_style = format;
 }
 
 void wxGridCellFloatEditor::Create(wxWindow* parent,
@@ -862,7 +886,7 @@ void wxGridCellFloatEditor::Create(wxWindow* parent,
     wxGridCellTextEditor::Create(parent, id, evtHandler);
 
 #if wxUSE_VALIDATORS
-    Text()->SetValidator(wxTextValidator(wxFILTER_NUMERIC));
+    Text()->SetValidator(wxFloatingPointValidator<double>(m_precision));
 #endif
 }
 
@@ -883,7 +907,7 @@ void wxGridCellFloatEditor::BeginEdit(int row, int col, wxGrid* grid)
         {
             if ( !value.ToDouble(&m_value) )
             {
-                wxFAIL_MSG( _T("this cell doesn't have float value") );
+                wxFAIL_MSG( wxT("this cell doesn't have float value") );
                 return;
             }
         }
@@ -953,7 +977,7 @@ void wxGridCellFloatEditor::StartingKey(wxKeyEvent& event)
     bool is_decimal_point = ( strbuf ==
        wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER) );
 #else
-    bool is_decimal_point = ( strbuf == _T(".") );
+    bool is_decimal_point = ( strbuf == wxT(".") );
 #endif
 
     if ( wxIsdigit(keycode) || keycode == '+' || keycode == '-'
@@ -975,51 +999,113 @@ void wxGridCellFloatEditor::SetParameters(const wxString& params)
         // reset to default
         m_width =
         m_precision = -1;
+        m_style = wxGRID_FLOAT_FORMAT_DEFAULT;
+        m_format.clear();
     }
     else
     {
-        long tmp;
-        if ( params.BeforeFirst(_T(',')).ToLong(&tmp) )
+        wxString rest;
+        wxString tmp = params.BeforeFirst(wxT(','), &rest);
+        if ( !tmp.empty() )
         {
-            m_width = (int)tmp;
-
-            if ( params.AfterFirst(_T(',')).ToLong(&tmp) )
+            long width;
+            if ( tmp.ToLong(&width) )
             {
-                m_precision = (int)tmp;
+                m_width = (int)width;
+            }
+            else
+            {
+                wxLogDebug(wxT("Invalid wxGridCellFloatRenderer width parameter string '%s ignored"), params.c_str());
+            }
+        }
 
-                // skip the error message below
-                return;
+        tmp = rest.BeforeFirst(wxT(','));
+        if ( !tmp.empty() )
+        {
+            long precision;
+            if ( tmp.ToLong(&precision) )
+            {
+                m_precision = (int)precision;
+            }
+            else
+            {
+                wxLogDebug(wxT("Invalid wxGridCellFloatRenderer precision parameter string '%s ignored"), params.c_str());
             }
         }
 
-        wxLogDebug(_T("Invalid wxGridCellFloatEditor parameter string '%s' ignored"), params.c_str());
+        tmp = rest.AfterFirst(wxT(','));
+        if ( !tmp.empty() )
+        {
+            if ( tmp[0] == wxT('f') )
+            {
+                m_style = wxGRID_FLOAT_FORMAT_FIXED;
+            }
+            else if ( tmp[0] == wxT('e') )
+            {
+                m_style = wxGRID_FLOAT_FORMAT_SCIENTIFIC;
+            }
+            else if ( tmp[0] == wxT('g') )
+            {
+                m_style = wxGRID_FLOAT_FORMAT_COMPACT;
+            }
+            else if ( tmp[0] == wxT('E') )
+            {
+                m_style = wxGRID_FLOAT_FORMAT_SCIENTIFIC |
+                          wxGRID_FLOAT_FORMAT_UPPER;
+            }
+            else if ( tmp[0] == wxT('F') )
+            {
+                m_style = wxGRID_FLOAT_FORMAT_FIXED |
+                          wxGRID_FLOAT_FORMAT_UPPER;
+            }
+            else if ( tmp[0] == wxT('G') )
+            {
+                m_style = wxGRID_FLOAT_FORMAT_COMPACT |
+                          wxGRID_FLOAT_FORMAT_UPPER;
+            }
+            else
+            {
+                wxLogDebug("Invalid wxGridCellFloatRenderer format "
+                           "parameter string '%s ignored", params);
+            }
+        }
     }
 }
 
-wxString wxGridCellFloatEditor::GetString() const
+wxString wxGridCellFloatEditor::GetString()
 {
-    wxString fmt;
-    if ( m_precision == -1 && m_width != -1)
-    {
-        // default precision
-        fmt.Printf(_T("%%%d.f"), m_width);
-    }
-    else if ( m_precision != -1 && m_width == -1)
+    if ( !m_format )
     {
-        // default width
-        fmt.Printf(_T("%%.%df"), m_precision);
-    }
-    else if ( m_precision != -1 && m_width != -1 )
-    {
-        fmt.Printf(_T("%%%d.%df"), m_width, m_precision);
-    }
-    else
-    {
-        // default width/precision
-        fmt = _T("%f");
+        if ( m_precision == -1 && m_width != -1)
+        {
+            // default precision
+            m_format.Printf(wxT("%%%d."), m_width);
+        }
+        else if ( m_precision != -1 && m_width == -1)
+        {
+            // default width
+            m_format.Printf(wxT("%%.%d"), m_precision);
+        }
+        else if ( m_precision != -1 && m_width != -1 )
+        {
+            m_format.Printf(wxT("%%%d.%d"), m_width, m_precision);
+        }
+        else
+        {
+            // default width/precision
+            m_format = wxT("%");
+        }
+
+        bool isUpper = (m_style & wxGRID_FLOAT_FORMAT_UPPER) != 0;
+        if ( m_style & wxGRID_FLOAT_FORMAT_SCIENTIFIC )
+            m_format += isUpper ? wxT('E') : wxT('e');
+        else if ( m_style & wxGRID_FLOAT_FORMAT_COMPACT )
+            m_format += isUpper ? wxT('G') : wxT('g');
+        else
+            m_format += wxT('f');
     }
 
-    return wxString::Format(fmt, m_value);
+    return wxString::Format(m_format, m_value);
 }
 
 bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event)
@@ -1027,18 +1113,13 @@ bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event)
     if ( wxGridCellEditor::IsAcceptedKey(event) )
     {
         const int keycode = event.GetKeyCode();
-        if ( isascii(keycode) )
+        if ( wxIsascii(keycode) )
         {
-            char tmpbuf[2];
-            tmpbuf[0] = (char) keycode;
-            tmpbuf[1] = '\0';
-            wxString strbuf(tmpbuf, *wxConvCurrent);
-
 #if wxUSE_INTL
             const wxString decimalPoint =
                 wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
 #else
-            const wxString decimalPoint(_T('.'));
+            const wxString decimalPoint(wxT('.'));
 #endif
 
             // accept digits, 'e' as in '1e+6', also '-', '+', and '.'
@@ -1065,7 +1146,7 @@ bool wxGridCellFloatEditor::IsAcceptedKey(wxKeyEvent& event)
 // ----------------------------------------------------------------------------
 
 // the default values for GetValue()
-wxString wxGridCellBoolEditor::ms_stringValues[2] = { _T(""), _T("1") };
+wxString wxGridCellBoolEditor::ms_stringValues[2] = { wxT(""), wxT("1") };
 
 void wxGridCellBoolEditor::Create(wxWindow* parent,
                                   wxWindowID id,
@@ -1183,7 +1264,7 @@ void wxGridCellBoolEditor::BeginEdit(int row, int col, wxGrid* grid)
             // because we'll still overwrite it with something different and
             // this risks to be very surprising for the user code, let them
             // know about it
-            wxFAIL_MSG( _T("invalid value for a cell with bool editor!") );
+            wxFAIL_MSG( wxT("invalid value for a cell with bool editor!") );
         }
     }
 
@@ -1341,8 +1422,32 @@ void wxGridCellChoiceEditor::Create(wxWindow* parent,
     wxGridCellEditor::Create(parent, id, evtHandler);
 }
 
-void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
-                                             wxGridCellAttr * attr)
+void wxGridCellChoiceEditor::SetSize(const wxRect& rect)
+{
+    wxASSERT_MSG(m_control,
+                 wxT("The wxGridCellChoiceEditor must be created first!"));
+
+    // Check that the height is not too small to fit the combobox.
+    wxRect rectTallEnough = rect;
+    const wxSize bestSize = m_control->GetBestSize();
+    const wxCoord diffY = bestSize.GetHeight() - rectTallEnough.GetHeight();
+    if ( diffY > 0 )
+    {
+        // Do make it tall enough.
+        rectTallEnough.height += diffY;
+
+        // Also centre the effective rectangle vertically with respect to the
+        // original one.
+        rectTallEnough.y -= diffY/2;
+    }
+    //else: The rectangle provided is already tall enough.
+
+    wxGridCellEditor::SetSize(rectTallEnough);
+}
+
+void wxGridCellChoiceEditor::PaintBackground(wxDC& dc,
+                                             const wxRect& rectCell,
+                                             const wxGridCellAttr& attr)
 {
     // as we fill the entire client area, don't do anything here to minimize
     // flicker
@@ -1350,7 +1455,7 @@ void wxGridCellChoiceEditor::PaintBackground(const wxRect& rectCell,
     // TODO: It doesn't actually fill the client area since the height of a
     // combo always defaults to the standard.  Until someone has time to
     // figure out the right rectangle to paint, just do it the normal way.
-    wxGridCellEditor::PaintBackground(rectCell, attr);
+    wxGridCellEditor::PaintBackground(dc, rectCell, attr);
 }
 
 void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
@@ -1372,6 +1477,14 @@ void wxGridCellChoiceEditor::BeginEdit(int row, int col, wxGrid* grid)
 
     Combo()->SetFocus();
 
+#ifdef __WXOSX_COCOA__
+    // This is a work around for the combobox being simply dismissed when a
+    // choice is made in it under OS X. The bug is almost certainly due to a
+    // problem in focus events generation logic but it's not obvious to fix and
+    // for now this at least allows to use wxGrid.
+    Combo()->Popup();
+#endif
+
     if (evtHandler)
     {
         // When dropping down the menu, a kill focus event
@@ -1432,7 +1545,7 @@ void wxGridCellChoiceEditor::SetParameters(const wxString& params)
 
     m_choices.Empty();
 
-    wxStringTokenizer tk(params, _T(','));
+    wxStringTokenizer tk(params, wxT(','));
     while ( tk.HasMoreTokens() )
     {
         m_choices.Add(tk.GetNextToken());
@@ -1478,6 +1591,14 @@ void wxGridCellEnumEditor::BeginEdit(int row, int col, wxGrid* grid)
     wxASSERT_MSG(m_control,
                  wxT("The wxGridCellEnumEditor must be Created first!"));
 
+    wxGridCellEditorEvtHandler* evtHandler = NULL;
+    if (m_control)
+        evtHandler = wxDynamicCast(m_control->GetEventHandler(), wxGridCellEditorEvtHandler);
+
+    // Don't immediately end if we get a kill focus event within BeginEdit
+    if (evtHandler)
+        evtHandler->SetInSetFocus(true);
+
     wxGridTableBase *table = grid->GetTable();
 
     if ( table->CanGetValueAs(row, col, wxGRID_VALUE_NUMBER) )
@@ -1498,9 +1619,24 @@ void wxGridCellEnumEditor::BeginEdit(int row, int col, wxGrid* grid)
     }
 
     Combo()->SetSelection(m_index);
-    Combo()->SetInsertionPointEnd();
     Combo()->SetFocus();
 
+#ifdef __WXOSX_COCOA__
+    // This is a work around for the combobox being simply dismissed when a
+    // choice is made in it under OS X. The bug is almost certainly due to a
+    // problem in focus events generation logic but it's not obvious to fix and
+    // for now this at least allows to use wxGrid.
+    Combo()->Popup();
+#endif
+
+    if (evtHandler)
+    {
+        // When dropping down the menu, a kill focus event
+        // happens after this point, so we can't reset the flag yet.
+#if !defined(__WXGTK20__)
+        evtHandler->SetInSetFocus(false);
+#endif
+    }
 }
 
 bool wxGridCellEnumEditor::EndEdit(int WXUNUSED(row),