From f6519b40fe9f5e4706e02497fe01ff71c65079d6 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Sun, 8 Oct 2006 17:46:12 +0000
Subject: [PATCH] added wxTextCtrl::ChangeValue() which is the same as
 SetValue() but doesn't send the text changed event (first part of patch
 1553551)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41739 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/latex/wx/text.tex            | 26 ++++++++++++++++++--
 include/wx/cocoa/textctrl.h       |  2 ++
 include/wx/gtk/textctrl.h         | 11 ++++++---
 include/wx/gtk1/textctrl.h        |  6 ++++-
 include/wx/mac/carbon/textctrl.h  |  2 ++
 include/wx/motif/textctrl.h       |  5 +++-
 include/wx/msw/textctrl.h         |  7 ++++--
 include/wx/msw/wince/textctrlce.h |  8 ++++--
 include/wx/os2/textctrl.h         |  9 ++++++-
 include/wx/palmos/textctrl.h      |  2 ++
 include/wx/textctrl.h             | 14 +++++++++++
 include/wx/univ/textctrl.h        |  2 ++
 include/wx/x11/textctrl.h         |  5 +++-
 samples/text/text.cpp             |  2 +-
 src/gtk/textctrl.cpp              | 41 ++++++++++++++++++++++++-------
 src/gtk1/textctrl.cpp             |  8 +++++-
 src/mac/carbon/textctrl.cpp       |  9 +++++++
 src/motif/textctrl.cpp            |  2 +-
 src/msw/textctrl.cpp              | 30 ++++++++++++++++------
 src/msw/wince/textctrlce.cpp      | 16 ++++++------
 src/os2/textctrl.cpp              | 15 +++++++++--
 src/palmos/textctrl.cpp           |  4 +++
 src/univ/textctrl.cpp             |  8 ++++--
 src/x11/textctrl.cpp              |  2 +-
 24 files changed, 191 insertions(+), 45 deletions(-)

diff --git a/docs/latex/wx/text.tex b/docs/latex/wx/text.tex
index 8b3f029567..4dc8df61a5 100644
--- a/docs/latex/wx/text.tex
+++ b/docs/latex/wx/text.tex
@@ -218,9 +218,10 @@ functions that take a \helpref{wxCommandEvent}{wxcommandevent} argument.
 \twocolwidtha{7cm}%
 \begin{twocollist}\itemsep=0pt
 \twocolitem{{\bf EVT\_TEXT(id, func)}}{Respond to a wxEVT\_COMMAND\_TEXT\_UPDATED event,
-generated when the text changes. Notice that this event will always be sent
+generated when the text changes. Notice that this event will be sent
 when the text controls contents changes - whether this is due to user input or
-comes from the program itself (for example, if SetValue() is called)}
+comes from the program itself (for example, if SetValue() is called); see ChangeValue() for
+a function which does not send this event.}
 \twocolitem{{\bf EVT\_TEXT\_ENTER(id, func)}}{Respond to a wxEVT\_COMMAND\_TEXT\_ENTER event,
 generated when enter is pressed in a text control (which must have
 wxTE\_PROCESS\_ENTER style for this event to be generated).}
@@ -973,6 +974,27 @@ after the call to SetValue).
 Note that this function will generate a {\tt wxEVT\_COMMAND\_TEXT\_UPDATED}
 event.
 
+This function is deprecated and should not be used in new code. Please use the
+\helpref{ChangeValue}{wxtextctrlchangevalue} function instead.
+
+\wxheading{Parameters}
+
+\docparam{value}{The new value to set. It may contain newline characters if the text control is multi-line.}
+
+
+\membersection{wxTextCtrl::ChangeValue}\label{wxtextctrlchangevalue}
+
+\func{virtual void}{ChangeValue}{\param{const wxString\& }{ value}}
+
+Sets the text value and marks the control as not-modified (which means that
+\helpref{IsModified}{wxtextctrlismodified} would return {\tt false} immediately
+after the call to SetValue).
+
+Note that this function will \emph{not} generate the {\tt wxEVT\_COMMAND\_TEXT\_UPDATED} 
+event.
+This is the only difference with \helpref{SetValue}{wxtextctrlsetvalue}.
+See \helpref{this topic}{progevent} for more info.
+
 \wxheading{Parameters}
 
 \docparam{value}{The new value to set. It may contain newline characters if the text control is multi-line.}
