Spell check added
This commit is contained in:
@@ -60,13 +60,14 @@
|
||||
#include "lltextparser.h"
|
||||
#include <queue>
|
||||
#include "llmenugl.h"
|
||||
#include "../newview/lgghunspell_wrapper.h"
|
||||
|
||||
//
|
||||
// Globals
|
||||
//
|
||||
static LLRegisterWidget<LLTextEditor> r("simple_text_editor");
|
||||
|
||||
BOOL gDebugTextEditorTips = FALSE;
|
||||
static BOOL bSpellCheckText;
|
||||
|
||||
//
|
||||
// Constants
|
||||
@@ -289,8 +290,11 @@ LLTextEditor::LLTextEditor(
|
||||
mMouseDownY(0),
|
||||
mLastSelectionX(-1),
|
||||
mLastSelectionY(-1),
|
||||
mLastContextMenuX(-1),
|
||||
mLastContextMenuY(-1),
|
||||
mReflowNeeded(FALSE),
|
||||
mScrollNeeded(FALSE)
|
||||
mScrollNeeded(FALSE),
|
||||
mSpellCheckable(FALSE)
|
||||
{
|
||||
mSourceID.generate();
|
||||
|
||||
@@ -354,6 +358,7 @@ LLTextEditor::LLTextEditor(
|
||||
menu->append(new LLMenuItemCallGL("Paste", context_paste, NULL, this));
|
||||
menu->append(new LLMenuItemCallGL("Delete", context_delete, NULL, this));
|
||||
menu->append(new LLMenuItemCallGL("Select All", context_selectall, NULL, this));
|
||||
menu->appendSeparator("Spelsep");
|
||||
menu->setCanTearOff(FALSE);
|
||||
menu->setVisible(FALSE);
|
||||
mPopupMenuHandle = menu->getHandle();
|
||||
@@ -387,6 +392,85 @@ void LLTextEditor::context_copy(void* data)
|
||||
LLTextEditor* line = (LLTextEditor*)data;
|
||||
if(line)line->copy();
|
||||
}
|
||||
|
||||
|
||||
void LLTextEditor::spell_correct(void* data)
|
||||
{
|
||||
SpellMenuBind* tempBind = (SpellMenuBind*)data;
|
||||
LLTextEditor* line = tempBind->origin;
|
||||
if(tempBind && line)
|
||||
{
|
||||
llinfos << tempBind->menuItem->getName() << " : " << tempBind->origin->getName() << " : " << tempBind->word << llendl;
|
||||
if(line)line->spellReplace(tempBind);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLTextEditor::spell_show(void * data)
|
||||
{
|
||||
SpellMenuBind* tempBind = (SpellMenuBind*)data;
|
||||
LLTextEditor* line = tempBind->origin;
|
||||
|
||||
if(tempBind && line)
|
||||
{
|
||||
BOOL show = (tempBind->word == "Show Misspellings");
|
||||
glggHunSpell->setSpellCheckHighlight(show);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<S32> LLTextEditor::getMisspelledWordsPositions()
|
||||
{
|
||||
resetSpellDirty();
|
||||
std::vector<S32> thePosesOfBadWords;
|
||||
LLWString& text = mWText;
|
||||
S32 wordStart=0;
|
||||
S32 wordEnd=spellStart;//start at the scroll start
|
||||
while(wordEnd < spellEnd)
|
||||
{
|
||||
//go through all the chars... XD
|
||||
if( LLTextEditor::isPartOfWord( text[wordEnd] ) )
|
||||
{
|
||||
// Select word the cursor is over
|
||||
while ((wordEnd > 0) && LLTextEditor::isPartOfWord(text[wordEnd-1]))
|
||||
{
|
||||
wordEnd--;
|
||||
}
|
||||
wordStart=wordEnd;
|
||||
while ((wordEnd < (S32)text.length()) && LLTextEditor::isPartOfWord( text[wordEnd] ) )
|
||||
{
|
||||
wordEnd++;
|
||||
}
|
||||
//got a word :D
|
||||
|
||||
std::string regText(text.begin(),text.end());
|
||||
std::string selectedWord(regText.substr(wordStart,wordEnd-wordStart));
|
||||
|
||||
if(!glggHunSpell->isSpelledRight(selectedWord))
|
||||
{
|
||||
//misspelled word here, and you have just right clicked on it
|
||||
|
||||
thePosesOfBadWords.push_back(wordStart);
|
||||
thePosesOfBadWords.push_back(wordEnd);
|
||||
}
|
||||
}
|
||||
wordEnd++;
|
||||
}
|
||||
return thePosesOfBadWords;
|
||||
}
|
||||
|
||||
|
||||
void LLTextEditor::spell_add(void* data)
|
||||
{
|
||||
SpellMenuBind* tempBind = (SpellMenuBind*)data;
|
||||
if(tempBind)
|
||||
{
|
||||
glggHunSpell->addWordToCustomDictionary(tempBind->word);
|
||||
tempBind->origin->mPrevSpelledText.erase();//make it update
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLTextEditor::context_paste(void* data)
|
||||
{
|
||||
LLTextEditor* line = (LLTextEditor*)data;
|
||||
@@ -779,6 +863,26 @@ S32 LLTextEditor::nextWordPos(S32 cursorPos) const
|
||||
return cursorPos;
|
||||
}
|
||||
|
||||
BOOL LLTextEditor::getWordBoundriesAt(const S32 at, S32* word_begin, S32* word_length) const
|
||||
{
|
||||
S32 pos = at;
|
||||
if (isPartOfWord(mWText[pos]))
|
||||
{
|
||||
while ( (pos > 0) && isPartOfWord(mWText[pos - 1]) )
|
||||
{
|
||||
pos--;
|
||||
}
|
||||
*word_begin = pos;
|
||||
while ( (pos < getLength()) && isPartOfWord(mWText[pos]) )
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
*word_length = pos - *word_begin;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
S32 LLTextEditor::getLineStart( S32 line ) const
|
||||
{
|
||||
S32 num_lines = getLineCount();
|
||||
@@ -1268,11 +1372,91 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
|
||||
BOOL LLTextEditor::handleRightMouseDown( S32 x, S32 y, MASK mask )
|
||||
{
|
||||
setFocus(TRUE);
|
||||
llinfos << "Right mouse click - Opening menu." << llendl;
|
||||
|
||||
//setCursorAtLocalPos( x, y, TRUE );
|
||||
S32 wordStart = 0;
|
||||
S32 wordLen = 0;
|
||||
S32 pos = getCursorPosFromLocalCoord(x,y,TRUE);
|
||||
|
||||
LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
|
||||
if (menu)
|
||||
{
|
||||
for(int i = 0;i<(int)suggestionMenuItems.size();i++)
|
||||
{
|
||||
SpellMenuBind * tempBind = suggestionMenuItems[i];
|
||||
if(tempBind)
|
||||
{
|
||||
menu->remove(tempBind->menuItem);
|
||||
tempBind->menuItem->die();
|
||||
//delete tempBind->menuItem;
|
||||
//tempBind->menuItem = NULL;
|
||||
delete tempBind;
|
||||
}
|
||||
}
|
||||
suggestionMenuItems.clear();
|
||||
|
||||
// spell_check="true" in xui
|
||||
menu->setItemVisible("Spelsep", !mReadOnly && mSpellCheckable);
|
||||
if (!mReadOnly && mSpellCheckable)
|
||||
{
|
||||
bool is_word_part = getWordBoundriesAt(pos, &wordStart, &wordLen);
|
||||
if (is_word_part)
|
||||
{
|
||||
const LLWString &text = mWText;
|
||||
std::string selectedWord(std::string(text.begin(), text.end()).substr(wordStart,wordLen));
|
||||
|
||||
if (!glggHunSpell->isSpelledRight(selectedWord))
|
||||
{
|
||||
//misspelled word here, and you have just right clicked on it!
|
||||
std::vector<std::string> suggs = glggHunSpell->getSuggestionList(selectedWord);
|
||||
|
||||
for (int i = 0; i<(int)suggs.size(); i++)
|
||||
{
|
||||
SpellMenuBind * tempStruct = new SpellMenuBind;
|
||||
tempStruct->origin = this;
|
||||
tempStruct->word = suggs[i];
|
||||
tempStruct->wordPositionEnd = wordStart + wordLen;
|
||||
tempStruct->wordPositionStart=wordStart;
|
||||
tempStruct->wordY=y;
|
||||
LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL(
|
||||
tempStruct->word, spell_correct, NULL, tempStruct);
|
||||
tempStruct->menuItem = suggMenuItem;
|
||||
suggestionMenuItems.push_back(tempStruct);
|
||||
menu->append(suggMenuItem);
|
||||
}
|
||||
SpellMenuBind * tempStruct = new SpellMenuBind;
|
||||
tempStruct->origin = this;
|
||||
tempStruct->word = selectedWord;
|
||||
tempStruct->wordPositionEnd = wordStart + wordLen;
|
||||
tempStruct->wordPositionStart=wordStart;
|
||||
tempStruct->wordY=y;
|
||||
LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL(
|
||||
"Add Word", spell_add, NULL, tempStruct);
|
||||
tempStruct->menuItem = suggMenuItem;
|
||||
suggestionMenuItems.push_back(tempStruct);
|
||||
menu->append(suggMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
SpellMenuBind * tempStruct = new SpellMenuBind;
|
||||
tempStruct->origin = this;
|
||||
if (glggHunSpell->getSpellCheckHighlight())
|
||||
{
|
||||
tempStruct->word = "Hide Misspellings";
|
||||
}
|
||||
else
|
||||
{
|
||||
tempStruct->word = "Show Misspellings";
|
||||
}
|
||||
|
||||
LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL(
|
||||
tempStruct->word, spell_show, NULL, tempStruct);
|
||||
tempStruct->menuItem = suggMenuItem;
|
||||
suggestionMenuItems.push_back(tempStruct);
|
||||
menu->append(suggMenuItem);
|
||||
}
|
||||
mLastContextMenuX = x;
|
||||
mLastContextMenuY = y;
|
||||
menu->buildDrawLabels();
|
||||
menu->updateParent(LLMenuGL::sMenuContainer);
|
||||
LLMenuGL::showPopup(this, menu, x, y);
|
||||
@@ -1971,6 +2155,17 @@ BOOL LLTextEditor::canPaste() const
|
||||
}
|
||||
|
||||
|
||||
void LLTextEditor::spellReplace(SpellMenuBind* spellData)
|
||||
{
|
||||
remove( spellData->wordPositionStart,
|
||||
spellData->wordPositionEnd - spellData->wordPositionStart, TRUE );
|
||||
LLWString clean_string = utf8str_to_wstring(spellData->word);
|
||||
insert(spellData->wordPositionStart, clean_string, FALSE);
|
||||
mCursorPos+=clean_string.length() - (spellData->wordPositionEnd-spellData->wordPositionStart);
|
||||
needsReflow();
|
||||
}
|
||||
|
||||
|
||||
// paste from clipboard
|
||||
void LLTextEditor::paste()
|
||||
{
|
||||
@@ -2823,6 +3018,106 @@ void LLTextEditor::drawSelectionBackground()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLTextEditor::drawMisspelled()
|
||||
{
|
||||
if (!mReadOnly && mSpellCheckable)
|
||||
{
|
||||
if(
|
||||
( ((getLength()<400)||(false)) &&( (S32(mSpellTimer.getElapsedTimeF32() / 1) & 1) ))
|
||||
||
|
||||
(S32(mKeystrokeTimer.getElapsedTimeF32() / 1) & 1)
|
||||
)
|
||||
{
|
||||
S32 newSpellStart = getLineStart(mScrollbar->getDocPos());//start at the scroll start
|
||||
S32 newSpellEnd = getLineStart(mScrollbar->getDocPos() + 1 + mScrollbar->getDocSize()-mScrollbar->getDocPosMax());//end at the end o.o
|
||||
|
||||
if (mScrollbar->getDocPos() == mScrollbar->getDocPosMax())
|
||||
{
|
||||
newSpellEnd = (S32)mWText.length();
|
||||
}
|
||||
if (isSpellDirty() || (newSpellEnd!=spellEnd || newSpellStart!=spellStart))
|
||||
{
|
||||
spellEnd = newSpellEnd;
|
||||
spellStart = newSpellStart;
|
||||
misspellLocations = getMisspelledWordsPositions();
|
||||
}
|
||||
}
|
||||
//draw
|
||||
if (glggHunSpell->getSpellCheckHighlight())
|
||||
{
|
||||
for (int i = 0; i<(int)misspellLocations.size() ;i++)
|
||||
{
|
||||
S32 wstart = misspellLocations[i];
|
||||
S32 wend = misspellLocations[++i];
|
||||
//start curor code mod
|
||||
const LLWString &text = mWText;
|
||||
const S32 text_len = getLength();
|
||||
// Skip through the lines we aren't drawing.
|
||||
S32 search_pos = mScrollbar->getDocPos();
|
||||
S32 num_lines = getLineCount();
|
||||
if (search_pos >= num_lines)
|
||||
{
|
||||
return;
|
||||
}
|
||||
S32 line_start = getLineStart(search_pos);
|
||||
F32 line_height = mGLFont->getLineHeight();
|
||||
F32 text_y = (F32)(mTextRect.mTop) - line_height;
|
||||
|
||||
F32 word_left = 0.f;
|
||||
F32 word_right = 0.f;
|
||||
F32 word_bottom = 0.f;
|
||||
BOOL word_visible = FALSE;
|
||||
|
||||
S32 line_end = 0;
|
||||
// Determine if the cursor is visible and if so what its coordinates are.
|
||||
while( (mTextRect.mBottom <= llround(text_y)) && (search_pos < num_lines))
|
||||
{
|
||||
line_end = text_len + 1;
|
||||
S32 next_line = -1;
|
||||
|
||||
if ((search_pos + 1) < num_lines)
|
||||
{
|
||||
next_line = getLineStart(search_pos + 1);
|
||||
line_end = next_line - 1;
|
||||
}
|
||||
const llwchar* line = text.c_str() + line_start;
|
||||
// Find the cursor and selection bounds
|
||||
if( line_start <= wstart && wend <= line_end )
|
||||
{
|
||||
word_visible = TRUE;
|
||||
word_left = (F32)mTextRect.mLeft + mGLFont->getWidthF32(line, 0, wstart - line_start, mAllowEmbeddedItems )-1.f;
|
||||
word_right = (F32)mTextRect.mLeft + mGLFont->getWidthF32(line, 0, wend - line_start, mAllowEmbeddedItems )+1.f;
|
||||
word_bottom = text_y;
|
||||
break;
|
||||
}
|
||||
// move down one line
|
||||
text_y -= line_height;
|
||||
line_start = next_line;
|
||||
search_pos++;
|
||||
}
|
||||
if (mShowLineNumbers)
|
||||
{
|
||||
word_left += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
|
||||
word_right += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
|
||||
}
|
||||
// Draw the cursor
|
||||
if (word_visible)
|
||||
{
|
||||
//end cursor code mod
|
||||
gGL.color4ub(255,0,0,200);
|
||||
while (word_left<word_right)
|
||||
{
|
||||
gl_line_2d(word_left,word_bottom-2, word_left+3,word_bottom+1);
|
||||
gl_line_2d(word_left+3,word_bottom+1, word_left+6,word_bottom-2);
|
||||
word_left += 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLTextEditor::drawCursor()
|
||||
{
|
||||
if( gFocusMgr.getKeyboardFocus() == this
|
||||
@@ -3305,7 +3600,8 @@ void LLTextEditor::draw()
|
||||
drawPreeditMarker();
|
||||
drawText();
|
||||
drawCursor();
|
||||
|
||||
drawMisspelled();
|
||||
resetSpellDirty();
|
||||
unbindEmbeddedChars(mGLFont);
|
||||
|
||||
//RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret
|
||||
@@ -4474,6 +4770,8 @@ void LLTextEditor::setTextEditorParameters(LLXMLNodePtr node)
|
||||
|
||||
node->getAttributeBOOL("track_bottom", mTrackBottom);
|
||||
|
||||
node->getAttributeBOOL("spell_check", mSpellCheckable);
|
||||
|
||||
LLColor4 color;
|
||||
if (LLUICtrlFactory::getAttributeColor(node,"cursor_color", color))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user