wxTextCtrl::Replace() seems to work

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/branches/wxUNIVERSAL@8560 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2000-10-15 16:52:52 +00:00
parent 649850e16c
commit 6dbe10e7a6
2 changed files with 220 additions and 89 deletions

View File

@@ -268,7 +268,7 @@ protected:
// refresh the text from in the given line range (inclusive), if lineLast
// is -1, refresh all [visible] text after the lineFirst
void RefreshLineRange(long lineFirst, long lineLast = 0);
void RefreshLineRange(long lineFirst, long lineLast = -1);
// refresh the text in the given range which can span multiple lines
// (this method accepts arguments in any order)

View File

@@ -11,6 +11,12 @@
/*
Search for "OPT" for possible optimizations
Possible optimization would be to always store the coords in the text in
triplets (pos, col, line) and update them simultaneously instead of
recalculating col and line from pos each time it is needed. Currently we
only do it for the current position but we might also do it for the
selection start and end.
*/
// ============================================================================
@@ -41,9 +47,9 @@
#include "wx/textctrl.h"
#endif
#include "wx/tokenzr.h"
#include "wx/clipbrd.h"
#include "wx/textfile.h"
#include "wx/tokenzr.h"
#include "wx/caret.h"
@@ -201,29 +207,6 @@ void wxTextCtrl::Clear()
SetValue(_T(""));
}
/*
The algorithm of Replace():
1. change the line where replacement starts
a) keep the text in the beginning of it unchanged
b) replace the middle (if lineEnd == lineStart) or everything to the
end with the first line of replacement text
2. delete all lines between lineStart and lineEnd (excluding)
3. insert the lines of the replacement text
4. change the line where replacement ends:
a) remove the part which is in replacement range
b) insert the last line of replacement text
c) insert the end of the first line if lineEnd == lineStart
d) keep the end unchanged
In the code below the steps 2 and 3 are merged and are done in parallel for
efficiency reasons (it is better to change lines in place rather than
remove/insert them from a potentially huge array)
*/
void wxTextCtrl::Replace(long from, long to, const wxString& text)
{
long colStart, colEnd,
@@ -248,6 +231,35 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text)
textTotalNew += textTotal.c_str() + (size_t)to;
#endif // WXDEBUG_TEXT_REPLACE
// the first attempt at implementing Replace() - it was meant to be more
// efficient than the current code but it also is much more complicated
// and, worse, still has a few bugs and so as I'm not even sure any more
// that it is really more efficient, I'm dropping it in favour of much
// simpler code below
#if 0
/*
The algorithm of Replace():
1. change the line where replacement starts
a) keep the text in the beginning of it unchanged
b) replace the middle (if lineEnd == lineStart) or everything to the
end with the first line of replacement text
2. delete all lines between lineStart and lineEnd (excluding)
3. insert the lines of the replacement text
4. change the line where replacement ends:
a) remove the part which is in replacement range
b) insert the last line of replacement text
c) insert the end of the first line if lineEnd == lineStart
d) keep the end unchanged
In the code below the steps 2 and 3 are merged and are done in parallel for
efficiency reasons (it is better to change lines in place rather than
remove/insert them from a potentially huge array)
*/
// break the replacement text into lines
wxArrayString lines = wxStringTokenize(text, _T("\n"),
wxTOKEN_RET_EMPTY_ALL);
@@ -372,8 +384,12 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text)
}
}
// (3) if there are still lines left in the replacement text, insert them
// before modifying the last line
// all the rest is only necessary if there is more than one line of
// replacement text
if ( nReplaceCount > 1 )
{
// (3) if there are still lines left in the replacement text, insert
// them before modifying the last line
if ( nReplaceLine < nReplaceCount - 1 )
{
// the lines below will scroll down
@@ -395,8 +411,8 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text)
RefreshLineRange(lineStart + 1, refreshAllBelow ? -1 : lineEnd - 1);
}
// now deal with the last line: (1) replace its beginning with the end of
// the replacement text
// now deal with the last line: (1) replace its beginning with the end
// of the replacement text
wxString lineLast;
if ( nReplaceLine < nReplaceCount )
{
@@ -405,8 +421,8 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text)
lineLast = lines[nReplaceLine];
}
// (2) add the text which was at the end of first line if we replaced its
// middle with multiline text
// (2) add the text which was at the end of first line if we replaced
// its middle with multiline text
if ( lineEnd == lineStart )
{
lineLast += lineFirstEnd;
@@ -434,9 +450,115 @@ void wxTextCtrl::Replace(long from, long to, const wxString& text)
{
RefreshPixelRange(lineEnd, 0, 0); // entire line
}
}
//else: only one line of replacement text
// update the current position
SetInsertionPoint(to);
#else // 1 (new replacement code)
/*
Join all the lines in the replacement range into one string, then
replace a part of it with the new text and break it into lines again.
*/
// (1) join lines
wxString textOrig;
long line;
for ( line = lineStart; line <= lineEnd; line++ )
{
if ( line > lineStart )
{
// from previous line
textOrig += _T('\n');
}
textOrig += m_lines[line];
}
// (2) replace text in the combined string
wxString textNew(textOrig, colStart);
// these values will be used to refresh the changed area below
wxCoord widthNewText, startNewText = GetTextWidth(textNew);
if ( (size_t)colStart == m_lines[lineStart].length() )
{
// text appended, refresh just enough to show the new text
widthNewText = GetTextWidth(text.BeforeFirst(_T('\n')));
}
else // text inserted, refresh till the end of line
{
widthNewText = 0;
}
textNew += text;
size_t toRel = (size_t)((to - from) + colStart); // adjust for index shift
if ( toRel < textOrig.length() )
textNew += textOrig.c_str() + toRel;
// (3) break it into lines
wxArrayString lines;
if ( textNew.empty() )
{
// special case: if the replacement string is empty we still want to
// have one (empty) string in the lines array but wxStringTokenize()
// won't put anything in it in this case, so do it ourselves
lines.Add(wxEmptyString);
}
else // break into lines normally
{
lines = wxStringTokenize(textNew, _T("\n"), wxTOKEN_RET_EMPTY_ALL);
}
size_t nReplaceCount = lines.GetCount(),
nReplaceLine = 0;
// (4) merge into the array
size_t countOld = m_lines.GetCount();
// (4a) replace
for ( line = lineStart; line <= lineEnd; line++, nReplaceLine++ )
{
if ( nReplaceLine < nReplaceCount )
{
// we have the replacement line for this one
m_lines[line] = lines[nReplaceLine];
}
else // no more replacement lines
{
// (4b) delete all extra lines
while ( line <= lineEnd )
{
m_lines.RemoveAt(line++);
}
}
}
// (4c) insert the new lines
while ( nReplaceLine < nReplaceCount )
{
m_lines.Insert(lines[nReplaceLine++], ++lineEnd);
}
// (5) now refresh the changed area
RefreshPixelRange(lineStart, startNewText, widthNewText);
if ( m_lines.GetCount() == countOld )
{
// number of lines didn't change, refresh the updated lines and the
// last one
if ( lineStart < lineEnd )
RefreshLineRange(lineStart + 1, lineEnd);
}
else
{
// number of lines did change, we need to refresh everything below the
// start line
RefreshLineRange(lineStart + 1);
}
#endif // 0/1
// update the current position: note that we always put the cursor at the
// end of the replacement text
SetInsertionPoint(from + text.length());
// and the selection (do it after setting the cursor to have correct value
// for selection anchor)
@@ -496,13 +618,10 @@ void wxTextCtrl::InitInsertionPoint()
void wxTextCtrl::DoSetInsertionPoint(long pos)
{
HideCaret();
m_curPos = pos;
PositionToXY(m_curPos, &m_curCol, &m_curRow);
ShowPosition(m_curPos);
ShowCaret();
ShowPosition(m_curPos);
}
void wxTextCtrl::SetInsertionPointEnd()
@@ -907,6 +1026,8 @@ bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
void wxTextCtrl::ShowPosition(long pos)
{
HideCaret();
if ( IsSingleLine() )
{
ShowHorzPosition(GetCaretPosition(pos));
@@ -915,6 +1036,8 @@ void wxTextCtrl::ShowPosition(long pos)
{
// TODO
}
ShowCaret();
}
// ----------------------------------------------------------------------------
@@ -1020,7 +1143,8 @@ void wxTextCtrl::Copy()
{
wxClipboardLocker clipLock;
wxString text = GetTextToShow(GetSelectionText());
// wxTextFile::Translate() is needed to transform all '\n' into "\r\n"
wxString text = wxTextFile::Translate(GetTextToShow(GetSelectionText()));
wxTextDataObject *data = new wxTextDataObject(text);
wxTheClipboard->SetData(data);
}
@@ -1046,7 +1170,8 @@ void wxTextCtrl::Paste()
if ( wxTheClipboard->IsSupported(data.GetFormat())
&& wxTheClipboard->GetData(data) )
{
WriteText(data.GetText());
// reverse transformation: '\r\n\" -> '\n'
WriteText(wxTextFile::Translate(data.GetText(), wxTextFileType_Unix));
}
#endif // wxUSE_CLIPBOARD
}
@@ -1886,7 +2011,6 @@ void wxTextCtrl::DoDraw(wxControlRenderer *renderer)
m_hasCaret = TRUE;
}
}
// ----------------------------------------------------------------------------
@@ -2103,12 +2227,19 @@ void wxTextCtrl::OnChar(wxKeyEvent& event)
{
int keycode = event.GetKeyCode();
if ( keycode == WXK_RETURN )
{
if ( IsSingleLine() || (GetWindowStyle() & wxTE_PROCESS_ENTER) )
{
wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, GetId());
InitCommandEvent(event);
event.SetString(GetValue());
GetEventHandler()->ProcessEvent(event);
}
else // interpret <Enter> normally: insert new line
{
PerformAction(wxACTION_TEXT_INSERT, -1, _T('\n'));
}
}
else if ( keycode < 255 &&
keycode != WXK_DELETE &&
keycode != WXK_BACK )