diff --git a/include/wx/cocoa/textctrl.h b/include/wx/cocoa/textctrl.h
index 3746fc6a67..f6ea42dd6e 100644
--- a/include/wx/cocoa/textctrl.h
+++ b/include/wx/cocoa/textctrl.h
@@ -57,6 +57,8 @@ public:
     virtual wxString GetValue() const;
     virtual void SetValue(const wxString& value);
 
+    virtual void ChangeValue(const wxString &value);
+
     virtual int GetLineLength(long lineNo) const;
     virtual wxString GetLineText(long lineNo) const;
     virtual int GetNumberOfLines() const;
diff --git a/include/wx/gtk/textctrl.h b/include/wx/gtk/textctrl.h
index 17c7006d41..8cde769c6b 100644
--- a/include/wx/gtk/textctrl.h
+++ b/include/wx/gtk/textctrl.h
@@ -43,7 +43,9 @@ public:
     // ----------------------------------
 
     virtual wxString GetValue() const;
-    virtual void SetValue(const wxString& value);
+    virtual void SetValue(const wxString& value) { DoSetValue(value, SetValue_SendEvent); }
+
+    virtual void ChangeValue(const wxString &value) { DoSetValue(value); }
 
     virtual int GetLineLength(long lineNo) const;
     virtual wxString GetLineText(long lineNo) const;
@@ -155,7 +157,7 @@ public:
     virtual void OnParentEnable( bool enable ) ;
 
     // tell the control to ignore next text changed signal
-    void IgnoreNextTextUpdate() { m_ignoreNextUpdate = true; }
+    void IgnoreNextTextUpdate(int n = 1) { m_countUpdatesToIgnore = n; }
 
     // should we ignore the changed signal? always resets the flag
     bool IgnoreTextUpdate();
@@ -189,6 +191,8 @@ protected:
     // has the control been frozen by Freeze()?
     bool IsFrozen() const { return m_frozenness > 0; }
 
+    void DoSetValue(const wxString &value, int flags = 0);
+
 private:
     // change the font for everything in this control
     void ChangeFontGlobally();
@@ -203,9 +207,10 @@ private:
     GtkWidget  *m_text;
 
     bool        m_modified:1;
-    bool        m_ignoreNextUpdate:1;
     bool        m_dontMarkDirty:1;
 
+    int         m_countUpdatesToIgnore;
+
     // Our text buffer. Convenient, and holds the buffer while using
     // a dummy one when m_frozenness > 0
     GtkTextBuffer *m_buffer;
diff --git a/include/wx/gtk1/textctrl.h b/include/wx/gtk1/textctrl.h
index c34e71de27..8c8f3dec07 100644
--- a/include/wx/gtk1/textctrl.h
+++ b/include/wx/gtk1/textctrl.h
@@ -43,7 +43,9 @@ public:
     // ----------------------------------
 
     virtual wxString GetValue() const;
-    virtual void SetValue(const wxString& value);
+    virtual void SetValue(const wxString& value) { DoSetValue(value, SetValue_SendEvent); }
+
+    virtual void ChangeValue(const wxString &value) { DoSetValue(value); }
 
     virtual int GetLineLength(long lineNo) const;
     virtual wxString GetLineText(long lineNo) const;
@@ -182,6 +184,8 @@ protected:
     // override this and return true.
     virtual bool UseGTKStyleBase() const { return true; }
 
+    void DoSetValue(const wxString &value, int flags = 0);
+
 private:
     // change the font for everything in this control
     void ChangeFontGlobally();
diff --git a/include/wx/mac/carbon/textctrl.h b/include/wx/mac/carbon/textctrl.h
index db4dbe7985..f77e41423a 100644
--- a/include/wx/mac/carbon/textctrl.h
+++ b/include/wx/mac/carbon/textctrl.h
@@ -63,6 +63,8 @@ public:
     virtual wxString GetValue() const;
     virtual void SetValue(const wxString& value);
 
+    virtual void ChangeValue(const wxString &value);
+
     virtual int GetLineLength(long lineNo) const;
     virtual wxString GetLineText(long lineNo) const;
     virtual int GetNumberOfLines() const;
diff --git a/include/wx/motif/textctrl.h b/include/wx/motif/textctrl.h
index ed4f480c05..3fdfa7ee31 100644
--- a/include/wx/motif/textctrl.h
+++ b/include/wx/motif/textctrl.h
@@ -43,7 +43,10 @@ public:
     // accessors
     // ---------
     virtual wxString GetValue() const;
-    virtual void SetValue(const wxString& value);
+    virtual void SetValue(const wxString& value)
+        { ChangeValue(value); SendTextUpdatedEvent(); }
+
+    virtual void ChangeValue(const wxString &value);
 
     virtual int GetLineLength(long lineNo) const;
     virtual wxString GetLineText(long lineNo) const;
diff --git a/include/wx/msw/textctrl.h b/include/wx/msw/textctrl.h
index 2988ed08df..dee8fd0bbe 100644
--- a/include/wx/msw/textctrl.h
+++ b/include/wx/msw/textctrl.h
@@ -45,7 +45,8 @@ public:
     // ----------------------------------
 
     virtual wxString GetValue() const;
-    virtual void SetValue(const wxString& value);
+    virtual void SetValue(const wxString& value) { DoSetValue(value, SetValue_SendEvent); }
+    virtual void ChangeValue(const wxString &value) { DoSetValue(value); }
 
     virtual wxString GetRange(long from, long to) const;
 
@@ -207,6 +208,8 @@ protected:
     // common part of all ctors
     void Init();
 
+    void DoSetValue(const wxString &value, int flags = 0);
+
     // return true if this control has a user-set limit on amount of text (i.e.
     // the limit is due to a previous call to SetMaxLength() and not built in)
     bool HasSpaceLimit(unsigned int *len) const;
@@ -229,7 +232,7 @@ protected:
 
     // replace the contents of the selection or of the entire control with the
     // given text
-    void DoWriteText(const wxString& text, bool selectionOnly = true);
+    void DoWriteText(const wxString& text, int flags = SetValue_SelectionOnly);
 
     // set the selection possibly without scrolling the caret into view
     void DoSetSelection(long from, long to, bool scrollCaret = true);
diff --git a/include/wx/msw/wince/textctrlce.h b/include/wx/msw/wince/textctrlce.h
index 0ed278f7cd..259a3daadb 100644
--- a/include/wx/msw/wince/textctrlce.h
+++ b/include/wx/msw/wince/textctrlce.h
@@ -50,7 +50,9 @@ public:
     // ----------------------------------
 
     virtual wxString GetValue() const;
-    virtual void SetValue(const wxString& value);
+    virtual void SetValue(const wxString& value) { DoSetValue(value, SetValue_SendEvent); }
+
+    virtual void ChangeValue(const wxString &value) { DoSetValue(value); }
 
     virtual wxString GetRange(long from, long to) const;
 
@@ -185,9 +187,11 @@ protected:
     // false if we hit the limit set by SetMaxLength() and so didn't change it
     bool AdjustSpaceLimit();
 
+    void DoSetValue(const wxString &value, int flags = 0);
+
     // replace the contents of the selection or of the entire control with the
     // given text
-    void DoWriteText(const wxString& text, bool selectionOnly = true);
+    void DoWriteText(const wxString& text, int flags = SetValue_SelectionOnly);
 
     // set the selection possibly without scrolling the caret into view
     void DoSetSelection(long from, long to, bool scrollCaret = true);
diff --git a/include/wx/os2/textctrl.h b/include/wx/os2/textctrl.h
index 81085c80a3..e6197dd8fd 100644
--- a/include/wx/os2/textctrl.h
+++ b/include/wx/os2/textctrl.h
@@ -47,7 +47,9 @@ public:
     // ----------------------------------
     //
     virtual      wxString GetValue(void) const;
