Spell check added

This commit is contained in:
tmac@latestevidence.com
2011-04-23 18:08:59 -04:00
parent 0b9a44a842
commit af203533b3
73 changed files with 2442 additions and 200 deletions

View File

@@ -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))
{