]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk1/textctrl.cpp
Fix for unsafe use of a global pointer for focus window: now checks at destruct
[wxWidgets.git] / src / gtk1 / textctrl.cpp
index 1039af2f372bdccd42e43f1ddeb6dc3cc517be50..6194b622bc2d71c3efd0df4bc4708587bd13aeb1 100644 (file)
@@ -14,6 +14,7 @@
 #include "wx/textctrl.h"
 #include "wx/utils.h"
 #include "wx/intl.h"
 #include "wx/textctrl.h"
 #include "wx/utils.h"
 #include "wx/intl.h"
+#include "wx/log.h"
 #include "wx/settings.h"
 
 #include <sys/types.h>
 #include "wx/settings.h"
 
 #include <sys/types.h>
@@ -51,6 +52,7 @@ gtk_text_changed_callback( GtkWidget *WXUNUSED(widget), wxTextCtrl *win )
         wxapp_install_idle_handler();
 
     win->SetModified();
         wxapp_install_idle_handler();
 
     win->SetModified();
+    win->UpdateFontIfNeeded();
 
     wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, win->GetId() );
     event.SetString( win->GetValue() );
 
     wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, win->GetId() );
     event.SetString( win->GetValue() );
@@ -95,22 +97,36 @@ BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
     EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
 END_EVENT_TABLE()
 
     EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
 END_EVENT_TABLE()
 
-wxTextCtrl::wxTextCtrl()
+void wxTextCtrl::Init()
 {
     m_modified = FALSE;
 {
     m_modified = FALSE;
+    m_updateFont = FALSE;
+    m_text =
+    m_vScrollbar = (GtkWidget *)NULL;
 }
 
 }
 
-wxTextCtrl::wxTextCtrl( wxWindow *parent, wxWindowID id, const wxString &value,
-      const wxPoint &pos, const wxSize &size,
-      int style, const wxValidator& validator, const wxString &name )
+wxTextCtrl::wxTextCtrl( wxWindow *parent,
+                        wxWindowID id,
+                        const wxString &value,
+                        const wxPoint &pos,
+                        const wxSize &size,
+                        long style,
+                        const wxValidator& validator,
+                        const wxString &name )
 {
 {
-    m_modified = FALSE;
+    Init();
+
     Create( parent, id, value, pos, size, style, validator, name );
 }
 
     Create( parent, id, value, pos, size, style, validator, name );
 }
 
-bool wxTextCtrl::Create( wxWindow *parent, wxWindowID id, const wxString &value,
-      const wxPoint &pos, const wxSize &size,
-      int style, const wxValidator& validator, const wxString &name )
+bool wxTextCtrl::Create( wxWindow *parent,
+                         wxWindowID id,
+                         const wxString &value,
+                         const wxPoint &pos,
+                         const wxSize &size,
+                         long style,
+                         const wxValidator& validator,
+                         const wxString &name )
 {
     m_needParent = TRUE;
     m_acceptsFocus = TRUE;
 {
     m_needParent = TRUE;
     m_acceptsFocus = TRUE;
@@ -119,7 +135,7 @@ bool wxTextCtrl::Create( wxWindow *parent, wxWindowID id, const wxString &value,
         !CreateBase( parent, id, pos, size, style, validator, name ))
     {
         wxFAIL_MSG( wxT("wxTextCtrl creation failed") );
         !CreateBase( parent, id, pos, size, style, validator, name ))
     {
         wxFAIL_MSG( wxT("wxTextCtrl creation failed") );
-       return FALSE;
+        return FALSE;
     }
 
 
     }
 
 
@@ -182,15 +198,21 @@ bool wxTextCtrl::Create( wxWindow *parent, wxWindowID id, const wxString &value,
           m_text = gtk_entry_new();
     }
 
           m_text = gtk_entry_new();
     }
 
-    wxSize newSize = size;
-    if (newSize.x == -1) newSize.x = 80;
-    if (newSize.y == -1) newSize.y = 26;
-    SetSize( newSize.x, newSize.y );
-
     m_parent->DoAddChild( this );
 
     PostCreation();
 
     m_parent->DoAddChild( this );
 
     PostCreation();
 
+    SetFont( parent->GetFont() );
+
+    wxSize size_best( DoGetBestSize() );
+    wxSize new_size( size );
+    if (new_size.x == -1)
+        new_size.x = size_best.x;
+    if (new_size.y == -1)
+        new_size.y = size_best.y;
+    if ((new_size.x != size.x) || (new_size.y != size.y))
+        SetSize( new_size.x, new_size.y );
+
     if (multi_line)
         gtk_widget_show(m_text);
 
     if (multi_line)
         gtk_widget_show(m_text);
 