-    virtual void SetValue(const wxString& rsValue);
+    virtual void SetValue(const wxString& value) { DoSetValue(value, SetValue_SendEvent); }
+
+    virtual void ChangeValue(const wxString &value) { DoSetValue(value); }
 
     virtual int      GetLineLength(long nLineNo) const;
     virtual wxString GetLineText(long nLineNo) const;
@@ -180,6 +182,11 @@ protected:
     virtual WXDWORD OS2GetStyle( long     lStyle
                                 ,WXDWORD* dwExstyle
                                ) const;
+
+    void DoSetValue(const wxString &value, int flags = 0);
+
+    bool m_bSkipUpdate;
+
 private:
     bool                            m_bIsMLE;
     DECLARE_EVENT_TABLE()
diff --git a/include/wx/palmos/textctrl.h b/include/wx/palmos/textctrl.h
index 6b1bb1ba54..bfb5c9b663 100644
--- a/include/wx/palmos/textctrl.h
+++ b/include/wx/palmos/textctrl.h
@@ -47,6 +47,8 @@ public:
     virtual wxString GetValue() const;
     virtual void SetValue(const wxString& value);
 
+    virtual void ChangeValue(const wxString &value);
+
     virtual int GetLineLength(long lineNo) const;
     virtual wxString GetLineText(long lineNo) const;
     virtual int GetNumberOfLines() const;
diff --git a/include/wx/textctrl.h b/include/wx/textctrl.h
index 204c28b7df..172301b6ad 100644
--- a/include/wx/textctrl.h
+++ b/include/wx/textctrl.h
@@ -300,6 +300,8 @@ public:
     virtual wxString GetValue() const = 0;
     virtual void SetValue(const wxString& value) = 0;
 
+    virtual void ChangeValue(const wxString &value) = 0;
+
     virtual wxString GetRange(long from, long to) const;
 
     virtual int GetLineLength(long lineNo) const = 0;
@@ -429,6 +431,18 @@ protected:
     int overflow(int i);
 #endif // wxHAS_TEXT_WINDOW_STREAM
 
+    // typically, wxTextCtrl classes will use a DoSetValue() function to
+    // implement both SetValue() and ChangeValue() functions and these
+    // flags are meant to be passed to such DoSetValue()
+    enum
+    {
+        SetValue_SendEvent = 1,
+        SetValue_SelectionOnly = 2
+    };
+
+    // generate the wxEVT_COMMAND_TEXT_UPDATED event
+    void SendTextUpdatedEvent();
+
     // the name of the last file loaded with LoadFile() which will be used by
     // SaveFile() by default
     wxString m_filename;
diff --git a/include/wx/univ/textctrl.h b/include/wx/univ/textctrl.h
index 018454e8f9..2ec12ca172 100644
--- a/include/wx/univ/textctrl.h
+++ b/include/wx/univ/textctrl.h
@@ -107,6 +107,8 @@ public:
     virtual wxString GetValue() const;
     virtual void SetValue(const wxString& value);
 
+    virtual void ChangeValue(const wxString &value);
+
     virtual int GetLineLength(wxTextCoord lineNo) const;
     virtual wxString GetLineText(wxTextCoord lineNo) const;
     virtual int GetNumberOfLines() const;
diff --git a/include/wx/x11/textctrl.h b/include/wx/x11/textctrl.h
index 197acb64b5..f201439b07 100644
--- a/include/wx/x11/textctrl.h
+++ b/include/wx/x11/textctrl.h
@@ -117,7 +117,10 @@ public:
     // ----------------------------------
 
     virtual wxString GetValue() const;
-    virtual void SetValue(const wxString& value);
+    virtual void SetValue(const wxString& value)
+        { ChangeValue(value); SendTextUpdatedEvent(); }
+
+    virtual void ChangeValue(const wxString &value);
 
     virtual int GetLineLength(long lineNo) const;
     virtual wxString GetLineText(long lineNo) const;
