Fix wxTextCtrl contents corruption with long strings in wxMSW.
wxMSW automatically extended wxTextCtrl length limit beyond the tiny standard 32KB when it was exceeded, but part of the text being appended into the control was lost when doing it. Fix this by retrying insertion after extending the limit. Closes #15980. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@75940 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
parent
43f960c9e1
commit
81b62354dc
@ -173,6 +173,20 @@ private:
|
||||
wxDECLARE_NO_COPY_CLASS(UpdatesCountFilter);
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// The length of the text being currently inserted into the control.
|
||||
//
|
||||
// This is used to pass information from DoWriteText() to AdjustSpaceLimit()
|
||||
// and is global as text can only be inserted into one text control at a time
|
||||
// by a single thread and this operation can only be done from the main thread
|
||||
// (and we don't want to waste space in every wxTextCtrl object for this field
|
||||
// unnecessarily).
|
||||
int gs_lenOfInsertedText = 0;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// event tables and other macros
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -1137,10 +1151,33 @@ void wxTextCtrl::DoWriteText(const wxString& value, int flags)
|
||||
|
||||
UpdatesCountFilter ucf(m_updatesCount);
|
||||
|
||||
// Remember the length of the text we're inserting so that
|
||||
// AdjustSpaceLimit() could adjust the limit to be big enough for it:
|
||||
// and also signal us whether it did it by resetting it to 0.
|
||||
gs_lenOfInsertedText = valueDos.length();
|
||||
|
||||
::SendMessage(GetHwnd(), selectionOnly ? EM_REPLACESEL : WM_SETTEXT,
|
||||
// EM_REPLACESEL takes 1 to indicate the operation should be redoable
|
||||
selectionOnly ? 1 : 0, wxMSW_CONV_LPARAM(valueDos));
|
||||
|
||||
if ( !gs_lenOfInsertedText )
|
||||
{
|
||||
// Text size limit has been hit and added text has been truncated.
|
||||
// But the max length has been increased by the EN_MAXTEXT message
|
||||
// handler, which also reset gs_lenOfInsertedText to 0), so we
|
||||
// should be able to set it successfully now if we try again.
|
||||
if ( selectionOnly )
|
||||
Undo();
|
||||
|
||||
::SendMessage(GetHwnd(), selectionOnly ? EM_REPLACESEL : WM_SETTEXT,
|
||||
selectionOnly ? 1 : 0, wxMSW_CONV_LPARAM(valueDos));
|
||||
}
|
||||
else
|
||||
{
|
||||
// EN_MAXTEXT handler wasn't called, so reset the flag ourselves.
|
||||
gs_lenOfInsertedText = 0;
|
||||
}
|
||||
|
||||
if ( !ucf.GotUpdate() && (flags & SetValue_SendEvent) )
|
||||
{
|
||||
SendUpdateEvent();
|
||||
@ -2119,8 +2156,22 @@ bool wxTextCtrl::AdjustSpaceLimit()
|
||||
unsigned int len = ::GetWindowTextLength(GetHwnd());
|
||||
if ( len >= limit )
|
||||
{
|
||||
// increment in 32Kb chunks
|
||||
SetMaxLength(len + 0x8000);
|
||||
// We need to increase the size of the buffer and to avoid increasing
|
||||
// it too many times make sure that we make it at least big enough to
|
||||
// fit all the text we are currently inserting into the control.
|
||||
unsigned long increaseBy = gs_lenOfInsertedText;
|
||||
|
||||
// Don't let it affect any future unrelated calls to this function.
|
||||
gs_lenOfInsertedText = 0;
|
||||
|
||||
// But also increase it by at least 32KB chunks -- again, to avoid
|
||||
// doing it too often -- and round it up to 32KB in any case.
|
||||
if ( increaseBy < 0x8000 )
|
||||
increaseBy = 0x8000;
|
||||
else
|
||||
increaseBy = (increaseBy + 0x7fff) & ~0x7fff;
|
||||
|
||||
SetMaxLength(len + increaseBy);
|
||||
}
|
||||
|
||||
// we changed the limit
|
||||
|
@ -85,6 +85,7 @@ private:
|
||||
CPPUNIT_TEST( FontStyle );
|
||||
CPPUNIT_TEST( Lines );
|
||||
CPPUNIT_TEST( LogTextCtrl );
|
||||
CPPUNIT_TEST( LongText );
|
||||
CPPUNIT_TEST( PositionToCoords );
|
||||
CPPUNIT_TEST( PositionToCoordsRich );
|
||||
CPPUNIT_TEST( PositionToCoordsRich2 );
|
||||
@ -106,6 +107,7 @@ private:
|
||||
void FontStyle();
|
||||
void Lines();
|
||||
void LogTextCtrl();
|
||||
void LongText();
|
||||
void PositionToCoords();
|
||||
void PositionToCoordsRich();
|
||||
void PositionToCoordsRich2();
|
||||
@ -521,6 +523,36 @@ void TextCtrlTestCase::LogTextCtrl()
|
||||
CPPUNIT_ASSERT(!m_text->IsEmpty());
|
||||
}
|
||||
|
||||
void TextCtrlTestCase::LongText()
|
||||
{
|
||||
delete m_text;
|
||||
CreateText(wxTE_MULTILINE|wxTE_DONTWRAP);
|
||||
|
||||
// Pattern for the line.
|
||||
wxChar linePattern[100+1];
|
||||
for (int i = 0; i < WXSIZEOF(linePattern) - 1; i++)
|
||||
{
|
||||
linePattern[i] = wxChar('0' + i % 10);
|
||||
}
|
||||
linePattern[WXSIZEOF(linePattern) - 1] = wxChar('\0');
|
||||
|
||||
// Fill the control.
|
||||
const int numLines = 1000;
|
||||
m_text->SetMaxLength(15000);
|
||||
for (int i = 0; i < numLines; i++)
|
||||
{
|
||||
m_text->AppendText(wxString::Format(wxT("[%3d] %s\n"), i, linePattern));
|
||||
}
|
||||
|
||||
// Check the content.
|
||||
for (int i = 0; i < numLines; i++)
|
||||
{
|
||||
wxString pattern = wxString::Format(wxT("[%3d] %s"), i, linePattern);
|
||||
wxString line = m_text->GetLineText(i);
|
||||
CPPUNIT_ASSERT_EQUAL( line, pattern );
|
||||
}
|
||||
}
|
||||
|
||||
void TextCtrlTestCase::PositionToCoords()
|
||||
{
|
||||
DoPositionToCoordsTestWithStyle(0);
|
||||
|
Loading…
Reference in New Issue
Block a user