@@ -250,7 +272,7 @@ bool wxTextCtrl::Create( wxWindow *parent, wxWindowID id, const wxString &value,
     SetForegroundColour( parent->GetForegroundColour() );
 
     m_cursor = wxCursor( wxCURSOR_IBEAM );
     SetForegroundColour( parent->GetForegroundColour() );
 
     m_cursor = wxCursor( wxCURSOR_IBEAM );
-    
+
     Show( TRUE );
 
     return TRUE;
     Show( TRUE );
 
     return TRUE;
@@ -303,24 +325,29 @@ void wxTextCtrl::SetValue( const wxString &value )
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
-    wxString tmp = wxT("");
-    if (!value.IsNull()) tmp = value;
     if (m_windowStyle & wxTE_MULTILINE)
     {
         gint len = gtk_text_get_length( GTK_TEXT(m_text) );
         gtk_editable_delete_text( GTK_EDITABLE(m_text), 0, len );
         len = 0;
 #if wxUSE_UNICODE
     if (m_windowStyle & wxTE_MULTILINE)
     {
         gint len = gtk_text_get_length( GTK_TEXT(m_text) );
         gtk_editable_delete_text( GTK_EDITABLE(m_text), 0, len );
         len = 0;
 #if wxUSE_UNICODE
-        wxWX2MBbuf tmpbuf = tmp.mbc_str();
+        wxWX2MBbuf tmpbuf = value.mbc_str();
         gtk_editable_insert_text( GTK_EDITABLE(m_text), tmpbuf, strlen(tmpbuf), &len );
 #else
         gtk_editable_insert_text( GTK_EDITABLE(m_text), tmpbuf, strlen(tmpbuf), &len );
 #else
-        gtk_editable_insert_text( GTK_EDITABLE(m_text), tmp.mbc_str(), tmp.Length(), &len );
+        gtk_editable_insert_text( GTK_EDITABLE(m_text), value.mbc_str(), value.Length(), &len );
 #endif
     }
     else
     {
 #endif
     }
     else
     {
-        gtk_entry_set_text( GTK_ENTRY(m_text), tmp.mbc_str() );
+        gtk_entry_set_text( GTK_ENTRY(m_text), value.mbc_str() );
     }
     }
+
+    // GRG, Jun/2000: Changed this after a lot of discussion in
+    //   the lists. wxWindows 2.2 will have a set of flags to
+    //   customize this behaviour.
+    SetInsertionPoint(0);
+
+    m_modified = FALSE;
 }
 
 void wxTextCtrl::WriteText( const wxString &text )
 }
 
 void wxTextCtrl::WriteText( const wxString &text )
@@ -567,7 +594,7 @@ void wxTextCtrl::SetInsertionPoint( long pos )
 
         /* bring editable's cursor uptodate. bug in GTK. */
 
 
         /* bring editable's cursor uptodate. bug in GTK. */
 
-        GTK_EDITABLE(m_text)->current_pos = pos;
+        GTK_EDITABLE(m_text)->current_pos = (guint32)pos;
     }
 }
 
     }
 }
 
@@ -591,6 +618,26 @@ void wxTextCtrl::SetEditable( bool editable )
         gtk_entry_set_editable( GTK_ENTRY(m_text), editable );
 }
 
         gtk_entry_set_editable( GTK_ENTRY(m_text), editable );
 }
 
+bool wxTextCtrl::Enable( bool enable )
+{
+    if (!wxWindowBase::Enable(enable))
+    {
+        // nothing to do
+        return FALSE;
+    }
+
+    if (m_windowStyle & wxTE_MULTILINE)
+    {
+        gtk_text_set_editable( GTK_TEXT(m_text), enable );
+    }
+    else
+    {
+        gtk_widget_set_sensitive( m_text, enable );
+    }
+
+    return TRUE;
+}
+
 void wxTextCtrl::DiscardEdits()
 {
     m_modified = FALSE;
 void wxTextCtrl::DiscardEdits()
 {
     m_modified = FALSE;
@@ -600,6 +647,14 @@ void wxTextCtrl::SetSelection( long from, long to )
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
+    if ( (m_windowStyle & wxTE_MULTILINE) &&
+         !GTK_TEXT(m_text)->line_start_cache )
+    {
+        // tell the programmer that it didn't work
+        wxLogDebug(_T("Can't call SetSelection() before realizing the control"));
+        return;
+    }
+
     gtk_editable_select_region( GTK_EDITABLE(m_text), (gint)from, (gint)to );
 }
 
     gtk_editable_select_region( GTK_EDITABLE(m_text), (gint)from, (gint)to );
 }
 
@@ -699,7 +754,7 @@ bool wxTextCtrl::CanCut() const
     // Can cut if there's a selection
     long from, to;
     GetSelection(& from, & to);
     // Can cut if there's a selection
     long from, to;
     GetSelection(& from, & to);
-    return (from != to) ;
+    return (from != to) && (IsEditable());
 }
 
 bool wxTextCtrl::CanPaste() const
 }
 
 bool wxTextCtrl::CanPaste() const