diff --git a/samples/text/text.cpp b/samples/text/text.cpp
index 87c2a6d6b1..525a21e2dd 100644
--- a/samples/text/text.cpp
+++ b/samples/text/text.cpp
@@ -947,7 +947,7 @@ void MyTextCtrl::OnKeyDown(wxKeyEvent& event)
         case WXK_F6:
             wxLogMessage(_T("IsModified() before SetValue(): %d"),
                          IsModified());
-            SetValue(_T("SetValue() has been called"));
+            ChangeValue(_T("ChangeValue() has been called"));
             wxLogMessage(_T("IsModified() after SetValue(): %d"),
                          IsModified());
             break;
diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp
index 79cdce6465..f10fd64e01 100644
--- a/src/gtk/textctrl.cpp
+++ b/src/gtk/textctrl.cpp
@@ -544,9 +544,10 @@ END_EVENT_TABLE()
 void wxTextCtrl::Init()
 {
     m_dontMarkDirty =
-    m_ignoreNextUpdate =
     m_modified = false;
 
+    m_countUpdatesToIgnore = 0;
+
     SetUpdateFont(false);
 
     m_text = NULL;
@@ -820,7 +821,7 @@ wxFontEncoding wxTextCtrl::GetTextEncoding() const
     return enc;
 }
 
-void wxTextCtrl::SetValue( const wxString &value )
+void wxTextCtrl::DoSetValue( const wxString &value, int flags )
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
@@ -842,8 +843,20 @@ void wxTextCtrl::SetValue( const wxString &value )
             return;
         }
 
-        if (gtk_text_buffer_get_char_count(m_buffer) != 0)
-            IgnoreNextTextUpdate();
+
+        // if the control is not empty, two "changed" signals are emitted
+        if ( flags & SetValue_SendEvent )
+        {
+            if ( gtk_text_buffer_get_char_count(m_buffer) != 0 )
+                IgnoreNextTextUpdate();
+        }
+        else
+        {
+            if ( gtk_text_buffer_get_char_count(m_buffer) != 0 )
+                IgnoreNextTextUpdate(2);
+            else
+                IgnoreNextTextUpdate(1);        // skip only one
+        }
 
         gtk_text_buffer_set_text( m_buffer, buffer, strlen(buffer) );
     }
@@ -851,9 +864,19 @@ void wxTextCtrl::SetValue( const wxString &value )
     {
         // gtk_entry_set_text() emits two "changed" signals if the control is
         // not empty because internally it calls gtk_editable_delete_text() and
-        // gtk_editable_insert_text() but we want to have only one event
-        if ( !GetValue().empty() )
-            IgnoreNextTextUpdate();
+        // gtk_editable_insert_text()
+        if ( flags & SetValue_SendEvent )
+        {
+            if ( !GetValue().empty() )
+                IgnoreNextTextUpdate();
+        }
+        else
+        {
+            if ( !GetValue().empty() )
+                IgnoreNextTextUpdate(2);
+            else
+                IgnoreNextTextUpdate(1);        // if we are empty, skip only one event
+        }
 
         gtk_entry_set_text( GTK_ENTRY(m_text), wxGTK_CONV(value) );
     }
@@ -1178,9 +1201,9 @@ void wxTextCtrl::DiscardEdits()
 
 bool wxTextCtrl::IgnoreTextUpdate()
 {
-    if ( m_ignoreNextUpdate )
+    if ( m_countUpdatesToIgnore > 0 )
     {
-        m_ignoreNextUpdate = false;
+        m_countUpdatesToIgnore--;
 
         return true;
     }
diff --git a/src/gtk1/textctrl.cpp b/src/gtk1/textctrl.cpp
index ca95f24fff..147486f864 100644
--- a/src/gtk1/textctrl.cpp
+++ b/src/gtk1/textctrl.cpp
@@ -412,10 +412,16 @@ wxString wxTextCtrl::GetValue() const
     return tmp;
 }
 
-void wxTextCtrl::SetValue( const wxString &value )
+void wxTextCtrl::DoSetValue( const wxString &value, int flags )
 {
     wxCHECK_RET( m_text != NULL, wxT("invalid text ctrl") );
 
+    if ( !(flags & SetValue_SendEvent) )
+    {
+        // do not generate events
+        IgnoreNextTextUpdate();
+    }
+
     if (m_windowStyle & wxTE_MULTILINE)
     {
         gint len = gtk_text_get_length( GTK_TEXT(m_text) );
diff --git a/src/mac/carbon/textctrl.cpp b/src/mac/carbon/textctrl.cpp
index 3ee3663952..bd00109085 100644
--- a/src/mac/carbon/textctrl.cpp
+++ b/src/mac/carbon/textctrl.cpp
@@ -564,6 +564,15 @@ void wxTextCtrl::SetValue(const wxString& str)
     }
 }
 
+void wxTextCtrl::ChangeValue(const wxString& str)
+{
+    // optimize redraws
+    if ( GetValue() == str )
+        return ;
+
+    GetPeer()->SetStringValue( str ) ;
+}
+
 void wxTextCtrl::SetMaxLength(unsigned long len)
 {
     m_maxLength = len ;
diff --git a/src/motif/textctrl.cpp b/src/motif/textctrl.cpp
index a74fc61d97..d09a620465 100644
--- a/src/motif/textctrl.cpp
+++ b/src/motif/textctrl.cpp
@@ -240,7 +240,7 @@ wxString wxTextCtrl::GetValue() const
     return str;
 }
 
-void wxTextCtrl::SetValue(const wxString& text)
+void wxTextCtrl::ChangeValue(const wxString& text)
 {
     m_inSetValue = true;
 
diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp
index 5db4094a34..a71654a1ec 100644
--- a/src/msw/textctrl.cpp
+++ b/src/msw/textctrl.cpp
@@ -134,9 +134,13 @@ public:
     UpdatesCountFilter(int& count)
         : m_count(count)
     {
-        wxASSERT_MSG( m_count == -1, _T("wrong initial m_updatesCount value") );
+        wxASSERT_MSG( m_count == -1 || m_count == -2,
+                      _T("wrong initial m_updatesCount value") );
 
-        m_count = 0;
+        if (m_count != -2)
+            m_count = 0;
+        //else: we don't want to count how many update events we get as we're going
+        //      to ignore all of them
     }
 
     ~UpdatesCountFilter()
@@ -781,7 +785,7 @@ wxString wxTextCtrl::GetRange(long from, long to) const
     return str;
 }
 
-void wxTextCtrl::SetValue(const wxString& value)
+void wxTextCtrl::DoSetValue(const wxString& value, int flags)
 {
     // if the text is long enough, it's faster to just set it instead of first
     // comparing it with the old one (chances are that it will be different
@@ -789,7 +793,7 @@ void wxTextCtrl::SetValue(const wxString& value)
     // edit controls mostly)
     if ( (value.length() > 0x400) || (value != GetValue()) )
     {
-        DoWriteText(value, false /* not selection only */);
+        DoWriteText(value, flags);
 
         // mark the control as being not dirty - we changed its text, not the
         // user
@@ -807,7 +811,8 @@ void wxTextCtrl::SetValue(const wxString& value)
         DiscardEdits();
 
         // still send an event for consistency
-        SendUpdateEvent();
+        if (flags & SetValue_SendEvent)
+            SendUpdateEvent();
     }
 }
 
@@ -1005,8 +1010,9 @@ void wxTextCtrl::WriteText(const wxString& value)
     DoWriteText(value);
 }
 
