changed the code to be really sure that exactly one update event is sent when SetValue() is called

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@30781 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2004-11-25 14:43:54 +00:00
parent 034e304169
commit 2c62dd25cd
2 changed files with 64 additions and 41 deletions

View File

@ -247,9 +247,9 @@ protected:
int m_verRichEdit;
#endif // wxUSE_RICHEDIT
// if true, SendUpdateEvent() will eat the next event (see comments in the
// code as to why this is needed)
bool m_suppressNextUpdate;
// number of EN_UPDATE events sent by Windows when we change the controls
// text ourselves: we want this to be exactly 1
int m_updatesCount;
virtual wxVisualAttributes GetDefaultAttributes() const;

View File

@ -102,6 +102,36 @@ IMPLEMENT_DYNAMIC_CLASS(wxRichEditModule, wxModule)
#endif // wxUSE_RICHEDIT
// a small class used to set m_updatesCount to 0 (to filter duplicate events if
// necessary) and to reset it back to -1 afterwards
class UpdatesCountFilter
{
public:
UpdatesCountFilter(int& count)
: m_count(count)
{
wxASSERT_MSG( m_count == -1, _T("wrong initial m_updatesCount value") );
m_count = 0;
}
~UpdatesCountFilter()
{
m_count = -1;
}
// return true if an event has been received
bool GotUpdate() const
{
return m_count == 1;
}
private:
int& m_count;
DECLARE_NO_COPY_CLASS(UpdatesCountFilter)
};
// ----------------------------------------------------------------------------
// event tables and other macros
// ----------------------------------------------------------------------------
@ -218,7 +248,7 @@ void wxTextCtrl::Init()
#endif // wxUSE_RICHEDIT
m_privateContextMenu = NULL;
m_suppressNextUpdate = false;
m_updatesCount = -1;
m_isNativeCaretShown = true;
m_isCaretAtEnd = true;
}
@ -751,13 +781,8 @@ wxTextCtrl::StreamIn(const wxString& value,
// the cast below is needed for broken (very) old mingw32 headers
eds.pfnCallback = (EDITSTREAMCALLBACK)wxRichEditStreamIn;
// we're going to receive 2 EN_CHANGE notifications if we got any selection
// (same problem as in DoWriteText())
if ( selectionOnly && HasSelection() )
{
// so suppress one of them
m_suppressNextUpdate = true;
}
// same problem as in DoWriteText(): we can get multiple events here
UpdatesCountFilter ucf(m_updatesCount);
::SendMessage(GetHwnd(), EM_STREAMIN,
SF_TEXT |
@ -765,6 +790,8 @@ wxTextCtrl::StreamIn(const wxString& value,
(selectionOnly ? SFF_SELECTION : 0),
(LPARAM)&eds);
wxASSERT_MSG( ucf.GotUpdate(), _T("EM_STREAMIN didn't send EN_UPDATE?") );
if ( eds.dwError )
{
wxLogLastError(_T("EM_STREAMIN"));
@ -906,36 +933,20 @@ void wxTextCtrl::DoWriteText(const wxString& value, bool selectionOnly)
#endif // wxUSE_RICHEDIT
{
// in some cases we get 2 EN_CHANGE notifications after the SendMessage
// call below which is confusing for the client code and so should be
// avoided
//
// these cases are: (a) plain EDIT controls if EM_REPLACESEL is used
// and there is a non empty selection currently and (b) rich text
// controls in any case
if (
#if wxUSE_RICHEDIT
IsRich() ||
#endif // wxUSE_RICHEDIT
(selectionOnly && HasSelection()) )
{
m_suppressNextUpdate = true;
}
// call (this happens for plain EDITs with EM_REPLACESEL and under some
// -- undetermined -- conditions with rich edit) and sometimes we don't
// get any events at all (plain EDIT with WM_SETTEXT), so ensure that
// 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
UpdatesCountFilter ucf(m_updatesCount);
::SendMessage(GetHwnd(), selectionOnly ? EM_REPLACESEL : WM_SETTEXT,
0, (LPARAM)valueDos.c_str());
// OTOH, non rich text controls don't generate any events at all when
// we use WM_SETTEXT -- have to emulate them here
if ( !selectionOnly
#if wxUSE_RICHEDIT
&& !IsRich()
#endif // wxUSE_RICHEDIT
)
if ( !ucf.GotUpdate() )
{
// Windows already sends an update event for single-line
// controls.
if ( m_windowStyle & wxTE_MULTILINE )
SendUpdateEvent();
SendUpdateEvent();
}
}
}
@ -1801,13 +1812,25 @@ WXLRESULT wxTextCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPara
bool wxTextCtrl::SendUpdateEvent()
{
// is event reporting suspended?
if ( m_suppressNextUpdate )
switch ( m_updatesCount )
{
// do process the next one
m_suppressNextUpdate = false;
case 0:
// remember that we've got an update
m_updatesCount++;
break;
return false;
case 1:
// we had already sent one event since the last control modification
return false;
default:
wxFAIL_MSG( _T("unexpected wxTextCtrl::m_updatesCount value") );
// fall through
case -1:
// we hadn't updated the control ourselves, this event comes from
// the user, don't need to ignore it nor update the count
break;
}
wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId());