diff options
| author | Roxie Linden <roxie@lindenlab.com> | 2024-05-20 12:59:59 -0700 | 
|---|---|---|
| committer | Roxie Linden <roxie@lindenlab.com> | 2024-05-20 12:59:59 -0700 | 
| commit | 3a212d9608492ae64a3a32f80790371b90be9e9e (patch) | |
| tree | fcb3901b838af753e40c2ddd1ce84b95a6c2f603 /indra/llui/lltexteditor.cpp | |
| parent | c7461061b8113fa258611b1a31f16a119fad1a2c (diff) | |
| parent | e1623bb276f83a43ce7a197e388720c05bdefe61 (diff) | |
Merge branch 'spaces-merge' into roxie/webrtc-voice
Diffstat (limited to 'indra/llui/lltexteditor.cpp')
| -rw-r--r-- | indra/llui/lltexteditor.cpp | 4639 | 
1 files changed, 2326 insertions, 2313 deletions
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp index 7150052b65..e030861f20 100644 --- a/indra/llui/lltexteditor.cpp +++ b/indra/llui/lltexteditor.cpp @@ -1,24 +1,24 @@ -/**  +/**   * @file lltexteditor.cpp   *   * $LicenseInfo:firstyear=2001&license=viewerlgpl$   * Second Life Viewer Source Code   * Copyright (C) 2010, Linden Research, Inc. - *  + *   * This library is free software; you can redistribute it and/or   * modify it under the terms of the GNU Lesser General Public   * License as published by the Free Software Foundation;   * version 2.1 of the License only. - *  + *   * This library is distributed in the hope that it will be useful,   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   * Lesser General Public License for more details. - *  + *   * You should have received a copy of the GNU Lesser General Public   * License along with this library; if not, write to the Free Software   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - *  + *   * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA   * $/LicenseInfo$   */ @@ -32,7 +32,7 @@  #include "llfontfreetype.h" // for LLFontFreetype::FIRST_CHAR  #include "llfontgl.h" -#include "llgl.h"			// LLGLSUIDefault() +#include "llgl.h"           // LLGLSUIDefault()  #include "lllocalcliprect.h"  #include "llrender.h"  #include "llui.h" @@ -64,105 +64,105 @@  #include <queue>  #include "llcombobox.h" -//  +//  // Globals  //  static LLDefaultChildRegistry::Register<LLTextEditor> r("simple_text_editor");  // Compiler optimization, generate extern template  template class LLTextEditor* LLView::getChild<class LLTextEditor>( -	const std::string& name, BOOL recurse) const; +    const std::string& name, BOOL recurse) const;  //  // Constants  // -const S32	SPACES_PER_TAB = 4; -const F32	SPELLCHECK_DELAY = 0.5f;	// delay between the last keypress and spell checking the word the cursor is on +const S32   SPACES_PER_TAB = 4; +const F32   SPELLCHECK_DELAY = 0.5f;    // delay between the last keypress and spell checking the word the cursor is on  ///////////////////////////////////////////////////////////////////  class LLTextEditor::TextCmdInsert : public LLTextBase::TextCmd  {  public: -	TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment) -		: TextCmd(pos, group_with_next, segment), mWString(ws) -	{ -	} -	virtual ~TextCmdInsert() {} -	virtual BOOL execute( LLTextBase* editor, S32* delta ) -	{ -		*delta = insert(editor, getPosition(), mWString ); -		LLWStringUtil::truncate(mWString, *delta); -		//mWString = wstring_truncate(mWString, *delta); -		return (*delta != 0); -	}	 -	virtual S32 undo( LLTextBase* editor ) -	{ -		remove(editor, getPosition(), mWString.length() ); -		return getPosition(); -	} -	virtual S32 redo( LLTextBase* editor ) -	{ -		insert(editor, getPosition(), mWString ); -		return getPosition() + mWString.length(); -	} +    TextCmdInsert(S32 pos, BOOL group_with_next, const LLWString &ws, LLTextSegmentPtr segment) +        : TextCmd(pos, group_with_next, segment), mWString(ws) +    { +    } +    virtual ~TextCmdInsert() {} +    virtual BOOL execute( LLTextBase* editor, S32* delta ) +    { +        *delta = insert(editor, getPosition(), mWString ); +        LLWStringUtil::truncate(mWString, *delta); +        //mWString = wstring_truncate(mWString, *delta); +        return (*delta != 0); +    } +    virtual S32 undo( LLTextBase* editor ) +    { +        remove(editor, getPosition(), mWString.length() ); +        return getPosition(); +    } +    virtual S32 redo( LLTextBase* editor ) +    { +        insert(editor, getPosition(), mWString ); +        return getPosition() + mWString.length(); +    }  private: -	LLWString mWString; +    LLWString mWString;  };  ///////////////////////////////////////////////////////////////////  class LLTextEditor::TextCmdAddChar : public LLTextBase::TextCmd  {  public: -	TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment) -		: TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE) -	{ -	} -	virtual void blockExtensions() -	{ -		mBlockExtensions = TRUE; -	} -	virtual BOOL canExtend(S32 pos) const -	{ -		// cannot extend text with custom segments -		if (!mSegments.empty()) return FALSE; - -		return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length()); -	} -	virtual BOOL execute( LLTextBase* editor, S32* delta ) -	{ -		*delta = insert(editor, getPosition(), mWString); -		LLWStringUtil::truncate(mWString, *delta); -		//mWString = wstring_truncate(mWString, *delta); -		return (*delta != 0); -	} -	virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta )	 -	{  -		LLWString ws; -		ws += wc; -		 -		*delta = insert(editor, pos, ws); -		if( *delta > 0 ) -		{ -			mWString += wc; -		} -		return (*delta != 0); -	} -	virtual S32 undo( LLTextBase* editor ) -	{ -		remove(editor, getPosition(), mWString.length() ); -		return getPosition(); -	} -	virtual S32 redo( LLTextBase* editor ) -	{ -		insert(editor, getPosition(), mWString ); -		return getPosition() + mWString.length(); -	} +    TextCmdAddChar( S32 pos, BOOL group_with_next, llwchar wc, LLTextSegmentPtr segment) +        : TextCmd(pos, group_with_next, segment), mWString(1, wc), mBlockExtensions(FALSE) +    { +    } +    virtual void blockExtensions() +    { +        mBlockExtensions = TRUE; +    } +    virtual BOOL canExtend(S32 pos) const +    { +        // cannot extend text with custom segments +        if (!mSegments.empty()) return FALSE; + +        return !mBlockExtensions && (pos == getPosition() + (S32)mWString.length()); +    } +    virtual BOOL execute( LLTextBase* editor, S32* delta ) +    { +        *delta = insert(editor, getPosition(), mWString); +        LLWStringUtil::truncate(mWString, *delta); +        //mWString = wstring_truncate(mWString, *delta); +        return (*delta != 0); +    } +    virtual BOOL extendAndExecute( LLTextBase* editor, S32 pos, llwchar wc, S32* delta ) +    { +        LLWString ws; +        ws += wc; + +        *delta = insert(editor, pos, ws); +        if( *delta > 0 ) +        { +            mWString += wc; +        } +        return (*delta != 0); +    } +    virtual S32 undo( LLTextBase* editor ) +    { +        remove(editor, getPosition(), mWString.length() ); +        return getPosition(); +    } +    virtual S32 redo( LLTextBase* editor ) +    { +        insert(editor, getPosition(), mWString ); +        return getPosition() + mWString.length(); +    }  private: -	LLWString	mWString; -	BOOL		mBlockExtensions; +    LLWString   mWString; +    BOOL        mBlockExtensions;  }; @@ -171,30 +171,30 @@ private:  class LLTextEditor::TextCmdOverwriteChar : public LLTextBase::TextCmd  {  public: -	TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) -		: TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {} - -	virtual BOOL execute( LLTextBase* editor, S32* delta ) -	{  -		mOldChar = editor->getWText()[getPosition()]; -		overwrite(editor, getPosition(), mChar); -		*delta = 0; -		return TRUE; -	}	 -	virtual S32 undo( LLTextBase* editor ) -	{ -		overwrite(editor, getPosition(), mOldChar); -		return getPosition(); -	} -	virtual S32 redo( LLTextBase* editor ) -	{ -		overwrite(editor, getPosition(), mChar); -		return getPosition()+1; -	} +    TextCmdOverwriteChar( S32 pos, BOOL group_with_next, llwchar wc) +        : TextCmd(pos, group_with_next), mChar(wc), mOldChar(0) {} + +    virtual BOOL execute( LLTextBase* editor, S32* delta ) +    { +        mOldChar = editor->getWText()[getPosition()]; +        overwrite(editor, getPosition(), mChar); +        *delta = 0; +        return TRUE; +    } +    virtual S32 undo( LLTextBase* editor ) +    { +        overwrite(editor, getPosition(), mOldChar); +        return getPosition(); +    } +    virtual S32 redo( LLTextBase* editor ) +    { +        overwrite(editor, getPosition(), mChar); +        return getPosition()+1; +    }  private: -	llwchar		mChar; -	llwchar		mOldChar; +    llwchar     mChar; +    llwchar     mOldChar;  };  /////////////////////////////////////////////////////////////////// @@ -202,114 +202,116 @@ private:  class LLTextEditor::TextCmdRemove : public LLTextBase::TextCmd  {  public: -	TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) : -		TextCmd(pos, group_with_next), mLen(len) -	{ -		std::swap(mSegments, segments); -	} -	virtual BOOL execute( LLTextBase* editor, S32* delta ) -	{  -		mWString = editor->getWText().substr(getPosition(), mLen); -		*delta = remove(editor, getPosition(), mLen ); -		return (*delta != 0); -	} -	virtual S32 undo( LLTextBase* editor ) -	{ -		insert(editor, getPosition(), mWString); -		return getPosition() + mWString.length(); -	} -	virtual S32 redo( LLTextBase* editor ) -	{ -		remove(editor, getPosition(), mLen ); -		return getPosition(); -	} +    TextCmdRemove( S32 pos, BOOL group_with_next, S32 len, segment_vec_t& segments ) : +        TextCmd(pos, group_with_next), mLen(len) +    { +        std::swap(mSegments, segments); +    } +    virtual BOOL execute( LLTextBase* editor, S32* delta ) +    { +        mWString = editor->getWText().substr(getPosition(), mLen); +        *delta = remove(editor, getPosition(), mLen ); +        return (*delta != 0); +    } +    virtual S32 undo( LLTextBase* editor ) +    { +        insert(editor, getPosition(), mWString); +        return getPosition() + mWString.length(); +    } +    virtual S32 redo( LLTextBase* editor ) +    { +        remove(editor, getPosition(), mLen ); +        return getPosition(); +    }  private: -	LLWString	mWString; -	S32				mLen; +    LLWString   mWString; +    S32             mLen;  };  ///////////////////////////////////////////////////////////////////  LLTextEditor::Params::Params() -:	default_text("default_text"), -	prevalidate_callback("prevalidate_callback"), -	embedded_items("embedded_items", false), -	ignore_tab("ignore_tab", true), -	auto_indent("auto_indent", true), -	default_color("default_color"), +:   default_text("default_text"), +    prevalidator("prevalidator"), +    embedded_items("embedded_items", false), +    ignore_tab("ignore_tab", true), +    auto_indent("auto_indent", true), +    default_color("default_color"),      commit_on_focus_lost("commit_on_focus_lost", false), -	show_context_menu("show_context_menu"), -	show_emoji_helper("show_emoji_helper"), -	enable_tooltip_paste("enable_tooltip_paste") +    show_context_menu("show_context_menu"), +    show_emoji_helper("show_emoji_helper"), +    enable_tooltip_paste("enable_tooltip_paste")  { -	addSynonym(prevalidate_callback, "text_type"); +    addSynonym(prevalidator, "prevalidate_callback"); +    addSynonym(prevalidator, "text_type");  }  LLTextEditor::LLTextEditor(const LLTextEditor::Params& p) : -	LLTextBase(p), -	mAutoreplaceCallback(), -	mBaseDocIsPristine(TRUE), -	mPristineCmd( NULL ), -	mLastCmd( NULL ), -	mDefaultColor( p.default_color() ), -	mAutoIndent(p.auto_indent), -	mCommitOnFocusLost( p.commit_on_focus_lost), -	mAllowEmbeddedItems( p.embedded_items ), -	mMouseDownX(0), -	mMouseDownY(0), -	mTabsToNextField(p.ignore_tab), -	mPrevalidateFunc(p.prevalidate_callback()), -	mShowContextMenu(p.show_context_menu), -	mShowEmojiHelper(p.show_emoji_helper), -	mEnableTooltipPaste(p.enable_tooltip_paste), -	mPassDelete(FALSE), -	mKeepSelectionOnReturn(false) -{ -	mSourceID.generate(); - -	//FIXME: use image? -	LLViewBorder::Params params; -	params.name = "text ed border"; -	params.rect = getLocalRect(); -	params.bevel_style = LLViewBorder::BEVEL_IN; -	params.border_thickness = 1; -	params.visible = p.border_visible; -	mBorder = LLUICtrlFactory::create<LLViewBorder> (params); -	addChild( mBorder ); -	setText(p.default_text()); -	 -	mParseOnTheFly = TRUE; +    LLTextBase(p), +    mAutoreplaceCallback(), +    mBaseDocIsPristine(TRUE), +    mPristineCmd( NULL ), +    mLastCmd( NULL ), +    mDefaultColor( p.default_color() ), +    mAutoIndent(p.auto_indent), +    mParseOnTheFly(false), +    mCommitOnFocusLost( p.commit_on_focus_lost), +    mAllowEmbeddedItems( p.embedded_items ), +    mMouseDownX(0), +    mMouseDownY(0), +    mTabsToNextField(p.ignore_tab), +    mPrevalidator(p.prevalidator()), +    mShowContextMenu(p.show_context_menu), +    mShowEmojiHelper(p.show_emoji_helper), +    mEnableTooltipPaste(p.enable_tooltip_paste), +    mPassDelete(false), +    mKeepSelectionOnReturn(false) +{ +    mSourceID.generate(); + +    //FIXME: use image? +    LLViewBorder::Params params; +    params.name = "text ed border"; +    params.rect = getLocalRect(); +    params.bevel_style = LLViewBorder::BEVEL_IN; +    params.border_thickness = 1; +    params.visible = p.border_visible; +    mBorder = LLUICtrlFactory::create<LLViewBorder> (params); +    addChild( mBorder ); +    setText(p.default_text()); + +    mParseOnTheFly = true;  }  void LLTextEditor::initFromParams( const LLTextEditor::Params& p)  { -	LLTextBase::initFromParams(p); +    LLTextBase::initFromParams(p); -	// HACK:  text editors always need to be enabled so that we can scroll -	LLView::setEnabled(true); +    // HACK:  text editors always need to be enabled so that we can scroll +    LLView::setEnabled(true); -	if (p.commit_on_focus_lost.isProvided()) -	{ -		mCommitOnFocusLost = p.commit_on_focus_lost; -	} -	 -	updateAllowingLanguageInput(); +    if (p.commit_on_focus_lost.isProvided()) +    { +        mCommitOnFocusLost = p.commit_on_focus_lost; +    } + +    updateAllowingLanguageInput();  }  LLTextEditor::~LLTextEditor()  { -	gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() while LLTextEditor still valid +    gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() while LLTextEditor still valid -	// Scrollbar is deleted by LLView -	std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); -	mUndoStack.clear(); -	// Mark the menu as dead or its retained in memory till shutdown. -	LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); -	if(menu) -	{ -		menu->die(); -		mContextMenuHandle.markDead(); -	} +    // Scrollbar is deleted by LLView +    std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); +    mUndoStack.clear(); +    // Mark the menu as dead or its retained in memory till shutdown. +    LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); +    if(menu) +    { +        menu->die(); +        mContextMenuHandle.markDead(); +    }  }  //////////////////////////////////////////////////////////// @@ -318,649 +320,651 @@ LLTextEditor::~LLTextEditor()  void LLTextEditor::setText(const LLStringExplicit &utf8str, const LLStyle::Params& input_params)  { -	// validate incoming text if necessary -	if (mPrevalidateFunc) -	{ -		LLWString test_text = utf8str_to_wstring(utf8str); -		if (!mPrevalidateFunc(test_text)) -		{ -			// not valid text, nothing to do -			return; -		} -	} +    // validate incoming text if necessary +    if (mPrevalidator) +    { +        if (!mPrevalidator.validate(utf8str)) +        { +            LLUI::getInstance()->reportBadKeystroke(); +            mPrevalidator.showLastErrorUsingTimeout(); + +            // not valid text, nothing to do +            return; +        } +    } + +    blockUndo(); +    deselect(); -	blockUndo(); -	deselect(); -	 -	mParseOnTheFly = FALSE; -	LLTextBase::setText(utf8str, input_params); -	mParseOnTheFly = TRUE; +    mParseOnTheFly = false; +    LLTextBase::setText(utf8str, input_params); +    mParseOnTheFly = true; -	resetDirty(); +    resetDirty();  }  void LLTextEditor::selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap)  { -	if (search_text_in.empty()) -	{ -		return; -	} - -	LLWString text = getWText(); -	LLWString search_text = utf8str_to_wstring(search_text_in); -	if (case_insensitive) -	{ -		LLWStringUtil::toLower(text); -		LLWStringUtil::toLower(search_text); -	} -	 -	if (mIsSelecting) -	{ -		LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); -		 -		if (selected_text == search_text) -		{ -			// We already have this word selected, we are searching for the next. -			setCursorPos(mCursorPos + search_text.size()); -		} -	} -	 -	S32 loc = text.find(search_text,mCursorPos); -	 -	// If Maybe we wrapped, search again -	if (wrap && (-1 == loc)) -	{	 -		loc = text.find(search_text); -	} -	 -	// If still -1, then search_text just isn't found. +    if (search_text_in.empty()) +    { +        return; +    } + +    LLWString text = getWText(); +    LLWString search_text = utf8str_to_wstring(search_text_in); +    if (case_insensitive) +    { +        LLWStringUtil::toLower(text); +        LLWStringUtil::toLower(search_text); +    } + +    if (mIsSelecting) +    { +        LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); + +        if (selected_text == search_text) +        { +            // We already have this word selected, we are searching for the next. +            setCursorPos(mCursorPos + search_text.size()); +        } +    } + +    S32 loc = text.find(search_text,mCursorPos); + +    // If Maybe we wrapped, search again +    if (wrap && (-1 == loc)) +    { +        loc = text.find(search_text); +    } + +    // If still -1, then search_text just isn't found.      if (-1 == loc) -	{ -		mIsSelecting = FALSE; -		mSelectionEnd = 0; -		mSelectionStart = 0; -		return; -	} +    { +        mIsSelecting = FALSE; +        mSelectionEnd = 0; +        mSelectionStart = 0; +        return; +    } -	setCursorPos(loc); -	 -	mIsSelecting = TRUE; -	mSelectionEnd = mCursorPos; -	mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); +    setCursorPos(loc); + +    mIsSelecting = TRUE; +    mSelectionEnd = mCursorPos; +    mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size()));  }  BOOL LLTextEditor::replaceText(const std::string& search_text_in, const std::string& replace_text, -							   BOOL case_insensitive, BOOL wrap) +                               BOOL case_insensitive, BOOL wrap)  { -	BOOL replaced = FALSE; +    BOOL replaced = FALSE; -	if (search_text_in.empty()) -	{ -		return replaced; -	} +    if (search_text_in.empty()) +    { +        return replaced; +    } -	LLWString search_text = utf8str_to_wstring(search_text_in); -	if (mIsSelecting) -	{ -		LLWString text = getWText(); -		LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); +    LLWString search_text = utf8str_to_wstring(search_text_in); +    if (mIsSelecting) +    { +        LLWString text = getWText(); +        LLWString selected_text = text.substr(mSelectionEnd, mSelectionStart - mSelectionEnd); -		if (case_insensitive) -		{ -			LLWStringUtil::toLower(selected_text); -			LLWStringUtil::toLower(search_text); -		} +        if (case_insensitive) +        { +            LLWStringUtil::toLower(selected_text); +            LLWStringUtil::toLower(search_text); +        } -		if (selected_text == search_text) -		{ -			insertText(replace_text); -			replaced = TRUE; -		} -	} +        if (selected_text == search_text) +        { +            insertText(replace_text); +            replaced = TRUE; +        } +    } -	selectNext(search_text_in, case_insensitive, wrap); -	return replaced; +    selectNext(search_text_in, case_insensitive, wrap); +    return replaced;  }  void LLTextEditor::replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive)  { -	startOfDoc(); -	selectNext(search_text, case_insensitive, FALSE); +    startOfDoc(); +    selectNext(search_text, case_insensitive, FALSE); -	BOOL replaced = TRUE; -	while ( replaced ) -	{ -		replaced = replaceText(search_text,replace_text, case_insensitive, FALSE); -	} +    BOOL replaced = TRUE; +    while ( replaced ) +    { +        replaced = replaceText(search_text,replace_text, case_insensitive, FALSE); +    }  }  S32 LLTextEditor::prevWordPos(S32 cursorPos) const  { -	LLWString wtext(getWText()); -	while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) -	{ -		cursorPos--; -	} -	while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) -	{ -		cursorPos--; -	} -	return cursorPos; +    LLWString wtext(getWText()); +    while( (cursorPos > 0) && (wtext[cursorPos-1] == ' ') ) +    { +        cursorPos--; +    } +    while( (cursorPos > 0) && LLWStringUtil::isPartOfWord( wtext[cursorPos-1] ) ) +    { +        cursorPos--; +    } +    return cursorPos;  }  S32 LLTextEditor::nextWordPos(S32 cursorPos) const  { -	LLWString wtext(getWText()); -	while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) -	{ -		cursorPos++; -	}  -	while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) -	{ -		cursorPos++; -	} -	return cursorPos; +    LLWString wtext(getWText()); +    while( (cursorPos < getLength()) && LLWStringUtil::isPartOfWord( wtext[cursorPos] ) ) +    { +        cursorPos++; +    } +    while( (cursorPos < getLength()) && (wtext[cursorPos] == ' ') ) +    { +        cursorPos++; +    } +    return cursorPos;  } -const LLTextSegmentPtr	LLTextEditor::getPreviousSegment() const +const LLTextSegmentPtr  LLTextEditor::getPreviousSegment() const  { -	static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment; +    static LLPointer<LLIndexSegment> index_segment = new LLIndexSegment; -	index_segment->setStart(mCursorPos); -	index_segment->setEnd(mCursorPos); +    index_segment->setStart(mCursorPos); +    index_segment->setEnd(mCursorPos); -	// find segment index at character to left of cursor (or rightmost edge of selection) -	segment_set_t::const_iterator it = mSegments.lower_bound(index_segment); +    // find segment index at character to left of cursor (or rightmost edge of selection) +    segment_set_t::const_iterator it = mSegments.lower_bound(index_segment); -	if (it != mSegments.end()) -	{ -		return *it; -	} -	else -	{ -		return LLTextSegmentPtr(); -	} +    if (it != mSegments.end()) +    { +        return *it; +    } +    else +    { +        return LLTextSegmentPtr(); +    }  }  void LLTextEditor::getSelectedSegments(LLTextEditor::segment_vec_t& segments) const  { -	S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; -	S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; +    S32 left = hasSelection() ? llmin(mSelectionStart, mSelectionEnd) : mCursorPos; +    S32 right = hasSelection() ? llmax(mSelectionStart, mSelectionEnd) : mCursorPos; -	return getSegmentsInRange(segments, left, right, true); +    return getSegmentsInRange(segments, left, right, true);  }  void LLTextEditor::getSegmentsInRange(LLTextEditor::segment_vec_t& segments_out, S32 start, S32 end, bool include_partial) const  { -	segment_set_t::const_iterator first_it = getSegIterContaining(start); -	segment_set_t::const_iterator end_it = getSegIterContaining(end - 1); -	if (end_it != mSegments.end()) ++end_it; +    segment_set_t::const_iterator first_it = getSegIterContaining(start); +    segment_set_t::const_iterator end_it = getSegIterContaining(end - 1); +    if (end_it != mSegments.end()) ++end_it; -	for (segment_set_t::const_iterator it = first_it; it != end_it; ++it) -	{ -		LLTextSegmentPtr segment = *it; -		if (include_partial -			||	(segment->getStart() >= start -				&& segment->getEnd() <= end)) -		{ -			segments_out.push_back(segment); -		} -	} +    for (segment_set_t::const_iterator it = first_it; it != end_it; ++it) +    { +        LLTextSegmentPtr segment = *it; +        if (include_partial +            ||  (segment->getStart() >= start +                && segment->getEnd() <= end)) +        { +            segments_out.push_back(segment); +        } +    }  }  void LLTextEditor::setShowEmojiHelper(bool show)  { -	if (!mShowEmojiHelper) -	{ -		LLEmojiHelper::instance().hideHelper(this); -	} +    if (!mShowEmojiHelper) +    { +        LLEmojiHelper::instance().hideHelper(this); +    } -	mShowEmojiHelper = show; +    mShowEmojiHelper = show;  }  BOOL LLTextEditor::selectionContainsLineBreaks()  { -	if (hasSelection()) -	{ -		S32 left = llmin(mSelectionStart, mSelectionEnd); -		S32 right = left + llabs(mSelectionStart - mSelectionEnd); +    if (hasSelection()) +    { +        S32 left = llmin(mSelectionStart, mSelectionEnd); +        S32 right = left + llabs(mSelectionStart - mSelectionEnd); -		LLWString wtext = getWText(); -		for( S32 i = left; i < right; i++ ) -		{ -			if (wtext[i] == '\n') -			{ -				return TRUE; -			} -		} -	} -	return FALSE; +        LLWString wtext = getWText(); +        for( S32 i = left; i < right; i++ ) +        { +            if (wtext[i] == '\n') +            { +                return TRUE; +            } +        } +    } +    return FALSE;  }  S32 LLTextEditor::indentLine( S32 pos, S32 spaces )  { -	// Assumes that pos is at the start of the line -	// spaces may be positive (indent) or negative (unindent). -	// Returns the actual number of characters added or removed. - -	llassert(pos >= 0); -	llassert(pos <= getLength() ); - -	S32 delta_spaces = 0; - -	if (spaces >= 0) -	{ -		// Indent -		for(S32 i=0; i < spaces; i++) -		{ -			delta_spaces += addChar(pos, ' '); -		} -	} -	else -	{ -		// Unindent -		for(S32 i=0; i < -spaces; i++) -		{ -			LLWString wtext = getWText(); -			if (wtext[pos] == ' ') -			{ -				delta_spaces += remove( pos, 1, FALSE ); -			} - 		} -	} - -	return delta_spaces; +    // Assumes that pos is at the start of the line +    // spaces may be positive (indent) or negative (unindent). +    // Returns the actual number of characters added or removed. + +    llassert(pos >= 0); +    llassert(pos <= getLength() ); + +    S32 delta_spaces = 0; + +    if (spaces >= 0) +    { +        // Indent +        for(S32 i=0; i < spaces; i++) +        { +            delta_spaces += addChar(pos, ' '); +        } +    } +    else +    { +        // Unindent +        for(S32 i=0; i < -spaces; i++) +        { +            LLWString wtext = getWText(); +            if (wtext[pos] == ' ') +            { +                delta_spaces += remove( pos, 1, FALSE ); +            } +        } +    } + +    return delta_spaces;  }  void LLTextEditor::indentSelectedLines( S32 spaces )  { -	if( hasSelection() ) -	{ -		LLWString text = getWText(); -		S32 left = llmin( mSelectionStart, mSelectionEnd ); -		S32 right = left + llabs( mSelectionStart - mSelectionEnd ); -		BOOL cursor_on_right = (mSelectionEnd > mSelectionStart); -		S32 cur = left; - -		// Expand left to start of line -		while( (cur > 0) && (text[cur] != '\n') ) -		{ -			cur--; -		} -		left = cur; -		if( cur > 0 ) -		{ -			left++; -		} - -		// Expand right to end of line -		if( text[right - 1] == '\n' ) -		{ -			right--; -		} -		else -		{ -			while( (text[right] != '\n') && (right <= getLength() ) ) -			{ -				right++; -			} -		} - -		// Disabling parsing on the fly to avoid updating text segments -		// until all indentation commands are executed. -		mParseOnTheFly = FALSE; - -		// Find each start-of-line and indent it -		do -		{ -			if( text[cur] == '\n' ) -			{ -				cur++; -			} - -			S32 delta_spaces = indentLine( cur, spaces ); -			if( delta_spaces > 0 ) -			{ -				cur += delta_spaces; -			} -			right += delta_spaces; - -			text = getWText(); - -			// Find the next new line -			while( (cur < right) && (text[cur] != '\n') ) -			{ -				cur++; -			} -		} -		while( cur < right ); - -		mParseOnTheFly = TRUE; - -		if( (right < getLength()) && (text[right] == '\n') ) -		{ -			right++; -		} - -		// Set the selection and cursor -		if( cursor_on_right ) -		{ -			mSelectionStart = left; -			mSelectionEnd = right; -		} -		else -		{ -			mSelectionStart = right; -			mSelectionEnd = left; -		} -		setCursorPos(mSelectionEnd); -	} +    if( hasSelection() ) +    { +        LLWString text = getWText(); +        S32 left = llmin( mSelectionStart, mSelectionEnd ); +        S32 right = left + llabs( mSelectionStart - mSelectionEnd ); +        BOOL cursor_on_right = (mSelectionEnd > mSelectionStart); +        S32 cur = left; + +        // Expand left to start of line +        while( (cur > 0) && (text[cur] != '\n') ) +        { +            cur--; +        } +        left = cur; +        if( cur > 0 ) +        { +            left++; +        } + +        // Expand right to end of line +        if( text[right - 1] == '\n' ) +        { +            right--; +        } +        else +        { +            while( (text[right] != '\n') && (right <= getLength() ) ) +            { +                right++; +            } +        } + +        // Disabling parsing on the fly to avoid updating text segments +        // until all indentation commands are executed. +        mParseOnTheFly = false; + +        // Find each start-of-line and indent it +        do +        { +            if( text[cur] == '\n' ) +            { +                cur++; +            } + +            S32 delta_spaces = indentLine( cur, spaces ); +            if( delta_spaces > 0 ) +            { +                cur += delta_spaces; +            } +            right += delta_spaces; + +            text = getWText(); + +            // Find the next new line +            while( (cur < right) && (text[cur] != '\n') ) +            { +                cur++; +            } +        } +        while( cur < right ); + +        mParseOnTheFly = true; + +        if( (right < getLength()) && (text[right] == '\n') ) +        { +            right++; +        } + +        // Set the selection and cursor +        if( cursor_on_right ) +        { +            mSelectionStart = left; +            mSelectionEnd = right; +        } +        else +        { +            mSelectionStart = right; +            mSelectionEnd = left; +        } +        setCursorPos(mSelectionEnd); +    }  }  //virtual  BOOL LLTextEditor::canSelectAll() const  { -	return TRUE; +    return TRUE;  }  // virtual  void LLTextEditor::selectAll()  { -	mSelectionStart = getLength(); -	mSelectionEnd = 0; -	setCursorPos(mSelectionEnd); -	updatePrimary(); +    mSelectionStart = getLength(); +    mSelectionEnd = 0; +    setCursorPos(mSelectionEnd); +    updatePrimary();  }  void LLTextEditor::selectByCursorPosition(S32 prev_cursor_pos, S32 next_cursor_pos)  { -	setCursorPos(prev_cursor_pos); -	startSelection(); -	setCursorPos(next_cursor_pos); -	endSelection(); +    setCursorPos(prev_cursor_pos); +    startSelection(); +    setCursorPos(next_cursor_pos); +    endSelection();  }  void LLTextEditor::insertEmoji(llwchar emoji)  { -	LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; -	auto styleParams = LLStyle::Params(); -	styleParams.font = LLFontGL::getFontEmoji(); -	auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); -	insert(mCursorPos, LLWString(1, emoji), false, segment); -	setCursorPos(mCursorPos + 1); +    LL_INFOS() << "LLTextEditor::insertEmoji(" << wchar_utf8_preview(emoji) << ")" << LL_ENDL; +    auto styleParams = LLStyle::Params(); +    styleParams.font = LLFontGL::getFontEmojiLarge(); +    auto segment = new LLEmojiTextSegment(new LLStyle(styleParams), mCursorPos, mCursorPos + 1, *this); +    insert(mCursorPos, LLWString(1, emoji), false, segment); +    setCursorPos(mCursorPos + 1);  }  void LLTextEditor::handleEmojiCommit(llwchar emoji)  { -	S32 shortCodePos; -	if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) -	{ -		remove(shortCodePos, mCursorPos - shortCodePos, true); -		setCursorPos(shortCodePos); +    S32 shortCodePos; +    if (LLEmojiHelper::isCursorInEmojiCode(getWText(), mCursorPos, &shortCodePos)) +    { +        remove(shortCodePos, mCursorPos - shortCodePos, true); +        setCursorPos(shortCodePos); -		insertEmoji(emoji); -	} +        insertEmoji(emoji); +    }  }  BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)  { -	BOOL	handled = FALSE; - -	// set focus first, in case click callbacks want to change it -	// RN: do we really need to have a tab stop? -	if (hasTabStop()) -	{ -		setFocus( TRUE ); -	} - -	// Let scrollbar have first dibs -	handled = LLTextBase::handleMouseDown(x, y, mask); - -	if( !handled ) -	{ -		if (!(mask & MASK_SHIFT)) -		{ -			deselect(); -		} - -		BOOL start_select = TRUE; -		if( start_select ) -		{ -			// If we're not scrolling (handled by child), then we're selecting -			if (mask & MASK_SHIFT) -			{ -				S32 old_cursor_pos = mCursorPos; -				setCursorAtLocalPos( x, y, true ); - -				if (hasSelection()) -				{ -					mSelectionEnd = mCursorPos; -				} -				else -				{ -					mSelectionStart = old_cursor_pos; -					mSelectionEnd = mCursorPos; -				} -				// assume we're starting a drag select -				mIsSelecting = TRUE; -			} -			else -			{ -				setCursorAtLocalPos( x, y, true ); -				startSelection(); -			} -		} - -		handled = TRUE; -	} - -	// Delay cursor flashing -	resetCursorBlink(); - -	if (handled && !gFocusMgr.getMouseCapture()) -	{ -		gFocusMgr.setMouseCapture( this ); -	} -	return handled; +    BOOL    handled = FALSE; + +    // set focus first, in case click callbacks want to change it +    // RN: do we really need to have a tab stop? +    if (hasTabStop()) +    { +        setFocus( TRUE ); +    } + +    // Let scrollbar have first dibs +    handled = LLTextBase::handleMouseDown(x, y, mask); + +    if( !handled ) +    { +        if (!(mask & MASK_SHIFT)) +        { +            deselect(); +        } + +        BOOL start_select = TRUE; +        if( start_select ) +        { +            // If we're not scrolling (handled by child), then we're selecting +            if (mask & MASK_SHIFT) +            { +                S32 old_cursor_pos = mCursorPos; +                setCursorAtLocalPos( x, y, true ); + +                if (hasSelection()) +                { +                    mSelectionEnd = mCursorPos; +                } +                else +                { +                    mSelectionStart = old_cursor_pos; +                    mSelectionEnd = mCursorPos; +                } +                // assume we're starting a drag select +                mIsSelecting = TRUE; +            } +            else +            { +                setCursorAtLocalPos( x, y, true ); +                startSelection(); +            } +        } + +        handled = TRUE; +    } + +    // Delay cursor flashing +    resetCursorBlink(); + +    if (handled && !gFocusMgr.getMouseCapture()) +    { +        gFocusMgr.setMouseCapture( this ); +    } +    return handled;  }  BOOL LLTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask)  { -	if (hasTabStop()) -	{ -		setFocus(TRUE); -	} +    if (hasTabStop()) +    { +        setFocus(TRUE); +    } -	bool show_menu = false; +    bool show_menu = false; -	// Prefer editor menu if it has selection. See EXT-6806. -	if (hasSelection()) -	{ -		S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE); -		if (click_pos > mSelectionStart && click_pos < mSelectionEnd) -		{ -			show_menu = true; -		} -	} +    // Prefer editor menu if it has selection. See EXT-6806. +    if (hasSelection()) +    { +        S32 click_pos = getDocIndexFromLocalCoord(x, y, FALSE); +        if (click_pos > mSelectionStart && click_pos < mSelectionEnd) +        { +            show_menu = true; +        } +    } -	// Let segments handle the click, if nothing does, show editor menu -	if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask)) -	{ -		show_menu = true; -	} +    // Let segments handle the click, if nothing does, show editor menu +    if (!show_menu && !LLTextBase::handleRightMouseDown(x, y, mask)) +    { +        show_menu = true; +    } -	if (show_menu && getShowContextMenu()) -	{ -		showContextMenu(x, y); -	} +    if (show_menu && getShowContextMenu()) +    { +        showContextMenu(x, y); +    } -	return TRUE; +    return TRUE;  }  BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask)  { -	if (hasTabStop()) -	{ -		setFocus(TRUE); -	} +    if (hasTabStop()) +    { +        setFocus(TRUE); +    } -	if (!LLTextBase::handleMouseDown(x, y, mask)) -	{ -		if( canPastePrimary() ) -		{ -			setCursorAtLocalPos( x, y, true ); -			// does not rely on focus being set -			pastePrimary(); -		} -	} -	return TRUE; +    if (!LLTextBase::handleMouseDown(x, y, mask)) +    { +        if( canPastePrimary() ) +        { +            setCursorAtLocalPos( x, y, true ); +            // does not rely on focus being set +            pastePrimary(); +        } +    } +    return TRUE;  }  BOOL LLTextEditor::handleHover(S32 x, S32 y, MASK mask)  { -	BOOL handled = FALSE; - -	if(hasMouseCapture() ) -	{ -		if( mIsSelecting )  -		{ -			if(mScroller) -			{	 -				mScroller->autoScroll(x, y); -			} -			S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); -			S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); -			setCursorAtLocalPos( clamped_x, clamped_y, true ); -			mSelectionEnd = mCursorPos; -		} -		LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL;		 -		getWindow()->setCursor(UI_CURSOR_IBEAM); -		handled = TRUE; -	} - -	if( !handled ) -	{ -		// Pass to children -		handled = LLTextBase::handleHover(x, y, mask); -	} - -	if( handled ) -	{ -		// Delay cursor flashing -		resetCursorBlink(); -	} - -	if( !handled ) -	{ -		getWindow()->setCursor(UI_CURSOR_IBEAM); -		handled = TRUE; -	} - -	return handled; +    BOOL handled = FALSE; + +    if(hasMouseCapture() ) +    { +        if( mIsSelecting ) +        { +            if(mScroller) +            { +                mScroller->autoScroll(x, y); +            } +            S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); +            S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); +            setCursorAtLocalPos( clamped_x, clamped_y, true ); +            mSelectionEnd = mCursorPos; +        } +        LL_DEBUGS("UserInput") << "hover handled by " << getName() << " (active)" << LL_ENDL; +        getWindow()->setCursor(UI_CURSOR_IBEAM); +        handled = TRUE; +    } + +    if( !handled ) +    { +        // Pass to children +        handled = LLTextBase::handleHover(x, y, mask); +    } + +    if( handled ) +    { +        // Delay cursor flashing +        resetCursorBlink(); +    } + +    if( !handled ) +    { +        getWindow()->setCursor(UI_CURSOR_IBEAM); +        handled = TRUE; +    } + +    return handled;  }  BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)  { -	BOOL	handled = FALSE; - -	// if I'm not currently selecting text -	if (!(mIsSelecting && hasMouseCapture())) -	{ -		// let text segments handle mouse event -		handled = LLTextBase::handleMouseUp(x, y, mask); -	} - -	if( !handled ) -	{ -		if( mIsSelecting ) -		{ -			if(mScroller) -			{ -				mScroller->autoScroll(x, y); -			} -			S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); -			S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); -			setCursorAtLocalPos( clamped_x, clamped_y, true ); -			endSelection(); -		} -		 -		// take selection to 'primary' clipboard -		updatePrimary(); - -		handled = TRUE; -	} - -	// Delay cursor flashing -	resetCursorBlink(); - -	if( hasMouseCapture()  ) -	{ -		gFocusMgr.setMouseCapture( NULL ); -		 -		handled = TRUE; -	} - -	return handled; +    BOOL    handled = FALSE; + +    // if I'm not currently selecting text +    if (!(mIsSelecting && hasMouseCapture())) +    { +        // let text segments handle mouse event +        handled = LLTextBase::handleMouseUp(x, y, mask); +    } + +    if( !handled ) +    { +        if( mIsSelecting ) +        { +            if(mScroller) +            { +                mScroller->autoScroll(x, y); +            } +            S32 clamped_x = llclamp(x, mVisibleTextRect.mLeft, mVisibleTextRect.mRight); +            S32 clamped_y = llclamp(y, mVisibleTextRect.mBottom, mVisibleTextRect.mTop); +            setCursorAtLocalPos( clamped_x, clamped_y, true ); +            endSelection(); +        } + +        // take selection to 'primary' clipboard +        updatePrimary(); + +        handled = TRUE; +    } + +    // Delay cursor flashing +    resetCursorBlink(); + +    if( hasMouseCapture()  ) +    { +        gFocusMgr.setMouseCapture( NULL ); + +        handled = TRUE; +    } + +    return handled;  }  BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)  { -	BOOL	handled = FALSE; +    BOOL    handled = FALSE; -	// let scrollbar and text segments have first dibs -	handled = LLTextBase::handleDoubleClick(x, y, mask); +    // let scrollbar and text segments have first dibs +    handled = LLTextBase::handleDoubleClick(x, y, mask); -	if( !handled ) -	{ -		setCursorAtLocalPos( x, y, false ); -		deselect(); +    if( !handled ) +    { +        setCursorAtLocalPos( x, y, false ); +        deselect(); -		LLWString text = getWText(); -		 -		if( LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) -		{ -			// Select word the cursor is over -			while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord(text[mCursorPos-1])) -			{ -				if (!setCursorPos(mCursorPos - 1)) break; -			} -			startSelection(); +        LLWString text = getWText(); -			while ((mCursorPos < (S32)text.length()) && LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) -			{ -				if (!setCursorPos(mCursorPos + 1)) break; -			} -		 -			mSelectionEnd = mCursorPos; -		} -		else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) -		{ -			// Select the character the cursor is over -			startSelection(); -			setCursorPos(mCursorPos + 1); -			mSelectionEnd = mCursorPos; -		} +        if( LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) +        { +            // Select word the cursor is over +            while ((mCursorPos > 0) && LLWStringUtil::isPartOfWord(text[mCursorPos-1])) +            { +                if (!setCursorPos(mCursorPos - 1)) break; +            } +            startSelection(); + +            while ((mCursorPos < (S32)text.length()) && LLWStringUtil::isPartOfWord( text[mCursorPos] ) ) +            { +                if (!setCursorPos(mCursorPos + 1)) break; +            } + +            mSelectionEnd = mCursorPos; +        } +        else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) +        { +            // Select the character the cursor is over +            startSelection(); +            setCursorPos(mCursorPos + 1); +            mSelectionEnd = mCursorPos; +        } -		// We don't want handleMouseUp() to "finish" the selection (and thereby -		// set mSelectionEnd to where the mouse is), so we finish the selection here. -		mIsSelecting = FALSE;   +        // We don't want handleMouseUp() to "finish" the selection (and thereby +        // set mSelectionEnd to where the mouse is), so we finish the selection here. +        mIsSelecting = FALSE; -		// delay cursor flashing -		resetCursorBlink(); +        // delay cursor flashing +        resetCursorBlink(); -		// take selection to 'primary' clipboard -		updatePrimary(); +        // take selection to 'primary' clipboard +        updatePrimary(); -		handled = TRUE; -	} +        handled = TRUE; +    } -	return handled; +    return handled;  } @@ -969,228 +973,232 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)  S32 LLTextEditor::execute( TextCmd* cmd )  { -	if (!mReadOnly && mShowEmojiHelper) -	{ -		// Any change to our contents should always hide the helper -		LLEmojiHelper::instance().hideHelper(this); -	} - -	S32 delta = 0; -	if( cmd->execute(this, &delta) ) -	{ -		// Delete top of undo stack -		undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); -		std::for_each(mUndoStack.begin(), enditer, DeletePointer()); -		mUndoStack.erase(mUndoStack.begin(), enditer); -		// Push the new command is now on the top (front) of the undo stack. -		mUndoStack.push_front(cmd); -		mLastCmd = cmd; - -		bool need_to_rollback = mPrevalidateFunc  -								&& !mPrevalidateFunc(getViewModel()->getDisplay()); -		if (need_to_rollback) -		{ -			// get rid of this last command and clean up undo stack -			undo(); - -			// remove any evidence of this command from redo history -			mUndoStack.pop_front(); -			delete cmd; - -			// failure, nothing changed -			delta = 0; -		} -	} -	else -	{ -		// Operation failed, so don't put it on the undo stack. -		delete cmd; -	} - -	return delta; +    if (!mReadOnly && mShowEmojiHelper) +    { +        // Any change to our contents should always hide the helper +        LLEmojiHelper::instance().hideHelper(this); +    } + +    S32 delta = 0; +    if( cmd->execute(this, &delta) ) +    { +        // Delete top of undo stack +        undo_stack_t::iterator enditer = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); +        std::for_each(mUndoStack.begin(), enditer, DeletePointer()); +        mUndoStack.erase(mUndoStack.begin(), enditer); +        // Push the new command is now on the top (front) of the undo stack. +        mUndoStack.push_front(cmd); +        mLastCmd = cmd; + +        bool need_to_rollback = mPrevalidator && !mPrevalidator.validate(getViewModel()->getDisplay()); +        if (need_to_rollback) +        { +            LLUI::getInstance()->reportBadKeystroke(); +            mPrevalidator.showLastErrorUsingTimeout(); + +            // get rid of this last command and clean up undo stack +            undo(); + +            // remove any evidence of this command from redo history +            mUndoStack.pop_front(); +            delete cmd; + +            // failure, nothing changed +            delta = 0; +        } +    } +    else +    { +        // Operation failed, so don't put it on the undo stack. +        delete cmd; +    } + +    return delta;  }  S32 LLTextEditor::insert(S32 pos, const LLWString &wstr, bool group_with_next_op, LLTextSegmentPtr segment)  { -	return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) ); +    return execute( new TextCmdInsert( pos, group_with_next_op, wstr, segment ) );  }  S32 LLTextEditor::remove(S32 pos, S32 length, bool group_with_next_op)  { -	S32 end_pos = getEditableIndex(pos + length, true); -	BOOL removedChar = FALSE; +    S32 end_pos = getEditableIndex(pos + length, true); +    BOOL removedChar = FALSE; + +    segment_vec_t segments_to_remove; +    // store text segments +    getSegmentsInRange(segments_to_remove, pos, pos + length, false); -	segment_vec_t segments_to_remove; -	// store text segments -	getSegmentsInRange(segments_to_remove, pos, pos + length, false); -	 -	if (pos <= end_pos) -	{ -		removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) ); -	} +    if (pos <= end_pos) +    { +        removedChar = execute( new TextCmdRemove( pos, group_with_next_op, end_pos - pos, segments_to_remove ) ); +    } -	return removedChar; +    return removedChar;  }  S32 LLTextEditor::overwriteChar(S32 pos, llwchar wc)  { -	if ((S32)getLength() == pos) -	{ -		return addChar(pos, wc); -	} -	else -	{ -		return execute(new TextCmdOverwriteChar(pos, FALSE, wc)); -	} +    if ((S32)getLength() == pos) +    { +        return addChar(pos, wc); +    } +    else +    { +        return execute(new TextCmdOverwriteChar(pos, FALSE, wc)); +    }  }  // Remove a single character from the text.  Tries to remove  // a pseudo-tab (up to for spaces in a row)  void LLTextEditor::removeCharOrTab()  { -	if (!getEnabled()) -	{ -		return; -	} - -	if (mCursorPos > 0) -	{ -		S32 chars_to_remove = 1; - -		LLWString text = getWText(); -		if (text[mCursorPos - 1] == ' ') -		{ -			// Try to remove a "tab" -			S32 offset = getLineOffsetFromDocIndex(mCursorPos); -			if (offset > 0) -			{ -				chars_to_remove = offset % SPACES_PER_TAB; -				if (chars_to_remove == 0) -				{ -					chars_to_remove = SPACES_PER_TAB; -				} - -				for (S32 i = 0; i < chars_to_remove; i++) -				{ -					if (text[mCursorPos - i - 1] != ' ') -					{ -						// Fewer than a full tab's worth of spaces, so -						// just delete a single character. -						chars_to_remove = 1; -						break; -					} -				} -			} -		} -	 -		for (S32 i = 0; i < chars_to_remove; i++) -		{ -			setCursorPos(mCursorPos - 1); -			remove(mCursorPos, 1, false); -		} - -		tryToShowEmojiHelper(); -	} -	else -	{ -		LLUI::getInstance()->reportBadKeystroke(); -	} +    if (!getEnabled()) +    { +        return; +    } + +    if (mCursorPos > 0) +    { +        S32 chars_to_remove = 1; + +        LLWString text = getWText(); +        if (text[mCursorPos - 1] == ' ') +        { +            // Try to remove a "tab" +            S32 offset = getLineOffsetFromDocIndex(mCursorPos); +            if (offset > 0) +            { +                chars_to_remove = offset % SPACES_PER_TAB; +                if (chars_to_remove == 0) +                { +                    chars_to_remove = SPACES_PER_TAB; +                } + +                for (S32 i = 0; i < chars_to_remove; i++) +                { +                    if (text[mCursorPos - i - 1] != ' ') +                    { +                        // Fewer than a full tab's worth of spaces, so +                        // just delete a single character. +                        chars_to_remove = 1; +                        break; +                    } +                } +            } +        } + +        for (S32 i = 0; i < chars_to_remove; i++) +        { +            setCursorPos(mCursorPos - 1); +            remove(mCursorPos, 1, false); +        } + +        tryToShowEmojiHelper(); +    } +    else +    { +        LLUI::getInstance()->reportBadKeystroke(); +    }  }  // Remove a single character from the text  S32 LLTextEditor::removeChar(S32 pos)  { -	return remove(pos, 1, false); +    return remove(pos, 1, false);  }  void LLTextEditor::removeChar()  { -	if (!getEnabled()) -	{ -		return; -	} +    if (!getEnabled()) +    { +        return; +    } -	if (mCursorPos > 0) -	{ -		setCursorPos(mCursorPos - 1); -		removeChar(mCursorPos); -		tryToShowEmojiHelper(); -	} -	else -	{ -		LLUI::getInstance()->reportBadKeystroke(); -	} +    if (mCursorPos > 0) +    { +        setCursorPos(mCursorPos - 1); +        removeChar(mCursorPos); +        tryToShowEmojiHelper(); +    } +    else +    { +        LLUI::getInstance()->reportBadKeystroke(); +    }  }  // Add a single character to the text  S32 LLTextEditor::addChar(S32 pos, llwchar wc)  { -	if ( (wstring_utf8_length( getWText() ) + wchar_utf8_length( wc ))  > mMaxTextByteLength) -	{ -		make_ui_sound("UISndBadKeystroke"); -		return 0; -	} - -	if (mLastCmd && mLastCmd->canExtend(pos)) -	{ -		S32 delta = 0; -		if (mPrevalidateFunc) -		{ -			// get a copy of current text contents -			LLWString test_string(getViewModel()->getDisplay()); - -			// modify text contents as if this addChar succeeded -			llassert(pos <= (S32)test_string.size()); -			test_string.insert(pos, 1, wc); -			if (!mPrevalidateFunc( test_string)) -			{ -				return 0; -			} -		} -		mLastCmd->extendAndExecute(this, pos, wc, &delta); - -		return delta; -	} -	else -	{ -		return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr())); -	} +    if ((wstring_utf8_length(getWText()) + wchar_utf8_length(wc)) > mMaxTextByteLength) +    { +        LLUI::getInstance()->reportBadKeystroke(); +        return 0; +    } + +    if (mLastCmd && mLastCmd->canExtend(pos)) +    { +        if (mPrevalidator) +        { +            // get a copy of current text contents +            LLWString test_string(getViewModel()->getDisplay()); + +            // modify text contents as if this addChar succeeded +            llassert(pos <= (S32)test_string.size()); +            test_string.insert(pos, 1, wc); +            if (!mPrevalidator.validate(test_string)) +            { +                LLUI::getInstance()->reportBadKeystroke(); +                mPrevalidator.showLastErrorUsingTimeout(); +                return 0; +            } +        } + +        S32 delta = 0; +        mLastCmd->extendAndExecute(this, pos, wc, &delta); + +        return delta; +    } + +    return execute(new TextCmdAddChar(pos, FALSE, wc, LLTextSegmentPtr()));  }  void LLTextEditor::addChar(llwchar wc)  { -	if( !getEnabled() ) -	{ -		return; -	} -	if( hasSelection() ) -	{ -		deleteSelection(TRUE); -	} -	else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) -	{ -		removeChar(mCursorPos); -	} - -	setCursorPos(mCursorPos + addChar( mCursorPos, wc )); -	tryToShowEmojiHelper(); - -	if (!mReadOnly && mAutoreplaceCallback != NULL) -	{ -		// autoreplace the text, if necessary -		S32 replacement_start; -		S32 replacement_length; -		LLWString replacement_string; -		S32 new_cursor_pos = mCursorPos; -		mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, getWText()); - -		if (replacement_length > 0 || !replacement_string.empty()) -		{ -			remove(replacement_start, replacement_length, true); -			insert(replacement_start, replacement_string, false, LLTextSegmentPtr()); -			setCursorPos(new_cursor_pos); -		} -	} +    if (!getEnabled()) +    { +        return; +    } + +    if (hasSelection()) +    { +        deleteSelection(TRUE); +    } +    else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) +    { +        removeChar(mCursorPos); +    } + +    setCursorPos(mCursorPos + addChar( mCursorPos, wc )); +    tryToShowEmojiHelper(); + +    if (!mReadOnly && mAutoreplaceCallback != NULL) +    { +        // autoreplace the text, if necessary +        S32 replacement_start; +        S32 replacement_length; +        LLWString replacement_string; +        S32 new_cursor_pos = mCursorPos; +        mAutoreplaceCallback(replacement_start, replacement_length, replacement_string, new_cursor_pos, getWText()); + +        if (replacement_length > 0 || !replacement_string.empty()) +        { +            remove(replacement_start, replacement_length, true); +            insert(replacement_start, replacement_string, false, LLTextSegmentPtr()); +            setCursorPos(new_cursor_pos); +        } +    }  }  void LLTextEditor::showEmojiHelper() @@ -1226,791 +1234,796 @@ void LLTextEditor::tryToShowEmojiHelper()  void LLTextEditor::addLineBreakChar(BOOL group_together)  { -	if( !getEnabled() ) -	{ -		return; -	} -	if( hasSelection() ) -	{ -		deleteSelection(TRUE); -	} -	else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) -	{ -		removeChar(mCursorPos); -	} +    if( !getEnabled() ) +    { +        return; +    } +    if( hasSelection() ) +    { +        deleteSelection(TRUE); +    } +    else if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) +    { +        removeChar(mCursorPos); +    } + +    LLStyleConstSP sp(new LLStyle(LLStyle::Params())); +    LLTextSegmentPtr segment = new LLLineBreakTextSegment(sp, mCursorPos); -	LLStyleConstSP sp(new LLStyle(LLStyle::Params())); -	LLTextSegmentPtr segment = new LLLineBreakTextSegment(sp, mCursorPos); +    S32 pos = execute(new TextCmdAddChar(mCursorPos, group_together, '\n', segment)); -	S32 pos = execute(new TextCmdAddChar(mCursorPos, group_together, '\n', segment)); -	 -	setCursorPos(mCursorPos + pos); +    setCursorPos(mCursorPos + pos);  }  BOOL LLTextEditor::handleSelectionKey(const KEY key, const MASK mask)  { -	BOOL handled = FALSE; - -	if( mask & MASK_SHIFT ) -	{ -		handled = TRUE; -		 -		switch( key ) -		{ -		case KEY_LEFT: -			if( 0 < mCursorPos ) -			{ -				startSelection(); -				setCursorPos(mCursorPos - 1); -				if( mask & MASK_CONTROL ) -				{ -					setCursorPos(prevWordPos(mCursorPos)); -				} -				mSelectionEnd = mCursorPos; -			} -			break; - -		case KEY_RIGHT: -			if( mCursorPos < getLength() ) -			{ -				startSelection(); -				setCursorPos(mCursorPos + 1); -				if( mask & MASK_CONTROL ) -				{ -					setCursorPos(nextWordPos(mCursorPos)); -				} -				mSelectionEnd = mCursorPos; -			} -			break; - -		case KEY_UP: -			startSelection(); -			changeLine( -1 ); -			mSelectionEnd = mCursorPos; -			break; - -		case KEY_PAGE_UP: -			startSelection(); -			changePage( -1 ); -			mSelectionEnd = mCursorPos; -			break; - -		case KEY_HOME: -			startSelection(); -			if( mask & MASK_CONTROL ) -			{ -				setCursorPos(0); -			} -			else -			{ -				startOfLine(); -			} -			mSelectionEnd = mCursorPos; -			break; - -		case KEY_DOWN: -			startSelection(); -			changeLine( 1 ); -			mSelectionEnd = mCursorPos; -			break; - -		case KEY_PAGE_DOWN: -			startSelection(); -			changePage( 1 ); -			mSelectionEnd = mCursorPos; -			break; - -		case KEY_END: -			startSelection(); -			if( mask & MASK_CONTROL ) -			{ -				setCursorPos(getLength()); -			} -			else -			{ -				endOfLine(); -			} -			mSelectionEnd = mCursorPos; -			break; - -		default: -			handled = FALSE; -			break; -		} -	} - -	if( handled ) -	{ -		// take selection to 'primary' clipboard -		updatePrimary(); -	} -  -	return handled; +    BOOL handled = FALSE; + +    if( mask & MASK_SHIFT ) +    { +        handled = TRUE; + +        switch( key ) +        { +        case KEY_LEFT: +            if( 0 < mCursorPos ) +            { +                startSelection(); +                setCursorPos(mCursorPos - 1); +                if( mask & MASK_CONTROL ) +                { +                    setCursorPos(prevWordPos(mCursorPos)); +                } +                mSelectionEnd = mCursorPos; +            } +            break; + +        case KEY_RIGHT: +            if( mCursorPos < getLength() ) +            { +                startSelection(); +                setCursorPos(mCursorPos + 1); +                if( mask & MASK_CONTROL ) +                { +                    setCursorPos(nextWordPos(mCursorPos)); +                } +                mSelectionEnd = mCursorPos; +            } +            break; + +        case KEY_UP: +            startSelection(); +            changeLine( -1 ); +            mSelectionEnd = mCursorPos; +            break; + +        case KEY_PAGE_UP: +            startSelection(); +            changePage( -1 ); +            mSelectionEnd = mCursorPos; +            break; + +        case KEY_HOME: +            startSelection(); +            if( mask & MASK_CONTROL ) +            { +                setCursorPos(0); +            } +            else +            { +                startOfLine(); +            } +            mSelectionEnd = mCursorPos; +            break; + +        case KEY_DOWN: +            startSelection(); +            changeLine( 1 ); +            mSelectionEnd = mCursorPos; +            break; + +        case KEY_PAGE_DOWN: +            startSelection(); +            changePage( 1 ); +            mSelectionEnd = mCursorPos; +            break; + +        case KEY_END: +            startSelection(); +            if( mask & MASK_CONTROL ) +            { +                setCursorPos(getLength()); +            } +            else +            { +                endOfLine(); +            } +            mSelectionEnd = mCursorPos; +            break; + +        default: +            handled = FALSE; +            break; +        } +    } + +    if( handled ) +    { +        // take selection to 'primary' clipboard +        updatePrimary(); +    } + +    return handled;  }  BOOL LLTextEditor::handleNavigationKey(const KEY key, const MASK mask)  { -	BOOL handled = FALSE; - -	// Ignore capslock key -	if( MASK_NONE == mask ) -	{ -		handled = TRUE; -		switch( key ) -		{ -		case KEY_UP: -			changeLine( -1 ); -			break; - -		case KEY_PAGE_UP: -			changePage( -1 ); -			break; - -		case KEY_HOME: -			startOfLine(); -			break; - -		case KEY_DOWN: -			changeLine( 1 ); -			deselect(); -			break; - -		case KEY_PAGE_DOWN: -			changePage( 1 ); -			break; -  -		case KEY_END: -			endOfLine(); -			break; - -		case KEY_LEFT: -			if( hasSelection() ) -			{ -				setCursorPos(llmin( mSelectionStart, mSelectionEnd )); -			} -			else -			{ -				if( 0 < mCursorPos ) -				{ -					setCursorPos(mCursorPos - 1); -				} -				else -				{ -					LLUI::getInstance()->reportBadKeystroke(); -				} -			} -			break; - -		case KEY_RIGHT: -			if( hasSelection() ) -			{ -				setCursorPos(llmax( mSelectionStart, mSelectionEnd )); -			} -			else -			{ -				if( mCursorPos < getLength() ) -				{ -					setCursorPos(mCursorPos + 1); -				} -				else -				{ -					LLUI::getInstance()->reportBadKeystroke(); -				} -			}	 -			break; -			 -		default: -			handled = FALSE; -			break; -		} -	} -	 -	if (handled) -	{ -		deselect(); -	} -	 -	return handled; +    BOOL handled = FALSE; + +    // Ignore capslock key +    if( MASK_NONE == mask ) +    { +        handled = TRUE; +        switch( key ) +        { +        case KEY_UP: +            changeLine( -1 ); +            break; + +        case KEY_PAGE_UP: +            changePage( -1 ); +            break; + +        case KEY_HOME: +            startOfLine(); +            break; + +        case KEY_DOWN: +            changeLine( 1 ); +            deselect(); +            break; + +        case KEY_PAGE_DOWN: +            changePage( 1 ); +            break; + +        case KEY_END: +            endOfLine(); +            break; + +        case KEY_LEFT: +            if( hasSelection() ) +            { +                setCursorPos(llmin( mSelectionStart, mSelectionEnd )); +            } +            else +            { +                if( 0 < mCursorPos ) +                { +                    setCursorPos(mCursorPos - 1); +                } +                else +                { +                    LLUI::getInstance()->reportBadKeystroke(); +                } +            } +            break; + +        case KEY_RIGHT: +            if( hasSelection() ) +            { +                setCursorPos(llmax( mSelectionStart, mSelectionEnd )); +            } +            else +            { +                if( mCursorPos < getLength() ) +                { +                    setCursorPos(mCursorPos + 1); +                } +                else +                { +                    LLUI::getInstance()->reportBadKeystroke(); +                } +            } +            break; + +        default: +            handled = FALSE; +            break; +        } +    } + +    if (handled) +    { +        deselect(); +    } + +    return handled;  }  void LLTextEditor::deleteSelection(BOOL group_with_next_op )  { -	if( getEnabled() && hasSelection() ) -	{ -		S32 pos = llmin( mSelectionStart, mSelectionEnd ); -		S32 length = llabs( mSelectionStart - mSelectionEnd ); -	 -		remove( pos, length, group_with_next_op ); +    if( getEnabled() && hasSelection() ) +    { +        S32 pos = llmin( mSelectionStart, mSelectionEnd ); +        S32 length = llabs( mSelectionStart - mSelectionEnd ); -		deselect(); -		setCursorPos(pos); -	} +        remove( pos, length, group_with_next_op ); + +        deselect(); +        setCursorPos(pos); +    }  }  // virtual  BOOL LLTextEditor::canCut() const  { -	return !mReadOnly && hasSelection(); +    return !mReadOnly && hasSelection();  }  // cut selection to clipboard  void LLTextEditor::cut()  { -	if( !canCut() ) -	{ -		return; -	} -	S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); -	S32 length = llabs( mSelectionStart - mSelectionEnd ); -	LLClipboard::instance().copyToClipboard( getWText(), left_pos, length); -	deleteSelection( FALSE ); +    if( !canCut() ) +    { +        return; +    } +    S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); +    S32 length = llabs( mSelectionStart - mSelectionEnd ); +    LLClipboard::instance().copyToClipboard( getWText(), left_pos, length); +    deleteSelection( FALSE ); -	onKeyStroke(); +    onKeyStroke();  }  BOOL LLTextEditor::canCopy() const  { -	return hasSelection(); +    return hasSelection();  }  // copy selection to clipboard  void LLTextEditor::copy()  { -	if( !canCopy() ) -	{ -		return; -	} -	S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); -	S32 length = llabs( mSelectionStart - mSelectionEnd ); -	LLClipboard::instance().copyToClipboard(getWText(), left_pos, length); +    if( !canCopy() ) +    { +        return; +    } +    S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); +    S32 length = llabs( mSelectionStart - mSelectionEnd ); +    LLClipboard::instance().copyToClipboard(getWText(), left_pos, length);  }  BOOL LLTextEditor::canPaste() const  { -	return !mReadOnly && LLClipboard::instance().isTextAvailable(); +    return !mReadOnly && LLClipboard::instance().isTextAvailable();  }  // paste from clipboard  void LLTextEditor::paste()  { -	bool is_primary = false; -	pasteHelper(is_primary); +    bool is_primary = false; +    pasteHelper(is_primary);  }  // paste from primary  void LLTextEditor::pastePrimary()  { -	bool is_primary = true; -	pasteHelper(is_primary); +    bool is_primary = true; +    pasteHelper(is_primary);  }  // paste from primary (itsprimary==true) or clipboard (itsprimary==false)  void LLTextEditor::pasteHelper(bool is_primary)  { -	mParseOnTheFly = FALSE; -	bool can_paste_it; -	if (is_primary) -	{ -		can_paste_it = canPastePrimary(); -	} -	else -	{ -		can_paste_it = canPaste(); -	} +    struct BoolReset +    { +        BoolReset(bool& value) : mValuePtr(&value) { *mValuePtr = false; } +        ~BoolReset() { *mValuePtr = true; } +        bool* mValuePtr; +    } reset(mParseOnTheFly); -	if (!can_paste_it) -	{ -		return; -	} +    bool can_paste_it; +    if (is_primary) +    { +        can_paste_it = canPastePrimary(); +    } +    else +    { +        can_paste_it = canPaste(); +    } -	LLWString paste; -	LLClipboard::instance().pasteFromClipboard(paste, is_primary); +    if (!can_paste_it) +    { +        return; +    } -	if (paste.empty()) -	{ -		return; -	} +    LLWString paste; +    LLClipboard::instance().pasteFromClipboard(paste, is_primary); -	// Delete any selected characters (the paste replaces them) -	if( (!is_primary) && hasSelection() ) -	{ -		deleteSelection(TRUE); -	} +    if (paste.empty()) +    { +        return; +    } + +    // Delete any selected characters (the paste replaces them) +    if( (!is_primary) && hasSelection() ) +    { +        deleteSelection(TRUE); +    } -	// Clean up string (replace tabs and remove characters that our fonts don't support). -	LLWString clean_string(paste); -	cleanStringForPaste(clean_string); +    // Clean up string (replace tabs and remove characters that our fonts don't support). +    LLWString clean_string(paste); +    cleanStringForPaste(clean_string); -	// Insert the new text into the existing text. +    // Insert the new text into the existing text. -	//paste text with linebreaks. -	pasteTextWithLinebreaks(clean_string); +    //paste text with linebreaks. +    pasteTextWithLinebreaks(clean_string); -	deselect(); +    deselect(); -	onKeyStroke(); -	mParseOnTheFly = TRUE; +    onKeyStroke();  }  // Clean up string (replace tabs and remove characters that our fonts don't support).  void LLTextEditor::cleanStringForPaste(LLWString & clean_string)  { -	std::string clean_string_utf = wstring_to_utf8str(clean_string); -	std::replace( clean_string_utf.begin(), clean_string_utf.end(), '\r', '\n'); -	clean_string = utf8str_to_wstring(clean_string_utf); - -	LLWStringUtil::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); -	if( mAllowEmbeddedItems ) -	{ -		const llwchar LF = 10; -		S32 len = clean_string.length(); -		for( S32 i = 0; i < len; i++ ) -		{ -			llwchar wc = clean_string[i]; -			if( (wc < LLFontFreetype::FIRST_CHAR) && (wc != LF) ) -			{ -				clean_string[i] = LL_UNKNOWN_CHAR; -			} -			else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) -			{ -				clean_string[i] = pasteEmbeddedItem(wc); -			} -		} -	} +    std::string clean_string_utf = wstring_to_utf8str(clean_string); +    std::replace( clean_string_utf.begin(), clean_string_utf.end(), '\r', '\n'); +    clean_string = utf8str_to_wstring(clean_string_utf); + +    LLWStringUtil::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); +    if( mAllowEmbeddedItems ) +    { +        const llwchar LF = 10; +        S32 len = clean_string.length(); +        for( S32 i = 0; i < len; i++ ) +        { +            llwchar wc = clean_string[i]; +            if( (wc < LLFontFreetype::FIRST_CHAR) && (wc != LF) ) +            { +                clean_string[i] = LL_UNKNOWN_CHAR; +            } +            else if (wc >= FIRST_EMBEDDED_CHAR && wc <= LAST_EMBEDDED_CHAR) +            { +                clean_string[i] = pasteEmbeddedItem(wc); +            } +        } +    }  }  void LLTextEditor::pasteTextWithLinebreaks(LLWString & clean_string)  { -	std::basic_string<llwchar>::size_type start = 0; -	std::basic_string<llwchar>::size_type pos = clean_string.find('\n',start); -	 -	while((pos != -1) && (pos != clean_string.length() -1)) -	{ -		if(pos!=start) -		{ -			std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,pos-start); -			setCursorPos(mCursorPos + insert(mCursorPos, str, TRUE, LLTextSegmentPtr())); -		} -		addLineBreakChar(TRUE);			// Add a line break and group with the next addition. - -		start = pos+1; -		pos = clean_string.find('\n',start); -	} - -	if (pos != start) -	{ -		std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,clean_string.length()-start); -		setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr())); -	} -	else -	{ -		addLineBreakChar(FALSE);		// Add a line break and end the grouping. -	} +    std::basic_string<llwchar>::size_type start = 0; +    std::basic_string<llwchar>::size_type pos = clean_string.find('\n',start); + +    while((pos != -1) && (pos != clean_string.length() -1)) +    { +        if(pos!=start) +        { +            std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,pos-start); +            setCursorPos(mCursorPos + insert(mCursorPos, str, TRUE, LLTextSegmentPtr())); +        } +        addLineBreakChar(TRUE);         // Add a line break and group with the next addition. + +        start = pos+1; +        pos = clean_string.find('\n',start); +    } + +    if (pos != start) +    { +        std::basic_string<llwchar> str = std::basic_string<llwchar>(clean_string,start,clean_string.length()-start); +        setCursorPos(mCursorPos + insert(mCursorPos, str, FALSE, LLTextSegmentPtr())); +    } +    else +    { +        addLineBreakChar(FALSE);        // Add a line break and end the grouping. +    }  }  // copy selection to primary  void LLTextEditor::copyPrimary()  { -	if( !canCopy() ) -	{ -		return; -	} -	S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); -	S32 length = llabs( mSelectionStart - mSelectionEnd ); -	LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true); +    if( !canCopy() ) +    { +        return; +    } +    S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); +    S32 length = llabs( mSelectionStart - mSelectionEnd ); +    LLClipboard::instance().copyToClipboard(getWText(), left_pos, length, true);  }  BOOL LLTextEditor::canPastePrimary() const  { -	return !mReadOnly && LLClipboard::instance().isTextAvailable(true); +    return !mReadOnly && LLClipboard::instance().isTextAvailable(true);  }  void LLTextEditor::updatePrimary()  { -	if (canCopy()) -	{ -		copyPrimary(); -	} -} - -BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask)	 -{ -	BOOL handled = FALSE; - -	if( mask & MASK_CONTROL ) -	{ -		handled = TRUE; - -		switch( key ) -		{ -		case KEY_HOME: -			if( mask & MASK_SHIFT ) -			{ -				startSelection(); -				setCursorPos(0); -				mSelectionEnd = mCursorPos; -			} -			else -			{ -				// Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down -				// all move the cursor as if clicking, so should deselect. -				deselect(); -				startOfDoc(); -			} -			break; - -		case KEY_END: -			{ -				if( mask & MASK_SHIFT ) -				{ -					startSelection(); -				} -				else -				{ -					// Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down -					// all move the cursor as if clicking, so should deselect. -					deselect(); -				} -				endOfDoc(); -				if( mask & MASK_SHIFT ) -				{ -					mSelectionEnd = mCursorPos; -				} -				break; -			} - -		case KEY_RIGHT: -			if( mCursorPos < getLength() ) -			{ -				// Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down -				// all move the cursor as if clicking, so should deselect. -				deselect(); - -				setCursorPos(nextWordPos(mCursorPos + 1)); -			} -			break; - - -		case KEY_LEFT: -			if( mCursorPos > 0 ) -			{ -				// Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down -				// all move the cursor as if clicking, so should deselect. -				deselect(); - -				setCursorPos(prevWordPos(mCursorPos - 1)); -			} -			break; - -		default: -			handled = FALSE; -			break; -		} -	} - -	if (handled && !gFocusMgr.getMouseCapture()) -	{ -		updatePrimary(); -	} - -	return handled; -} - - -BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask)	 -	{ -	BOOL handled = TRUE; - -	if (mReadOnly) return FALSE; - -	switch( key ) -	{ -	case KEY_INSERT: -		if (mask == MASK_NONE) -		{ -			gKeyboard->toggleInsertMode(); -		} -		break; - -	case KEY_BACKSPACE: -		if( hasSelection() ) -		{ -			deleteSelection(FALSE); -		} -		else -		if( 0 < mCursorPos ) -		{ -			removeCharOrTab(); -		} -		else -		{ -			LLUI::getInstance()->reportBadKeystroke(); -		} -		break; - - -	case KEY_RETURN: -		if (mask == MASK_NONE) -		{ -			if( hasSelection() && !mKeepSelectionOnReturn ) -			{ -				deleteSelection(FALSE); -			} -			if (mAutoIndent) -			{ -				autoIndent(); -			} -		} -		else -		{ -			handled = FALSE; -			break; -		} -		break; - -	case KEY_TAB: -		if (mask & MASK_CONTROL) -		{ -			handled = FALSE; -			break; -		} -		if( hasSelection() && selectionContainsLineBreaks() ) -		{ -			indentSelectedLines( (mask & MASK_SHIFT) ? -SPACES_PER_TAB : SPACES_PER_TAB ); -		} -		else -		{ -			if( hasSelection() ) -			{ -				deleteSelection(FALSE); -			} -			 -			S32 offset = getLineOffsetFromDocIndex(mCursorPos); - -			S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); -			for( S32 i=0; i < spaces_needed; i++ ) -			{ -				addChar( ' ' ); -			} -		} -		break; -		 -	default: -		handled = FALSE; -		break; -	} - -	if (handled) -	{ -		onKeyStroke(); -	} -	return handled; +    if (canCopy()) +    { +        copyPrimary(); +    }  } - -void LLTextEditor::unindentLineBeforeCloseBrace() +BOOL LLTextEditor::handleControlKey(const KEY key, const MASK mask)  { -	if( mCursorPos >= 1 ) -	{ -		LLWString text = getWText(); -		if( ' ' == text[ mCursorPos - 1 ] ) -		{ -			S32 line = getLineNumFromDocIndex(mCursorPos, false); -			S32 line_start = getLineStart(line); +    BOOL handled = FALSE; + +    if( mask & MASK_CONTROL ) +    { +        handled = TRUE; + +        switch( key ) +        { +        case KEY_HOME: +            if( mask & MASK_SHIFT ) +            { +                startSelection(); +                setCursorPos(0); +                mSelectionEnd = mCursorPos; +            } +            else +            { +                // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down +                // all move the cursor as if clicking, so should deselect. +                deselect(); +                startOfDoc(); +            } +            break; + +        case KEY_END: +            { +                if( mask & MASK_SHIFT ) +                { +                    startSelection(); +                } +                else +                { +                    // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down +                    // all move the cursor as if clicking, so should deselect. +                    deselect(); +                } +                endOfDoc(); +                if( mask & MASK_SHIFT ) +                { +                    mSelectionEnd = mCursorPos; +                } +                break; +            } + +        case KEY_RIGHT: +            if( mCursorPos < getLength() ) +            { +                // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down +                // all move the cursor as if clicking, so should deselect. +                deselect(); + +                setCursorPos(nextWordPos(mCursorPos + 1)); +            } +            break; + + +        case KEY_LEFT: +            if( mCursorPos > 0 ) +            { +                // Ctrl-Home, Ctrl-Left, Ctrl-Right, Ctrl-Down +                // all move the cursor as if clicking, so should deselect. +                deselect(); + +                setCursorPos(prevWordPos(mCursorPos - 1)); +            } +            break; + +        default: +            handled = FALSE; +            break; +        } +    } + +    if (handled && !gFocusMgr.getMouseCapture()) +    { +        updatePrimary(); +    } + +    return handled; +} + + +BOOL LLTextEditor::handleSpecialKey(const KEY key, const MASK mask) +    { +    BOOL handled = TRUE; + +    if (mReadOnly) return FALSE; + +    switch( key ) +    { +    case KEY_INSERT: +        if (mask == MASK_NONE) +        { +            gKeyboard->toggleInsertMode(); +        } +        break; + +    case KEY_BACKSPACE: +        if( hasSelection() ) +        { +            deleteSelection(FALSE); +        } +        else +        if( 0 < mCursorPos ) +        { +            removeCharOrTab(); +        } +        else +        { +            LLUI::getInstance()->reportBadKeystroke(); +        } +        break; + + +    case KEY_RETURN: +        if (mask == MASK_NONE) +        { +            if( hasSelection() && !mKeepSelectionOnReturn ) +            { +                deleteSelection(FALSE); +            } +            if (mAutoIndent) +            { +                autoIndent(); +            } +        } +        else +        { +            handled = FALSE; +            break; +        } +        break; + +    case KEY_TAB: +        if (mask & MASK_CONTROL) +        { +            handled = FALSE; +            break; +        } +        if( hasSelection() && selectionContainsLineBreaks() ) +        { +            indentSelectedLines( (mask & MASK_SHIFT) ? -SPACES_PER_TAB : SPACES_PER_TAB ); +        } +        else +        { +            if( hasSelection() ) +            { +                deleteSelection(FALSE); +            } + +            S32 offset = getLineOffsetFromDocIndex(mCursorPos); + +            S32 spaces_needed = SPACES_PER_TAB - (offset % SPACES_PER_TAB); +            for( S32 i=0; i < spaces_needed; i++ ) +            { +                addChar( ' ' ); +            } +        } +        break; -			// Jump over spaces in the current line -			while ((' ' == text[line_start]) && (line_start < mCursorPos)) -			{ -				line_start++; -			} +    default: +        handled = FALSE; +        break; +    } -			// Make sure there is nothing but ' ' before the Brace we are unindenting -			if (line_start == mCursorPos) -			{ -				removeCharOrTab(); -			} -		} -	} +    if (handled) +    { +        onKeyStroke(); +    } +    return handled; +} + + +void LLTextEditor::unindentLineBeforeCloseBrace() +{ +    if( mCursorPos >= 1 ) +    { +        LLWString text = getWText(); +        if( ' ' == text[ mCursorPos - 1 ] ) +        { +            S32 line = getLineNumFromDocIndex(mCursorPos, false); +            S32 line_start = getLineStart(line); + +            // Jump over spaces in the current line +            while ((' ' == text[line_start]) && (line_start < mCursorPos)) +            { +                line_start++; +            } + +            // Make sure there is nothing but ' ' before the Brace we are unindenting +            if (line_start == mCursorPos) +            { +                removeCharOrTab(); +            } +        } +    }  }  BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )  { -	BOOL	handled = FALSE; - -	// Special case for TAB.  If want to move to next field, report -	// not handled and let the parent take care of field movement. -	if (KEY_TAB == key && mTabsToNextField) -	{ -		return FALSE; -	} - -	if (mReadOnly && mScroller) -	{ -		handled = (mScroller && mScroller->handleKeyHere( key, mask )) -				|| handleSelectionKey(key, mask) -				|| handleControlKey(key, mask); -	} -	else  -	{ -		if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) -		{ -			return TRUE; -		} - -		if (mEnableTooltipPaste && -			LLToolTipMgr::instance().toolTipVisible() && +    BOOL    handled = FALSE; + +    // Special case for TAB.  If want to move to next field, report +    // not handled and let the parent take care of field movement. +    if (KEY_TAB == key && mTabsToNextField) +    { +        return FALSE; +    } + +    if (mReadOnly && mScroller) +    { +        handled = (mScroller && mScroller->handleKeyHere( key, mask )) +                || handleSelectionKey(key, mask) +                || handleControlKey(key, mask); +    } +    else +    { +        if (!mReadOnly && mShowEmojiHelper && LLEmojiHelper::instance().handleKey(this, key, mask)) +        { +            return TRUE; +        } + +        if (mEnableTooltipPaste && +            LLToolTipMgr::instance().toolTipVisible() &&              LLToolTipMgr::instance().isTooltipPastable() && -			KEY_TAB == key) -		{	// Paste the first line of a tooltip into the editor -			std::string message; -			LLToolTipMgr::instance().getToolTipMessage(message); -			LLWString tool_tip_text(utf8str_to_wstring(message)); - -			if (tool_tip_text.size() > 0) -			{ -				// Delete any selected characters (the tooltip text replaces them) -				if(hasSelection()) -				{ -					deleteSelection(TRUE); -				} - -				std::basic_string<llwchar>::size_type pos = tool_tip_text.find('\n',0); -				if (pos != -1) -				{	// Extract the first line of the tooltip -					tool_tip_text = std::basic_string<llwchar>(tool_tip_text, 0, pos); -				} - -				// Add the text -				cleanStringForPaste(tool_tip_text); -				pasteTextWithLinebreaks(tool_tip_text); -				handled = TRUE; -			} -		} -		else -		{	// Normal key handling -			handled = handleNavigationKey( key, mask ) -					|| handleSelectionKey(key, mask) -					|| handleControlKey(key, mask) -					|| handleSpecialKey(key, mask); -		} -	} - -	if( handled ) -	{ -		resetCursorBlink(); -		needsScroll(); - -		if (mShowEmojiHelper) -		{ -			// Dismiss the helper whenever we handled a key that it didn't -			LLEmojiHelper::instance().hideHelper(this); -		} -	} - -	return handled; +            KEY_TAB == key) +        {   // Paste the first line of a tooltip into the editor +            std::string message; +            LLToolTipMgr::instance().getToolTipMessage(message); +            LLWString tool_tip_text(utf8str_to_wstring(message)); + +            if (tool_tip_text.size() > 0) +            { +                // Delete any selected characters (the tooltip text replaces them) +                if(hasSelection()) +                { +                    deleteSelection(TRUE); +                } + +                std::basic_string<llwchar>::size_type pos = tool_tip_text.find('\n',0); +                if (pos != -1) +                {   // Extract the first line of the tooltip +                    tool_tip_text = std::basic_string<llwchar>(tool_tip_text, 0, pos); +                } + +                // Add the text +                cleanStringForPaste(tool_tip_text); +                pasteTextWithLinebreaks(tool_tip_text); +                handled = TRUE; +            } +        } +        else +        {   // Normal key handling +            handled = handleNavigationKey( key, mask ) +                    || handleSelectionKey(key, mask) +                    || handleControlKey(key, mask) +                    || handleSpecialKey(key, mask); +        } +    } + +    if( handled ) +    { +        resetCursorBlink(); +        needsScroll(); + +        if (mShowEmojiHelper) +        { +            // Dismiss the helper whenever we handled a key that it didn't +            LLEmojiHelper::instance().hideHelper(this); +        } +    } + +    return handled;  }  BOOL LLTextEditor::handleUnicodeCharHere(llwchar uni_char)  { -	if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL -	{ -		return FALSE; -	} +    if ((uni_char < 0x20) || (uni_char == 0x7F)) // Control character or DEL +    { +        return FALSE; +    } -	BOOL	handled = FALSE; +    BOOL    handled = FALSE; -	// Handle most keys only if the text editor is writeable. -	if( !mReadOnly ) -	{ +    // Handle most keys only if the text editor is writeable. +    if( !mReadOnly ) +    {          if (mShowEmojiHelper && uni_char < 0x80 && LLEmojiHelper::instance().handleKey(this, (KEY)uni_char, MASK_NONE))          {              return TRUE;          }          if( mAutoIndent && '}' == uni_char ) -		{ -			unindentLineBeforeCloseBrace(); -		} +        { +            unindentLineBeforeCloseBrace(); +        } -		// TODO: KLW Add auto show of tool tip on ( -		addChar( uni_char ); +        // TODO: KLW Add auto show of tool tip on ( +        addChar( uni_char ); -		// Keys that add characters temporarily hide the cursor -		getWindow()->hideCursorUntilMouseMove(); +        // Keys that add characters temporarily hide the cursor +        getWindow()->hideCursorUntilMouseMove(); -		handled = TRUE; -	} +        handled = TRUE; +    } -	if( handled ) -	{ -		resetCursorBlink(); +    if( handled ) +    { +        resetCursorBlink(); -		// Most keystrokes will make the selection box go away, but not all will. -		deselect(); +        // Most keystrokes will make the selection box go away, but not all will. +        deselect(); -		onKeyStroke(); -	} +        onKeyStroke(); +    } -	return handled; +    return handled;  }  // virtual  BOOL LLTextEditor::canDoDelete() const  { -	return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) ); +    return !mReadOnly && ( !mPassDelete || ( hasSelection() || (mCursorPos < getLength())) );  }  void LLTextEditor::doDelete()  { -	if( !canDoDelete() ) -	{ -		return; -	} -	if( hasSelection() ) -	{ -		deleteSelection(FALSE); -	} -	else -	if( mCursorPos < getLength() ) -	{	 -		S32 i; -		S32 chars_to_remove = 1; -		LLWString text = getWText(); -		if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) -		{ -			// Try to remove a full tab's worth of spaces -			S32 offset = getLineOffsetFromDocIndex(mCursorPos); -			chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); -			if( chars_to_remove == 0 ) -			{ -				chars_to_remove = SPACES_PER_TAB; -			} - -			for( i = 0; i < chars_to_remove; i++ ) -			{ -				if( text[mCursorPos + i] != ' ' ) -				{ -					chars_to_remove = 1; -					break; -				} -			} -		} - -		for( i = 0; i < chars_to_remove; i++ ) -		{ -			setCursorPos(mCursorPos + 1); -			removeChar(); -		} - -	} - -	onKeyStroke(); +    if( !canDoDelete() ) +    { +        return; +    } +    if( hasSelection() ) +    { +        deleteSelection(FALSE); +    } +    else +    if( mCursorPos < getLength() ) +    { +        S32 i; +        S32 chars_to_remove = 1; +        LLWString text = getWText(); +        if( (text[ mCursorPos ] == ' ') && (mCursorPos + SPACES_PER_TAB < getLength()) ) +        { +            // Try to remove a full tab's worth of spaces +            S32 offset = getLineOffsetFromDocIndex(mCursorPos); +            chars_to_remove = SPACES_PER_TAB - (offset % SPACES_PER_TAB); +            if( chars_to_remove == 0 ) +            { +                chars_to_remove = SPACES_PER_TAB; +            } + +            for( i = 0; i < chars_to_remove; i++ ) +            { +                if( text[mCursorPos + i] != ' ' ) +                { +                    chars_to_remove = 1; +                    break; +                } +            } +        } + +        for( i = 0; i < chars_to_remove; i++ ) +        { +            setCursorPos(mCursorPos + 1); +            removeChar(); +        } + +    } + +    onKeyStroke();  }  //---------------------------------------------------------------------------- @@ -2018,624 +2031,624 @@ void LLTextEditor::doDelete()  void LLTextEditor::blockUndo()  { -	mBaseDocIsPristine = FALSE; -	mLastCmd = NULL; -	std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); -	mUndoStack.clear(); +    mBaseDocIsPristine = FALSE; +    mLastCmd = NULL; +    std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); +    mUndoStack.clear();  }  // virtual  BOOL LLTextEditor::canUndo() const  { -	return !mReadOnly && mLastCmd != NULL; +    return !mReadOnly && mLastCmd != NULL;  }  void LLTextEditor::undo()  { -	if( !canUndo() ) -	{ -		return; -	} -	deselect(); -	S32 pos = 0; -	do -	{ -		pos = mLastCmd->undo(this); -		undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); -		if (iter != mUndoStack.end()) -			++iter; -		if (iter != mUndoStack.end()) -			mLastCmd = *iter; -		else -			mLastCmd = NULL; +    if( !canUndo() ) +    { +        return; +    } +    deselect(); +    S32 pos = 0; +    do +    { +        pos = mLastCmd->undo(this); +        undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); +        if (iter != mUndoStack.end()) +            ++iter; +        if (iter != mUndoStack.end()) +            mLastCmd = *iter; +        else +            mLastCmd = NULL; -		} while( mLastCmd && mLastCmd->groupWithNext() ); +        } while( mLastCmd && mLastCmd->groupWithNext() ); -		setCursorPos(pos); +        setCursorPos(pos); -	onKeyStroke(); +    onKeyStroke();  }  BOOL LLTextEditor::canRedo() const  { -	return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front()); +    return !mReadOnly && (mUndoStack.size() > 0) && (mLastCmd != mUndoStack.front());  }  void LLTextEditor::redo()  { -	if( !canRedo() ) -	{ -		return; -	} -	deselect(); -	S32 pos = 0; -	do -	{ -		if( !mLastCmd ) -		{ -			mLastCmd = mUndoStack.back(); -		} -		else -		{ -			undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); -			if (iter != mUndoStack.begin()) -				mLastCmd = *(--iter); -			else -				mLastCmd = NULL; -		} - -			if( mLastCmd ) -			{ -				pos = mLastCmd->redo(this); -			} -		} while(  -			mLastCmd && -			mLastCmd->groupWithNext() && -			(mLastCmd != mUndoStack.front()) ); -		 -		setCursorPos(pos); - -	onKeyStroke(); +    if( !canRedo() ) +    { +        return; +    } +    deselect(); +    S32 pos = 0; +    do +    { +        if( !mLastCmd ) +        { +            mLastCmd = mUndoStack.back(); +        } +        else +        { +            undo_stack_t::iterator iter = std::find(mUndoStack.begin(), mUndoStack.end(), mLastCmd); +            if (iter != mUndoStack.begin()) +                mLastCmd = *(--iter); +            else +                mLastCmd = NULL; +        } + +            if( mLastCmd ) +            { +                pos = mLastCmd->redo(this); +            } +        } while( +            mLastCmd && +            mLastCmd->groupWithNext() && +            (mLastCmd != mUndoStack.front()) ); + +        setCursorPos(pos); + +    onKeyStroke();  }  void LLTextEditor::onFocusReceived()  { -	LLTextBase::onFocusReceived(); -	updateAllowingLanguageInput(); +    LLTextBase::onFocusReceived(); +    updateAllowingLanguageInput();  }  void LLTextEditor::focusLostHelper()  { -	updateAllowingLanguageInput(); +    updateAllowingLanguageInput(); -	// Route menu back to the default - 	if( gEditMenuHandler == this ) -	{ -		gEditMenuHandler = NULL; -	} +    // Route menu back to the default +    if( gEditMenuHandler == this ) +    { +        gEditMenuHandler = NULL; +    } -	if (mCommitOnFocusLost) -	{ -		onCommit(); -	} +    if (mCommitOnFocusLost) +    { +        onCommit(); +    } -	// Make sure cursor is shown again -	getWindow()->showCursorFromMouseMove(); +    // Make sure cursor is shown again +    getWindow()->showCursorFromMouseMove();  }  void LLTextEditor::onFocusLost()  { -	focusLostHelper(); -	LLTextBase::onFocusLost(); +    focusLostHelper(); +    LLTextBase::onFocusLost();  }  void LLTextEditor::onCommit()  { -	setControlValue(getValue());  -	LLTextBase::onCommit();  +    setControlValue(getValue()); +    LLTextBase::onCommit();  }  void LLTextEditor::setEnabled(BOOL enabled)  { -	// just treat enabled as read-only flag -	bool read_only = !enabled; -	if (read_only != mReadOnly) -	{ -		//mReadOnly = read_only; -		LLTextBase::setReadOnly(read_only); -		updateSegments(); -		updateAllowingLanguageInput(); -	} +    // just treat enabled as read-only flag +    bool read_only = !enabled; +    if (read_only != mReadOnly) +    { +        //mReadOnly = read_only; +        LLTextBase::setReadOnly(read_only); +        updateSegments(); +        updateAllowingLanguageInput(); +    }  }  void LLTextEditor::showContextMenu(S32 x, S32 y)  { -	LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); -	if (!menu) -	{ -		llassert(LLMenuGL::sMenuContainer != NULL); -		menu = LLUICtrlFactory::createFromFile<LLContextMenu>("menu_text_editor.xml",  -																				LLMenuGL::sMenuContainer,  -																				LLMenuHolderGL::child_registry_t::instance()); +    LLContextMenu* menu = static_cast<LLContextMenu*>(mContextMenuHandle.get()); +    if (!menu) +    { +        llassert(LLMenuGL::sMenuContainer != NULL); +        menu = LLUICtrlFactory::createFromFile<LLContextMenu>("menu_text_editor.xml", +                                                                                LLMenuGL::sMenuContainer, +                                                                                LLMenuHolderGL::child_registry_t::instance());          if(!menu)          {              LL_WARNS() << "Failed to create menu for LLTextEditor: " << getName() << LL_ENDL;              return;          } -		mContextMenuHandle = menu->getHandle(); -	} - -	// Route menu to this class -	// previously this was done in ::handleRightMoseDown: -	//if(hasTabStop()) -	// setFocus(TRUE)  - why? weird... -	// and then inside setFocus -	// .... -	//    gEditMenuHandler = this; -	// .... -	// but this didn't work in all cases and just weird... -    //why not here?  -	// (all this was done for EXT-4443) - -	gEditMenuHandler = this; - -	S32 screen_x, screen_y; -	localPointToScreen(x, y, &screen_x, &screen_y); - -	setCursorAtLocalPos(x, y, false); -	if (hasSelection()) -	{ -		if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) -		{ -			deselect(); -		} -		else -		{ -			setCursorPos(llmax(mSelectionStart, mSelectionEnd)); -		} -	} - -	bool use_spellcheck = getSpellCheck(), is_misspelled = false; -	if (use_spellcheck) -	{ -		mSuggestionList.clear(); - -		// If the cursor is on a misspelled word, retrieve suggestions for it -		std::string misspelled_word = getMisspelledWord(mCursorPos); -		if ((is_misspelled = !misspelled_word.empty()) == true) -		{ -			LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); -		} -	} - -	menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); -	menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); -	menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); -	menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); -	menu->show(screen_x, screen_y, this); +        mContextMenuHandle = menu->getHandle(); +    } + +    // Route menu to this class +    // previously this was done in ::handleRightMoseDown: +    //if(hasTabStop()) +    // setFocus(TRUE)  - why? weird... +    // and then inside setFocus +    // .... +    //    gEditMenuHandler = this; +    // .... +    // but this didn't work in all cases and just weird... +    //why not here? +    // (all this was done for EXT-4443) + +    gEditMenuHandler = this; + +    S32 screen_x, screen_y; +    localPointToScreen(x, y, &screen_x, &screen_y); + +    setCursorAtLocalPos(x, y, false); +    if (hasSelection()) +    { +        if ( (mCursorPos < llmin(mSelectionStart, mSelectionEnd)) || (mCursorPos > llmax(mSelectionStart, mSelectionEnd)) ) +        { +            deselect(); +        } +        else +        { +            setCursorPos(llmax(mSelectionStart, mSelectionEnd)); +        } +    } + +    bool use_spellcheck = getSpellCheck(), is_misspelled = false; +    if (use_spellcheck) +    { +        mSuggestionList.clear(); + +        // If the cursor is on a misspelled word, retrieve suggestions for it +        std::string misspelled_word = getMisspelledWord(mCursorPos); +        if ((is_misspelled = !misspelled_word.empty()) == true) +        { +            LLSpellChecker::instance().getSuggestions(misspelled_word, mSuggestionList); +        } +    } + +    menu->setItemVisible("Suggestion Separator", (use_spellcheck) && (!mSuggestionList.empty())); +    menu->setItemVisible("Add to Dictionary", (use_spellcheck) && (is_misspelled)); +    menu->setItemVisible("Add to Ignore", (use_spellcheck) && (is_misspelled)); +    menu->setItemVisible("Spellcheck Separator", (use_spellcheck) && (is_misspelled)); +    menu->show(screen_x, screen_y, this);  }  void LLTextEditor::drawPreeditMarker()  { -	static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); -	static LLUICachedControl<S32> preedit_marker_gap ("UIPreeditMarkerGap", 0); -	static LLUICachedControl<S32> preedit_marker_position ("UIPreeditMarkerPosition", 0); -	static LLUICachedControl<S32> preedit_marker_thickness ("UIPreeditMarkerThickness", 0); -	static LLUICachedControl<F32> preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); -	static LLUICachedControl<S32> preedit_standout_gap ("UIPreeditStandoutGap", 0); -	static LLUICachedControl<S32> preedit_standout_position ("UIPreeditStandoutPosition", 0); -	static LLUICachedControl<S32> preedit_standout_thickness ("UIPreeditStandoutThickness", 0); +    static LLUICachedControl<F32> preedit_marker_brightness ("UIPreeditMarkerBrightness", 0); +    static LLUICachedControl<S32> preedit_marker_gap ("UIPreeditMarkerGap", 0); +    static LLUICachedControl<S32> preedit_marker_position ("UIPreeditMarkerPosition", 0); +    static LLUICachedControl<S32> preedit_marker_thickness ("UIPreeditMarkerThickness", 0); +    static LLUICachedControl<F32> preedit_standout_brightness ("UIPreeditStandoutBrightness", 0); +    static LLUICachedControl<S32> preedit_standout_gap ("UIPreeditStandoutGap", 0); +    static LLUICachedControl<S32> preedit_standout_position ("UIPreeditStandoutPosition", 0); +    static LLUICachedControl<S32> preedit_standout_thickness ("UIPreeditStandoutThickness", 0); -	if (!hasPreeditString()) -	{ -		return; -	} +    if (!hasPreeditString()) +    { +        return; +    }      const LLWString textString(getWText()); -	const llwchar *text = textString.c_str(); -	const S32 text_len = getLength(); -	const S32 num_lines = getLineCount(); - -	S32 cur_line = getFirstVisibleLine(); -	if (cur_line >= num_lines) -	{ -		return; -	} -		 -	const S32 line_height = mFont->getLineHeight(); - -	S32 line_start = getLineStart(cur_line); -	S32 line_y = mVisibleTextRect.mTop - line_height; -	while((mVisibleTextRect.mBottom <= line_y) && (num_lines > cur_line)) -	{ -		S32 next_start = -1; -		S32 line_end = text_len; - -		if ((cur_line + 1) < num_lines) -		{ -			next_start = getLineStart(cur_line + 1); -			line_end = next_start; -		} -		if ( text[line_end-1] == '\n' ) -		{ -			--line_end; -		} - -		// Does this line contain preedits? -		if (line_start >= mPreeditPositions.back()) -		{ -			// We have passed the preedits. -			break; -		} -		if (line_end > mPreeditPositions.front()) -		{ -			for (U32 i = 0; i < mPreeditStandouts.size(); i++) -			{ -				S32 left = mPreeditPositions[i]; -				S32 right = mPreeditPositions[i + 1]; -				if (right <= line_start || left >= line_end) -				{ -					continue; -				} - -				line_info& line = mLineInfoList[cur_line]; -				LLRect text_rect(line.mRect); -				text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents -				text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position - -				S32 preedit_left = text_rect.mLeft; -				if (left > line_start) -				{ -					preedit_left += mFont->getWidth(text, line_start, left - line_start); -				} -				S32 preedit_right = text_rect.mLeft; -				if (right < line_end) -				{ -					preedit_right += mFont->getWidth(text, line_start, right - line_start); -				} -				else -				{ -					preedit_right += mFont->getWidth(text, line_start, line_end - line_start); -				} - -				if (mPreeditStandouts[i]) -				{ -					gl_rect_2d(preedit_left + preedit_standout_gap, -							   text_rect.mBottom + mFont->getDescenderHeight() - 1, -							   preedit_right - preedit_standout_gap - 1, -							   text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_standout_thickness, -							   (mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f)); -				} -				else -				{ -					gl_rect_2d(preedit_left + preedit_marker_gap, -							   text_rect.mBottom + mFont->getDescenderHeight() - 1, -							   preedit_right - preedit_marker_gap - 1, -							   text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_marker_thickness, -							   (mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f)); -				} -			} -		} - -		// move down one line -		line_y -= line_height; -		line_start = next_start; -		cur_line++; -	} +    const llwchar *text = textString.c_str(); +    const S32 text_len = getLength(); +    const S32 num_lines = getLineCount(); + +    S32 cur_line = getFirstVisibleLine(); +    if (cur_line >= num_lines) +    { +        return; +    } + +    const S32 line_height = mFont->getLineHeight(); + +    S32 line_start = getLineStart(cur_line); +    S32 line_y = mVisibleTextRect.mTop - line_height; +    while((mVisibleTextRect.mBottom <= line_y) && (num_lines > cur_line)) +    { +        S32 next_start = -1; +        S32 line_end = text_len; + +        if ((cur_line + 1) < num_lines) +        { +            next_start = getLineStart(cur_line + 1); +            line_end = next_start; +        } +        if ( text[line_end-1] == '\n' ) +        { +            --line_end; +        } + +        // Does this line contain preedits? +        if (line_start >= mPreeditPositions.back()) +        { +            // We have passed the preedits. +            break; +        } +        if (line_end > mPreeditPositions.front()) +        { +            for (U32 i = 0; i < mPreeditStandouts.size(); i++) +            { +                S32 left = mPreeditPositions[i]; +                S32 right = mPreeditPositions[i + 1]; +                if (right <= line_start || left >= line_end) +                { +                    continue; +                } + +                line_info& line = mLineInfoList[cur_line]; +                LLRect text_rect(line.mRect); +                text_rect.mRight = mDocumentView->getRect().getWidth(); // clamp right edge to document extents +                text_rect.translate(mDocumentView->getRect().mLeft, mDocumentView->getRect().mBottom); // adjust by scroll position + +                S32 preedit_left = text_rect.mLeft; +                if (left > line_start) +                { +                    preedit_left += mFont->getWidth(text, line_start, left - line_start); +                } +                S32 preedit_right = text_rect.mLeft; +                if (right < line_end) +                { +                    preedit_right += mFont->getWidth(text, line_start, right - line_start); +                } +                else +                { +                    preedit_right += mFont->getWidth(text, line_start, line_end - line_start); +                } + +                if (mPreeditStandouts[i]) +                { +                    gl_rect_2d(preedit_left + preedit_standout_gap, +                               text_rect.mBottom + mFont->getDescenderHeight() - 1, +                               preedit_right - preedit_standout_gap - 1, +                               text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_standout_thickness, +                               (mCursorColor.get() * preedit_standout_brightness + mWriteableBgColor.get() * (1 - preedit_standout_brightness)).setAlpha(1.0f)); +                } +                else +                { +                    gl_rect_2d(preedit_left + preedit_marker_gap, +                               text_rect.mBottom + mFont->getDescenderHeight() - 1, +                               preedit_right - preedit_marker_gap - 1, +                               text_rect.mBottom + mFont->getDescenderHeight() - 1 - preedit_marker_thickness, +                               (mCursorColor.get() * preedit_marker_brightness + mWriteableBgColor.get() * (1 - preedit_marker_brightness)).setAlpha(1.0f)); +                } +            } +        } + +        // move down one line +        line_y -= line_height; +        line_start = next_start; +        cur_line++; +    }  }  void LLTextEditor::draw()  { -	{ -		// pad clipping rectangle so that cursor can draw at full width -		// when at left edge of mVisibleTextRect -		LLRect clip_rect(mVisibleTextRect); -		clip_rect.stretch(1); -		LLLocalClipRect clip(clip_rect); -	} +    { +        // pad clipping rectangle so that cursor can draw at full width +        // when at left edge of mVisibleTextRect +        LLRect clip_rect(mVisibleTextRect); +        clip_rect.stretch(1); +        LLLocalClipRect clip(clip_rect); +    } -	LLTextBase::draw(); +    LLTextBase::draw();      drawPreeditMarker(); -	//RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret -	// when in readonly mode -	mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly); +    //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret +    // when in readonly mode +    mBorder->setKeyboardFocusHighlight( hasFocus() );// && !mReadOnly);  }  // Start or stop the editor from accepting text-editing keystrokes  // see also LLLineEditor  void LLTextEditor::setFocus( BOOL new_state )  { -	BOOL old_state = hasFocus(); +    BOOL old_state = hasFocus(); -	// Don't change anything if the focus state didn't change -	if (new_state == old_state) return; +    // Don't change anything if the focus state didn't change +    if (new_state == old_state) return; -	// Notify early if we are losing focus. -	if (!new_state) -	{ -		getWindow()->allowLanguageTextInput(this, FALSE); -	} +    // Notify early if we are losing focus. +    if (!new_state) +    { +        getWindow()->allowLanguageTextInput(this, FALSE); +    } -	LLTextBase::setFocus( new_state ); +    LLTextBase::setFocus( new_state ); -	if( new_state ) -	{ -		// Route menu to this class -		gEditMenuHandler = this; +    if( new_state ) +    { +        // Route menu to this class +        gEditMenuHandler = this; -		// Don't start the cursor flashing right away -		resetCursorBlink(); -	} -	else -	{ -		// Route menu back to the default -		if( gEditMenuHandler == this ) -		{ -			gEditMenuHandler = NULL; -		} +        // Don't start the cursor flashing right away +        resetCursorBlink(); +    } +    else +    { +        // Route menu back to the default +        if( gEditMenuHandler == this ) +        { +            gEditMenuHandler = NULL; +        } -		endSelection(); -	} +        endSelection(); +    }  }  // public  void LLTextEditor::setCursorAndScrollToEnd()  { -	deselect(); -	endOfDoc(); +    deselect(); +    endOfDoc();  } -void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap )  -{  -	*line = getLineNumFromDocIndex(mCursorPos, include_wordwrap); -	*col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap); +void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap ) +{ +    *line = getLineNumFromDocIndex(mCursorPos, include_wordwrap); +    *col = getLineOffsetFromDocIndex(mCursorPos, include_wordwrap);  }  void LLTextEditor::autoIndent()  { -	// Count the number of spaces in the current line -	S32 line = getLineNumFromDocIndex(mCursorPos, false); -	S32 line_start = getLineStart(line); -	S32 space_count = 0; -	S32 i; +    // Count the number of spaces in the current line +    S32 line = getLineNumFromDocIndex(mCursorPos, false); +    S32 line_start = getLineStart(line); +    S32 space_count = 0; +    S32 i; -	LLWString text = getWText(); -	S32 offset = getLineOffsetFromDocIndex(mCursorPos); -	while(( ' ' == text[line_start] ) && (space_count < offset)) -	{ -		space_count++; -		line_start++; -	} +    LLWString text = getWText(); +    S32 offset = getLineOffsetFromDocIndex(mCursorPos); +    while(( ' ' == text[line_start] ) && (space_count < offset)) +    { +        space_count++; +        line_start++; +    } -	// If we're starting a braced section, indent one level. -	if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') ) -	{ -		space_count += SPACES_PER_TAB; -	} +    // If we're starting a braced section, indent one level. +    if( (mCursorPos > 0) && (text[mCursorPos -1] == '{') ) +    { +        space_count += SPACES_PER_TAB; +    } -	// Insert that number of spaces on the new line +    // Insert that number of spaces on the new line -	//appendLineBreakSegment(LLStyle::Params());//addChar( '\n' ); -	addLineBreakChar(); +    //appendLineBreakSegment(LLStyle::Params());//addChar( '\n' ); +    addLineBreakChar(); -	for( i = 0; i < space_count; i++ ) -	{ -		addChar( ' ' ); -	} +    for( i = 0; i < space_count; i++ ) +    { +        addChar( ' ' ); +    }  }  // Inserts new text at the cursor position  void LLTextEditor::insertText(const std::string &new_text)  { -	BOOL enabled = getEnabled(); -	setEnabled( TRUE ); +    BOOL enabled = getEnabled(); +    setEnabled( TRUE ); -	// Delete any selected characters (the insertion replaces them) -	if( hasSelection() ) -	{ -		deleteSelection(TRUE); -	} +    // Delete any selected characters (the insertion replaces them) +    if( hasSelection() ) +    { +        deleteSelection(TRUE); +    } + +    setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() )); -	setCursorPos(mCursorPos + insert( mCursorPos, utf8str_to_wstring(new_text), FALSE, LLTextSegmentPtr() )); -	 -	setEnabled( enabled ); +    setEnabled( enabled );  }  void LLTextEditor::insertText(LLWString &new_text)  { -	BOOL enabled = getEnabled(); -	setEnabled( TRUE ); +    BOOL enabled = getEnabled(); +    setEnabled( TRUE ); -	// Delete any selected characters (the insertion replaces them) -	if( hasSelection() ) -	{ -		deleteSelection(TRUE); -	} +    // Delete any selected characters (the insertion replaces them) +    if( hasSelection() ) +    { +        deleteSelection(TRUE); +    } -	setCursorPos(mCursorPos + insert( mCursorPos, new_text, FALSE, LLTextSegmentPtr() )); +    setCursorPos(mCursorPos + insert( mCursorPos, new_text, FALSE, LLTextSegmentPtr() )); -	setEnabled( enabled ); +    setEnabled( enabled );  }  void LLTextEditor::appendWidget(const LLInlineViewSegment::Params& params, const std::string& text, bool allow_undo)  { -	// Save old state -	S32 selection_start = mSelectionStart; -	S32 selection_end = mSelectionEnd; -	BOOL was_selecting = mIsSelecting; -	S32 cursor_pos = mCursorPos; -	S32 old_length = getLength(); -	BOOL cursor_was_at_end = (mCursorPos == old_length); +    // Save old state +    S32 selection_start = mSelectionStart; +    S32 selection_end = mSelectionEnd; +    BOOL was_selecting = mIsSelecting; +    S32 cursor_pos = mCursorPos; +    S32 old_length = getLength(); +    BOOL cursor_was_at_end = (mCursorPos == old_length); -	deselect(); +    deselect(); -	setCursorPos(old_length); +    setCursorPos(old_length); -	LLWString widget_wide_text = utf8str_to_wstring(text); +    LLWString widget_wide_text = utf8str_to_wstring(text); -	LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size()); -	insert(getLength(), widget_wide_text, FALSE, segment); +    LLTextSegmentPtr segment = new LLInlineViewSegment(params, old_length, old_length + widget_wide_text.size()); +    insert(getLength(), widget_wide_text, FALSE, segment); -	// Set the cursor and scroll position -	if( selection_start != selection_end ) -	{ -		mSelectionStart = selection_start; -		mSelectionEnd = selection_end; +    // Set the cursor and scroll position +    if( selection_start != selection_end ) +    { +        mSelectionStart = selection_start; +        mSelectionEnd = selection_end; -		mIsSelecting = was_selecting; -		setCursorPos(cursor_pos); -	} -	else if( cursor_was_at_end ) -	{ -		setCursorPos(getLength()); -	} -	else -	{ -		setCursorPos(cursor_pos); -	} +        mIsSelecting = was_selecting; +        setCursorPos(cursor_pos); +    } +    else if( cursor_was_at_end ) +    { +        setCursorPos(getLength()); +    } +    else +    { +        setCursorPos(cursor_pos); +    } -	if (!allow_undo) -	{ -		blockUndo(); -	} +    if (!allow_undo) +    { +        blockUndo(); +    }  }  void LLTextEditor::removeTextFromEnd(S32 num_chars)  { -	if (num_chars <= 0) return; +    if (num_chars <= 0) return; -	remove(getLength() - num_chars, num_chars, FALSE); +    remove(getLength() - num_chars, num_chars, FALSE); -	S32 len = getLength(); -	setCursorPos (llclamp(mCursorPos, 0, len)); -	mSelectionStart = llclamp(mSelectionStart, 0, len); -	mSelectionEnd = llclamp(mSelectionEnd, 0, len); +    S32 len = getLength(); +    setCursorPos (llclamp(mCursorPos, 0, len)); +    mSelectionStart = llclamp(mSelectionStart, 0, len); +    mSelectionEnd = llclamp(mSelectionEnd, 0, len); -	needsScroll(); +    needsScroll();  }  //----------------------------------------------------------------------------  void LLTextEditor::onSpellCheckPerformed()  { -	if (isPristine()) -	{ -		mBaseDocIsPristine = FALSE; -	} +    if (isPristine()) +    { +        mBaseDocIsPristine = FALSE; +    }  }  void LLTextEditor::makePristine()  { -	mPristineCmd = mLastCmd; -	mBaseDocIsPristine = !mLastCmd; +    mPristineCmd = mLastCmd; +    mBaseDocIsPristine = !mLastCmd; -	// Create a clean partition in the undo stack.  We don't want a single command to extend from -	// the "pre-pristine" state to the "post-pristine" state. -	if( mLastCmd ) -	{ -		mLastCmd->blockExtensions(); -	} +    // Create a clean partition in the undo stack.  We don't want a single command to extend from +    // the "pre-pristine" state to the "post-pristine" state. +    if( mLastCmd ) +    { +        mLastCmd->blockExtensions(); +    }  }  BOOL LLTextEditor::isPristine() const  { -	if( mPristineCmd ) -	{ -		return (mPristineCmd == mLastCmd); -	} -	else -	{ -		// No undo stack, so check if the version before and commands were done was the original version -		return !mLastCmd && mBaseDocIsPristine; -	} +    if( mPristineCmd ) +    { +        return (mPristineCmd == mLastCmd); +    } +    else +    { +        // No undo stack, so check if the version before and commands were done was the original version +        return !mLastCmd && mBaseDocIsPristine; +    }  }  BOOL LLTextEditor::tryToRevertToPristineState()  { -	if( !isPristine() ) -	{ -		deselect(); -		S32 i = 0; -		while( !isPristine() && canUndo() ) -		{ -			undo(); -			i--; -		} - -		while( !isPristine() && canRedo() ) -		{ -			redo(); -			i++; -		} - -		if( !isPristine() ) -		{ -			// failed, so go back to where we started -			while( i > 0 ) -			{ -				undo(); -				i--; -			} -		} -	} - -	return isPristine(); // TRUE => success +    if( !isPristine() ) +    { +        deselect(); +        S32 i = 0; +        while( !isPristine() && canUndo() ) +        { +            undo(); +            i--; +        } + +        while( !isPristine() && canRedo() ) +        { +            redo(); +            i++; +        } + +        if( !isPristine() ) +        { +            // failed, so go back to where we started +            while( i > 0 ) +            { +                undo(); +                i--; +            } +        } +    } + +    return isPristine(); // TRUE => success  }  void LLTextEditor::updateLinkSegments()  { -	LLWString wtext = getWText(); - -	// update any segments that contain a link -	for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it) -	{ -		LLTextSegment *segment = *it; -		if (segment && segment->getStyle() && segment->getStyle()->isLink()) -		{ -			LLStyleConstSP style = segment->getStyle(); -			LLStyleSP new_style(new LLStyle(*style)); -			LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); - -			segment_set_t::const_iterator next_it = mSegments.upper_bound(segment); -			LLTextSegment *next_segment = *next_it; -			if (next_segment) -			{ -				LLWString next_url_label = wtext.substr(next_segment->getStart(), next_segment->getEnd()-next_segment->getStart()); -				std::string link_check = wstring_to_utf8str(url_label) + wstring_to_utf8str(next_url_label); -				LLUrlMatch match; - -				if ( LLUrlRegistry::instance().findUrl(link_check, match)) -				{ -					if(match.getQuery() == wstring_to_utf8str(next_url_label)) -					{ -						continue; -					} -				} -			} -			 -			// if the link's label (what the user can edit) is a valid Url, -			// then update the link's HREF to be the same as the label text. -			// This lets users edit Urls in-place. -			if (acceptsTextInput() && LLUrlRegistry::instance().hasUrl(url_label)) -			{ -				std::string new_url = wstring_to_utf8str(url_label); -				LLStringUtil::trim(new_url); -				new_style->setLinkHREF(new_url); -				LLStyleConstSP sp(new_style); -				segment->setStyle(sp); -			} -		} -	} +    LLWString wtext = getWText(); + +    // update any segments that contain a link +    for (segment_set_t::iterator it = mSegments.begin(); it != mSegments.end(); ++it) +    { +        LLTextSegment *segment = *it; +        if (segment && segment->getStyle() && segment->getStyle()->isLink()) +        { +            LLStyleConstSP style = segment->getStyle(); +            LLStyleSP new_style(new LLStyle(*style)); +            LLWString url_label = wtext.substr(segment->getStart(), segment->getEnd()-segment->getStart()); + +            segment_set_t::const_iterator next_it = mSegments.upper_bound(segment); +            LLTextSegment *next_segment = *next_it; +            if (next_segment) +            { +                LLWString next_url_label = wtext.substr(next_segment->getStart(), next_segment->getEnd()-next_segment->getStart()); +                std::string link_check = wstring_to_utf8str(url_label) + wstring_to_utf8str(next_url_label); +                LLUrlMatch match; + +                if ( LLUrlRegistry::instance().findUrl(link_check, match)) +                { +                    if(match.getQuery() == wstring_to_utf8str(next_url_label)) +                    { +                        continue; +                    } +                } +            } + +            // if the link's label (what the user can edit) is a valid Url, +            // then update the link's HREF to be the same as the label text. +            // This lets users edit Urls in-place. +            if (acceptsTextInput() && LLUrlRegistry::instance().hasUrl(url_label)) +            { +                std::string new_url = wstring_to_utf8str(url_label); +                LLStringUtil::trim(new_url); +                new_style->setLinkHREF(new_url); +                LLStyleConstSP sp(new_style); +                segment->setStyle(sp); +            } +        } +    }  }  void LLTextEditor::onMouseCaptureLost()  { -	endSelection(); +    endSelection();  }  /////////////////////////////////////////////////////////////////// @@ -2643,135 +2656,135 @@ void LLTextEditor::onMouseCaptureLost()  BOOL LLTextEditor::importBuffer(const char* buffer, S32 length )  { -	std::istringstream instream(buffer); -	 -	// Version 1 format: -	//		Linden text version 1\n -	//		{\n -	//			<EmbeddedItemList chunk> -	//			Text length <bytes without \0>\n -	//			<text without \0> (text may contain ext_char_values) -	//		}\n - -	char tbuf[MAX_STRING];	/* Flawfinder: ignore */ -	 -	S32 version = 0; -	instream.getline(tbuf, MAX_STRING); -	if( 1 != sscanf(tbuf, "Linden text version %d", &version) ) -	{ -		LL_WARNS() << "Invalid Linden text file header " << LL_ENDL; -		return FALSE; -	} - -	if( 1 != version ) -	{ -		LL_WARNS() << "Invalid Linden text file version: " << version << LL_ENDL; -		return FALSE; -	} - -	instream.getline(tbuf, MAX_STRING); -	if( 0 != sscanf(tbuf, "{") ) -	{ -		LL_WARNS() << "Invalid Linden text file format" << LL_ENDL; -		return FALSE; -	} - -	S32 text_len = 0; -	instream.getline(tbuf, MAX_STRING); -	if( 1 != sscanf(tbuf, "Text length %d", &text_len) ) -	{ -		LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; -		return FALSE; -	} - -	if( text_len > mMaxTextByteLength ) -	{ -		LL_WARNS() << "Invalid Linden text length: " << text_len << LL_ENDL; -		return FALSE; -	} - -	BOOL success = TRUE; - -	char* text = new char[ text_len + 1]; -	if (text == NULL) -	{ +    std::istringstream instream(buffer); + +    // Version 1 format: +    //      Linden text version 1\n +    //      {\n +    //          <EmbeddedItemList chunk> +    //          Text length <bytes without \0>\n +    //          <text without \0> (text may contain ext_char_values) +    //      }\n + +    char tbuf[MAX_STRING];  /* Flawfinder: ignore */ + +    S32 version = 0; +    instream.getline(tbuf, MAX_STRING); +    if( 1 != sscanf(tbuf, "Linden text version %d", &version) ) +    { +        LL_WARNS() << "Invalid Linden text file header " << LL_ENDL; +        return FALSE; +    } + +    if( 1 != version ) +    { +        LL_WARNS() << "Invalid Linden text file version: " << version << LL_ENDL; +        return FALSE; +    } + +    instream.getline(tbuf, MAX_STRING); +    if( 0 != sscanf(tbuf, "{") ) +    { +        LL_WARNS() << "Invalid Linden text file format" << LL_ENDL; +        return FALSE; +    } + +    S32 text_len = 0; +    instream.getline(tbuf, MAX_STRING); +    if( 1 != sscanf(tbuf, "Text length %d", &text_len) ) +    { +        LL_WARNS() << "Invalid Linden text length field" << LL_ENDL; +        return FALSE; +    } + +    if( text_len > mMaxTextByteLength ) +    { +        LL_WARNS() << "Invalid Linden text length: " << text_len << LL_ENDL; +        return FALSE; +    } + +    BOOL success = TRUE; + +    char* text = new char[ text_len + 1]; +    if (text == NULL) +    {          LLError::LLUserWarningMsg::showOutOfMemory(); -		LL_ERRS() << "Memory allocation failure." << LL_ENDL;			 -		return FALSE; -	} -	instream.get(text, text_len + 1, '\0'); -	text[text_len] = '\0'; -	if( text_len != (S32)strlen(text) )/* Flawfinder: ignore */ -	{ -		LL_WARNS() << llformat("Invalid text length: %d != %d ",strlen(text),text_len) << LL_ENDL;/* Flawfinder: ignore */ -		success = FALSE; -	} - -	instream.getline(tbuf, MAX_STRING); -	if( success && (0 != sscanf(tbuf, "}")) ) -	{ -		LL_WARNS() << "Invalid Linden text file format: missing terminal }" << LL_ENDL; -		success = FALSE; -	} - -	if( success ) -	{ -		// Actually set the text -		setText( LLStringExplicit(text) ); -	} - -	delete[] text; - -	startOfDoc(); -	deselect(); - -	return success; +        LL_ERRS() << "Memory allocation failure." << LL_ENDL; +        return FALSE; +    } +    instream.get(text, text_len + 1, '\0'); +    text[text_len] = '\0'; +    if( text_len != (S32)strlen(text) )/* Flawfinder: ignore */ +    { +        LL_WARNS() << llformat("Invalid text length: %d != %d ",strlen(text),text_len) << LL_ENDL;/* Flawfinder: ignore */ +        success = FALSE; +    } + +    instream.getline(tbuf, MAX_STRING); +    if( success && (0 != sscanf(tbuf, "}")) ) +    { +        LL_WARNS() << "Invalid Linden text file format: missing terminal }" << LL_ENDL; +        success = FALSE; +    } + +    if( success ) +    { +        // Actually set the text +        setText( LLStringExplicit(text) ); +    } + +    delete[] text; + +    startOfDoc(); +    deselect(); + +    return success;  }  BOOL LLTextEditor::exportBuffer(std::string &buffer )  { -	std::ostringstream outstream(buffer); -	 -	outstream << "Linden text version 1\n"; -	outstream << "{\n"; +    std::ostringstream outstream(buffer); + +    outstream << "Linden text version 1\n"; +    outstream << "{\n"; -	outstream << llformat("Text length %d\n", getLength() ); -	outstream << getText(); -	outstream << "}\n"; +    outstream << llformat("Text length %d\n", getLength() ); +    outstream << getText(); +    outstream << "}\n"; -	return TRUE; +    return TRUE;  }  void LLTextEditor::updateAllowingLanguageInput()  { -	LLWindow* window = getWindow(); -	if (!window) -	{ -		// test app, no window available -		return;	 -	} -	if (hasFocus() && !mReadOnly) -	{ -		window->allowLanguageTextInput(this, TRUE); -	} -	else -	{ -		window->allowLanguageTextInput(this, FALSE); -	} +    LLWindow* window = getWindow(); +    if (!window) +    { +        // test app, no window available +        return; +    } +    if (hasFocus() && !mReadOnly) +    { +        window->allowLanguageTextInput(this, TRUE); +    } +    else +    { +        window->allowLanguageTextInput(this, FALSE); +    }  }  // Preedit is managed off the undo/redo command stack.  BOOL LLTextEditor::hasPreeditString() const  { -	return (mPreeditPositions.size() > 1); +    return (mPreeditPositions.size() > 1);  }  void LLTextEditor::resetPreedit()  {      if (hasSelection())      { -		if (hasPreeditString()) +        if (hasPreeditString())          {              LL_WARNS() << "Preedit and selection!" << LL_ENDL;              deselect(); @@ -2781,277 +2794,277 @@ void LLTextEditor::resetPreedit()              deleteSelection(TRUE);          }      } -	if (hasPreeditString()) -	{ -		if (hasSelection()) -		{ -			LL_WARNS() << "Preedit and selection!" << LL_ENDL; -			deselect(); -		} +    if (hasPreeditString()) +    { +        if (hasSelection()) +        { +            LL_WARNS() << "Preedit and selection!" << LL_ENDL; +            deselect(); +        } -		setCursorPos(mPreeditPositions.front()); -		removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos); -		insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); +        setCursorPos(mPreeditPositions.front()); +        removeStringNoUndo(mCursorPos, mPreeditPositions.back() - mCursorPos); +        insertStringNoUndo(mCursorPos, mPreeditOverwrittenWString); -		mPreeditWString.clear(); -		mPreeditOverwrittenWString.clear(); -		mPreeditPositions.clear(); +        mPreeditWString.clear(); +        mPreeditOverwrittenWString.clear(); +        mPreeditPositions.clear(); -		// A call to updatePreedit should soon follow under a -		// normal course of operation, so we don't need to  -		// maintain internal variables such as line start  -		// positions now. -	} +        // A call to updatePreedit should soon follow under a +        // normal course of operation, so we don't need to +        // maintain internal variables such as line start +        // positions now. +    }  }  void LLTextEditor::updatePreedit(const LLWString &preedit_string, -		const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position) +        const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position)  { -	// Just in case. -	if (mReadOnly) -	{ -		return; -	} +    // Just in case. +    if (mReadOnly) +    { +        return; +    } -	getWindow()->hideCursorUntilMouseMove(); +    getWindow()->hideCursorUntilMouseMove(); -	S32 insert_preedit_at = mCursorPos; +    S32 insert_preedit_at = mCursorPos; + +    mPreeditWString = preedit_string; +    mPreeditPositions.resize(preedit_segment_lengths.size() + 1); +    S32 position = insert_preedit_at; +    for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) +    { +        mPreeditPositions[i] = position; +        position += preedit_segment_lengths[i]; +    } +    mPreeditPositions.back() = position; -	mPreeditWString = preedit_string; -	mPreeditPositions.resize(preedit_segment_lengths.size() + 1); -	S32 position = insert_preedit_at; -	for (segment_lengths_t::size_type i = 0; i < preedit_segment_lengths.size(); i++) -	{ -		mPreeditPositions[i] = position; -		position += preedit_segment_lengths[i]; -	} -	mPreeditPositions.back() = position; +    if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) +    { +        mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length()); +        removeStringNoUndo(insert_preedit_at, mPreeditWString.length()); +    } +    else +    { +        mPreeditOverwrittenWString.clear(); +    } -	if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) -	{ -		mPreeditOverwrittenWString = getWText().substr(insert_preedit_at, mPreeditWString.length()); -		removeStringNoUndo(insert_preedit_at, mPreeditWString.length()); -	} -	else -	{ -		mPreeditOverwrittenWString.clear(); -	} -     -	segment_vec_t segments; -	//pass empty segments to let "insertStringNoUndo" make new LLNormalTextSegment and insert it, if needed. -	insertStringNoUndo(insert_preedit_at, mPreeditWString, &segments);  +    segment_vec_t segments; +    //pass empty segments to let "insertStringNoUndo" make new LLNormalTextSegment and insert it, if needed. +    insertStringNoUndo(insert_preedit_at, mPreeditWString, &segments); -	mPreeditStandouts = preedit_standouts; +    mPreeditStandouts = preedit_standouts; -	setCursorPos(insert_preedit_at + caret_position); +    setCursorPos(insert_preedit_at + caret_position); -	// Update of the preedit should be caused by some key strokes. -	resetCursorBlink(); +    // Update of the preedit should be caused by some key strokes. +    resetCursorBlink(); -	onKeyStroke(); +    onKeyStroke();  }  BOOL LLTextEditor::getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const  { -	if (control) -	{ -		LLRect control_rect_screen; -		localRectToScreen(mVisibleTextRect, &control_rect_screen); -		LLUI::getInstance()->screenRectToGL(control_rect_screen, control); -	} - -	S32 preedit_left_position, preedit_right_position; -	if (hasPreeditString()) -	{ -		preedit_left_position = mPreeditPositions.front(); -		preedit_right_position = mPreeditPositions.back(); -	} -	else -	{ -		preedit_left_position = preedit_right_position = mCursorPos; -	} - -	const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos); -	if (query < preedit_left_position || query > preedit_right_position) -	{ -		return FALSE; -	} - -	const S32 first_visible_line = getFirstVisibleLine(); -	if (query < getLineStart(first_visible_line)) -	{ -		return FALSE; -	} - -	S32 current_line = first_visible_line; -	S32 current_line_start, current_line_end; -	for (;;) -	{ -		current_line_start = getLineStart(current_line); -		current_line_end = getLineStart(current_line + 1); -		if (query >= current_line_start && query < current_line_end) -		{ -			break; -		} -		if (current_line_start == current_line_end) -		{ -			// We have reached on the last line.  The query position must be here. -			break; -		} -		current_line++; -	} +    if (control) +    { +        LLRect control_rect_screen; +        localRectToScreen(mVisibleTextRect, &control_rect_screen); +        LLUI::getInstance()->screenRectToGL(control_rect_screen, control); +    } + +    S32 preedit_left_position, preedit_right_position; +    if (hasPreeditString()) +    { +        preedit_left_position = mPreeditPositions.front(); +        preedit_right_position = mPreeditPositions.back(); +    } +    else +    { +        preedit_left_position = preedit_right_position = mCursorPos; +    } + +    const S32 query = (query_offset >= 0 ? preedit_left_position + query_offset : mCursorPos); +    if (query < preedit_left_position || query > preedit_right_position) +    { +        return FALSE; +    } + +    const S32 first_visible_line = getFirstVisibleLine(); +    if (query < getLineStart(first_visible_line)) +    { +        return FALSE; +    } + +    S32 current_line = first_visible_line; +    S32 current_line_start, current_line_end; +    for (;;) +    { +        current_line_start = getLineStart(current_line); +        current_line_end = getLineStart(current_line + 1); +        if (query >= current_line_start && query < current_line_end) +        { +            break; +        } +        if (current_line_start == current_line_end) +        { +            // We have reached on the last line.  The query position must be here. +            break; +        } +        current_line++; +    }      const LLWString textString(getWText()); -	const llwchar * const text = textString.c_str(); -	const S32 line_height = mFont->getLineHeight(); - -	if (coord) -	{ -		const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start); -		const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; -		S32 query_screen_x, query_screen_y; -		localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); -		LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); -	} - -	if (bounds) -	{ -		S32 preedit_left = mVisibleTextRect.mLeft; -		if (preedit_left_position > current_line_start) -		{ -			preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); -		} - -		S32 preedit_right = mVisibleTextRect.mLeft; -		if (preedit_right_position < current_line_end) -		{ -			preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); -		} -		else -		{ -			preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start); -		} - -		const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; -		const S32 preedit_bottom = preedit_top - line_height; - -		const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); -		LLRect preedit_rect_screen; -		localRectToScreen(preedit_rect_local, &preedit_rect_screen); -		LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); -	} - -	return TRUE; +    const llwchar * const text = textString.c_str(); +    const S32 line_height = mFont->getLineHeight(); + +    if (coord) +    { +        const S32 query_x = mVisibleTextRect.mLeft + mFont->getWidth(text, current_line_start, query - current_line_start); +        const S32 query_y = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height - line_height / 2; +        S32 query_screen_x, query_screen_y; +        localPointToScreen(query_x, query_y, &query_screen_x, &query_screen_y); +        LLUI::getInstance()->screenPointToGL(query_screen_x, query_screen_y, &coord->mX, &coord->mY); +    } + +    if (bounds) +    { +        S32 preedit_left = mVisibleTextRect.mLeft; +        if (preedit_left_position > current_line_start) +        { +            preedit_left += mFont->getWidth(text, current_line_start, preedit_left_position - current_line_start); +        } + +        S32 preedit_right = mVisibleTextRect.mLeft; +        if (preedit_right_position < current_line_end) +        { +            preedit_right += mFont->getWidth(text, current_line_start, preedit_right_position - current_line_start); +        } +        else +        { +            preedit_right += mFont->getWidth(text, current_line_start, current_line_end - current_line_start); +        } + +        const S32 preedit_top = mVisibleTextRect.mTop - (current_line - first_visible_line) * line_height; +        const S32 preedit_bottom = preedit_top - line_height; + +        const LLRect preedit_rect_local(preedit_left, preedit_top, preedit_right, preedit_bottom); +        LLRect preedit_rect_screen; +        localRectToScreen(preedit_rect_local, &preedit_rect_screen); +        LLUI::getInstance()->screenRectToGL(preedit_rect_screen, bounds); +    } + +    return TRUE;  }  void LLTextEditor::getSelectionRange(S32 *position, S32 *length) const  { -	if (hasSelection()) -	{ -		*position = llmin(mSelectionStart, mSelectionEnd); -		*length = llabs(mSelectionStart - mSelectionEnd); -	} -	else -	{ -		*position = mCursorPos; -		*length = 0; -	} +    if (hasSelection()) +    { +        *position = llmin(mSelectionStart, mSelectionEnd); +        *length = llabs(mSelectionStart - mSelectionEnd); +    } +    else +    { +        *position = mCursorPos; +        *length = 0; +    }  }  void LLTextEditor::getPreeditRange(S32 *position, S32 *length) const  { -	if (hasPreeditString()) -	{ -		*position = mPreeditPositions.front(); -		*length = mPreeditPositions.back() - mPreeditPositions.front(); -	} -	else -	{ -		*position = mCursorPos; -		*length = 0; -	} +    if (hasPreeditString()) +    { +        *position = mPreeditPositions.front(); +        *length = mPreeditPositions.back() - mPreeditPositions.front(); +    } +    else +    { +        *position = mCursorPos; +        *length = 0; +    }  }  void LLTextEditor::markAsPreedit(S32 position, S32 length)  { -	deselect(); -	setCursorPos(position); -	if (hasPreeditString()) -	{ -		LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; -	} -	mPreeditWString = LLWString( getWText(), position, length ); -	if (length > 0) -	{ -		mPreeditPositions.resize(2); -		mPreeditPositions[0] = position; -		mPreeditPositions[1] = position + length; -		mPreeditStandouts.resize(1); -		mPreeditStandouts[0] = FALSE; -	} -	else -	{ -		mPreeditPositions.clear(); -		mPreeditStandouts.clear(); -	} -	if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) -	{ -		mPreeditOverwrittenWString = mPreeditWString; -	} -	else -	{ -		mPreeditOverwrittenWString.clear(); -	} +    deselect(); +    setCursorPos(position); +    if (hasPreeditString()) +    { +        LL_WARNS() << "markAsPreedit invoked when hasPreeditString is true." << LL_ENDL; +    } +    mPreeditWString = LLWString( getWText(), position, length ); +    if (length > 0) +    { +        mPreeditPositions.resize(2); +        mPreeditPositions[0] = position; +        mPreeditPositions[1] = position + length; +        mPreeditStandouts.resize(1); +        mPreeditStandouts[0] = FALSE; +    } +    else +    { +        mPreeditPositions.clear(); +        mPreeditStandouts.clear(); +    } +    if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode()) +    { +        mPreeditOverwrittenWString = mPreeditWString; +    } +    else +    { +        mPreeditOverwrittenWString.clear(); +    }  }  S32 LLTextEditor::getPreeditFontSize() const  { -	return ll_round((F32)mFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]); +    return ll_round((F32)mFont->getLineHeight() * LLUI::getScaleFactor().mV[VY]);  }  BOOL LLTextEditor::isDirty() const  { -	if(mReadOnly) -	{ -		return FALSE; -	} +    if(mReadOnly) +    { +        return FALSE; +    } -	if( mPristineCmd ) -	{ -		return ( mPristineCmd == mLastCmd ); -	} -	else -	{ -		return ( NULL != mLastCmd ); -	} +    if( mPristineCmd ) +    { +        return ( mPristineCmd == mLastCmd ); +    } +    else +    { +        return ( NULL != mLastCmd ); +    }  }  void LLTextEditor::setKeystrokeCallback(const keystroke_signal_t::slot_type& callback)  { -	mKeystrokeSignal.connect(callback); +    mKeystrokeSignal.connect(callback);  }  void LLTextEditor::onKeyStroke()  { -	mKeystrokeSignal(this); +    mKeystrokeSignal(this); -	mSpellCheckStart = mSpellCheckEnd = -1; -	mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY); +    mSpellCheckStart = mSpellCheckEnd = -1; +    mSpellCheckTimer.setTimerExpirySec(SPELLCHECK_DELAY);  }  //virtual  void LLTextEditor::clear()  { -	getViewModel()->setDisplay(LLWStringUtil::null); -	clearSegments(); +    getViewModel()->setDisplay(LLWStringUtil::null); +    clearSegments();  }  bool LLTextEditor::canLoadOrSaveToFile()  { -	return !mReadOnly; +    return !mReadOnly;  }  S32 LLTextEditor::spacesPerTab()  { -	return SPACES_PER_TAB; +    return SPACES_PER_TAB;  }  | 