-void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
+void wxTextCtrl::DoWriteText(const wxString& value, int flags)
 {
+    bool selectionOnly = (flags & SetValue_SelectionOnly) != 0;
     wxString valueDos;
     if ( m_windowStyle & wxTE_MULTILINE )
         valueDos = wxTextFile::Translate(value, wxTextFileType_Dos);
@@ -1070,13 +1076,16 @@ void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
         // we generate exactly one of them by ignoring all but the first one in
         // SendUpdateEvent() and generating one ourselves if we hadn't got any
         // notifications from Windows
+        if ( !(flags & SetValue_SendEvent) )
+            m_updatesCount = -2;        // suppress any update event
+
         UpdatesCountFilter ucf(m_updatesCount);
 
         ::SendMessage(GetHwnd(), selectionOnly ? EM_REPLACESEL : WM_SETTEXT,
                       // EM_REPLACESEL takes 1 to indicate the operation should be redoable
                       selectionOnly ? 1 : 0, (LPARAM)valueDos.c_str());
 
-        if ( !ucf.GotUpdate() )
+        if ( !ucf.GotUpdate() && (flags & SetValue_SendEvent) )
         {
             SendUpdateEvent();
         }
@@ -1427,7 +1436,7 @@ void wxTextCtrl::Replace(long from, long to, const wxString& value)
     // Set selection and remove it
     DoSetSelection(from, to, false /* don't scroll caret into view */);
 
-    DoWriteText(value, true /* selection only */);
+    DoWriteText(value, SetValue_SelectionOnly);
 }
 
 void wxTextCtrl::Remove(long from, long to)
@@ -1971,6 +1980,11 @@ bool wxTextCtrl::SendUpdateEvent()
             // we hadn't updated the control ourselves, this event comes from
             // the user, don't need to ignore it nor update the count
             break;
+
+        case -2:
+            // the control was updated programmatically and we do NOT want to
+            // send events
+            return false;
     }
 
     wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());
diff --git a/src/msw/wince/textctrlce.cpp b/src/msw/wince/textctrlce.cpp
index abea606670..1a83ef5cb3 100644
--- a/src/msw/wince/textctrlce.cpp
+++ b/src/msw/wince/textctrlce.cpp
@@ -393,7 +393,7 @@ wxString wxTextCtrl::GetRange(long from, long to) const
     return str;
 }
 