@@ -742,8 +797,9 @@ void wxTextCtrl::GetSelection(long* from, long* to) const
 
     if (!(GTK_EDITABLE(m_text)->has_selection))
     {
 
     if (!(GTK_EDITABLE(m_text)->has_selection))
     {
-        if (from) *from = 0;
-        if (to)   *to = 0;
+        long i = GetInsertionPoint();
+        if (from) *from = i;
+        if (to)   *to = i;
         return;
     }
 
         return;
     }
 
@@ -776,21 +832,22 @@ void wxTextCtrl::OnChar( wxKeyEvent &key_event )
     {
         wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
         event.SetEventObject(this);
     {
         wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
         event.SetEventObject(this);
+        event.SetString(GetValue());
         if (GetEventHandler()->ProcessEvent(event)) return;
     }
 
     if ((key_event.KeyCode() == WXK_RETURN) && !(m_windowStyle & wxTE_MULTILINE))
     {
         wxWindow *top_frame = m_parent;
         if (GetEventHandler()->ProcessEvent(event)) return;
     }
 
     if ((key_event.KeyCode() == WXK_RETURN) && !(m_windowStyle & wxTE_MULTILINE))
     {
         wxWindow *top_frame = m_parent;
-        while (top_frame->GetParent() && !(top_frame->GetParent()->m_isFrame))
+        while (top_frame->GetParent() && !(top_frame->IsTopLevel()))
             top_frame = top_frame->GetParent();
             top_frame = top_frame->GetParent();
-       GtkWindow *window = GTK_WINDOW(top_frame->m_widget);
-       
-       if (window->default_widget)
+        GtkWindow *window = GTK_WINDOW(top_frame->m_widget);
+
+        if (window->default_widget)
         {
             gtk_widget_activate (window->default_widget);
         {
             gtk_widget_activate (window->default_widget);
-           return;
-       }
+            return;
+        }
     }
 
     key_event.Skip();
     }
 
     key_event.Skip();
@@ -822,20 +879,37 @@ bool wxTextCtrl::SetFont( const wxFont &font )
 
     if ( m_windowStyle & wxTE_MULTILINE )
     {
 
     if ( m_windowStyle & wxTE_MULTILINE )
     {
-        // for compatibility with other ports: the font is a global controls
-        // characteristic, so change the font globally
-        wxString value = GetValue();
-        if ( !value.IsEmpty() )
-        {
-            Clear();
+        m_updateFont = TRUE;
 
 
-            AppendText(value);
-        }
+        ChangeFontGlobally();
     }
 
     return TRUE;
 }
 
     }
 
     return TRUE;
 }
 
+void wxTextCtrl::ChangeFontGlobally()
+{
+    // this method is very inefficient and hence should be called as rarely as
+    // possible!
+    wxASSERT_MSG( (m_windowStyle & wxTE_MULTILINE) && m_updateFont,
+                  _T("shouldn't be called for single line controls") );
+
+    wxString value = GetValue();
+    if ( !value.IsEmpty() )
+    {
+        Clear();
+        AppendText(value);
+
+        m_updateFont = FALSE;
+    }
+}
+
+void wxTextCtrl::UpdateFontIfNeeded()
+{
+    if ( m_updateFont )
+        ChangeFontGlobally();
+}
+
 bool wxTextCtrl::SetForegroundColour( const wxColour &WXUNUSED(colour) )
 {
     wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
 bool wxTextCtrl::SetForegroundColour( const wxColour &WXUNUSED(colour) )
 {
     wxCHECK_MSG( m_text != NULL, FALSE, wxT("invalid text ctrl") );
@@ -948,11 +1022,11 @@ void wxTextCtrl::OnInternalIdle()
     if (cursor.Ok())
     {
         GdkWindow *window = (GdkWindow*) NULL;
     if (cursor.Ok())
     {
         GdkWindow *window = (GdkWindow*) NULL;
-       if (HasFlag(wxTE_MULTILINE))
+        if (HasFlag(wxTE_MULTILINE))
             window = GTK_TEXT(m_text)->text_area;
         else
             window = GTK_ENTRY(m_text)->text_area;
             window = GTK_TEXT(m_text)->text_area;
         else
             window = GTK_ENTRY(m_text)->text_area;
-           
+
         if (window)
             gdk_window_set_cursor( window, cursor.GetCursor() );
 
         if (window)
             gdk_window_set_cursor( window, cursor.GetCursor() );
 
@@ -963,4 +1037,13 @@ void wxTextCtrl::OnInternalIdle()
         if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
             gdk_window_set_cursor( window, cursor.GetCursor() );
     }
         if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
             gdk_window_set_cursor( window, cursor.GetCursor() );
     }
+
+    UpdateWindowUI();
+}
+
+wxSize wxTextCtrl::DoGetBestSize() const
+{
+    // FIXME should be different for multi-line controls...
+    wxSize ret( wxControl::DoGetBestSize() );
+    return wxSize(80, ret.y);
 }
 }