-void wxTextCtrl::SetValue(const wxString& value)
+void wxTextCtrl::DoSetValue(const wxString& value, int flags)
 {
     // if the text is long enough, it's faster to just set it instead of first
     // comparing it with the old one (chances are that it will be different
@@ -401,7 +401,7 @@ void wxTextCtrl::SetValue(const wxString& value)
     // edit controls mostly)
     if ( (value.length() > 0x400) || (value != GetValue()) )
     {
-        DoWriteText(value, false);
+        DoWriteText(value, flags);
 
         // for compatibility, don't move the cursor when doing SetValue()
         SetInsertionPoint(0);
@@ -409,7 +409,8 @@ void wxTextCtrl::SetValue(const wxString& value)
     else // same text
     {
         // still send an event for consistency
-        SendUpdateEvent();
+        if ( flags & SetValue_SendEvent )
+            SendUpdateEvent();
     }
 
     // we should reset the modified flag even if the value didn't really change
@@ -424,8 +425,9 @@ void wxTextCtrl::WriteText(const wxString& value)
     DoWriteText(value);
 }
 
-void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
+void wxTextCtrl::DoWriteText(const wxString& value, int flags)
 {
+    bool selectionOnly = (flags & SetValue_SelectionOnly) != 0;
     wxString valueDos;
     if ( m_windowStyle & wxTE_MULTILINE )
         valueDos = wxTextFile::Translate(value, wxTextFileType_Dos);
@@ -436,7 +438,7 @@ void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
     // call below which is confusing for the client code and so should be
     // avoided
     //
-    if ( ( selectionOnly && HasSelection() ) )
+    if ( selectionOnly && HasSelection() )
     {
         m_suppressNextUpdate = true;
     }
@@ -444,7 +446,7 @@ void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
     ::SendMessage(GetBuddyHwnd(), selectionOnly ? EM_REPLACESEL : WM_SETTEXT,
                   0, (LPARAM)valueDos.c_str());
 
-    if ( !selectionOnly )
+    if ( !selectionOnly && !( flags & SetValue_SendEvent ) )
     {
         // Windows already sends an update event for single-line
         // controls.
@@ -641,7 +643,7 @@ void wxTextCtrl::Replace(long from, long to, const wxString& value)
     // Set selection and remove it
     DoSetSelection(from, to, false);
 
-    DoWriteText(value, true);
+    DoWriteText(value, SetValue_SelectionOnly);
 }
 
 void wxTextCtrl::Remove(long from, long to)
diff --git a/src/os2/textctrl.cpp b/src/os2/textctrl.cpp
index f5ac61433c..111a63165b 100644
--- a/src/os2/textctrl.cpp
+++ b/src/os2/textctrl.cpp
@@ -125,6 +125,7 @@ bool wxTextCtrl::Create(
 
     m_windowStyle = lStyle;
     m_bIsMLE = false;
+    m_bSkipUpdate = false;
 
     long                            lSstyle = WS_VISIBLE | WS_TABSTOP;
 
@@ -343,8 +344,9 @@ wxString wxTextCtrl::GetValue() const
     return sStr;
 } // end of wxTextCtrl::GetValue
 
-void wxTextCtrl::SetValue(
-  const wxString&                   rsValue
+void wxTextCtrl::DoSetValue(
+  const wxString&                   rsValue,
+  int flags
 )
 {
     //
@@ -355,6 +357,9 @@ void wxTextCtrl::SetValue(
     //
     if ((rsValue.length() > 0x400) || (rsValue != GetValue()))
     {
+        if ( flags & SetValue_SendEvent )
+            m_bSkipUpdate = true;
+
         ::WinSetWindowText(GetHwnd(), (PSZ)rsValue.c_str());
         AdjustSpaceLimit();
     }
@@ -1095,6 +1100,12 @@ bool wxTextCtrl::OS2Command(
 
         case EN_CHANGE:
             {
+                if (m_bSkipUpdate)
+                {
+                    m_bSkipUpdate = false;
+                    break;
+                }
+
                 wxCommandEvent      vEvent( wxEVT_COMMAND_TEXT_UPDATED
                                            ,m_windowId
                                           );
diff --git a/src/palmos/textctrl.cpp b/src/palmos/textctrl.cpp
index b27b0c5f3b..7302a7fe63 100644
--- a/src/palmos/textctrl.cpp
+++ b/src/palmos/textctrl.cpp
@@ -233,6 +233,10 @@ void wxTextCtrl::SetValue(const wxString& value)
 {
 }
 
+void wxTextCtrl::ChangeValue(const wxString& value)
+{
+}
+
 #if wxUSE_RICHEDIT && (!wxUSE_UNICODE || wxUSE_UNICODE_MSLU)
 
 // TODO: using memcpy() would improve performance a lot for big amounts of text
diff --git a/src/univ/textctrl.cpp b/src/univ/textctrl.cpp
index 5dc742581b..17ed256745 100644
--- a/src/univ/textctrl.cpp
+++ b/src/univ/textctrl.cpp
@@ -778,7 +778,7 @@ wxTextCtrl::~wxTextCtrl()
 // set/get the value
 // ----------------------------------------------------------------------------
 
-void wxTextCtrl::SetValue(const wxString& value)
+void wxTextCtrl::ChangeValue(const wxString& value)
 {
     if ( IsSingleLine() && (value == GetValue()) )
     {
@@ -792,8 +792,12 @@ void wxTextCtrl::SetValue(const wxString& value)
     {
         SetInsertionPoint(0);
     }
+}
 
-    // TODO: should we generate the event or not, finally?
+void wxTextCtrl::SetValue(const wxString& value)
+{
+    ChangeValue(value);
+    SendTextUpdatedEvent();
 }
 
 const wxArrayString& wxTextCtrl::GetLines() const
diff --git a/src/x11/textctrl.cpp b/src/x11/textctrl.cpp
index fdb7008a89..8f8aa99e48 100644
--- a/src/x11/textctrl.cpp
+++ b/src/x11/textctrl.cpp
@@ -277,7 +277,7 @@ wxString wxTextCtrl::GetValue() const
     return ret;
 }
 
-void wxTextCtrl::SetValue(const wxString& value)
+void wxTextCtrl::ChangeValue(const wxString& value)
 {
     m_modified = false;
 
-- 
2.45.2

