aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui
diff options
context:
space:
mode:
authorPatrick Sapinski2010-08-24 03:04:20 -0400
committerMcCabe Maxsted2010-08-30 17:04:59 -0700
commitded1245db74ae4c97d174c5779f8572ee2f032fa (patch)
treef42c33f233ed68e715a0ac4c74ddc043f43a68da /linden/indra/llui
parentAdded debug setting UseLegacyChatLogsFolder for saving chat.txt and IM logs i... (diff)
downloadmeta-impy-ded1245db74ae4c97d174c5779f8572ee2f032fa.zip
meta-impy-ded1245db74ae4c97d174c5779f8572ee2f032fa.tar.gz
meta-impy-ded1245db74ae4c97d174c5779f8572ee2f032fa.tar.bz2
meta-impy-ded1245db74ae4c97d174c5779f8572ee2f032fa.tar.xz
added spellcheck + translation from Emerald Viewer. references to modularsystems.sl should be changed!
Diffstat (limited to 'linden/indra/llui')
-rw-r--r--linden/indra/llui/lllineeditor.cpp521
-rw-r--r--linden/indra/llui/lllineeditor.h47
-rw-r--r--linden/indra/llui/llmenugl.cpp25
-rw-r--r--linden/indra/llui/llmenugl.h3
-rw-r--r--linden/indra/llui/lltexteditor.cpp639
-rw-r--r--linden/indra/llui/lltexteditor.h74
6 files changed, 1193 insertions, 116 deletions
diff --git a/linden/indra/llui/lllineeditor.cpp b/linden/indra/llui/lllineeditor.cpp
index 21f0800..5441d0a 100644
--- a/linden/indra/llui/lllineeditor.cpp
+++ b/linden/indra/llui/lllineeditor.cpp
@@ -37,7 +37,6 @@
37#include "lllineeditor.h" 37#include "lllineeditor.h"
38 38
39#include "lltexteditor.h" 39#include "lltexteditor.h"
40#include "audioengine.h"
41#include "llmath.h" 40#include "llmath.h"
42#include "llfontgl.h" 41#include "llfontgl.h"
43#include "llgl.h" 42#include "llgl.h"
@@ -57,6 +56,11 @@
57#include "lluictrlfactory.h" 56#include "lluictrlfactory.h"
58#include "llclipboard.h" 57#include "llclipboard.h"
59 58
59#include "../newview/lgghunspell_wrapper.h"
60#include "../newview/lltranslate.h"
61#include "../newview/llviewercontrol.h"
62#include "../newview/lggautocorrect.h"
63
60// 64//
61// Imported globals 65// Imported globals
62// 66//
@@ -89,6 +93,34 @@ static LLRegisterWidget<LLLineEditor> r1("line_editor");
89// 93//
90// Member functions 94// Member functions
91// 95//
96class LineChatTranslationReceiver : public LLTranslate::TranslationReceiver
97{
98public :
99 LineChatTranslationReceiver(const std::string &toLang, LLLineEditor* line): LLTranslate::TranslationReceiver("", toLang),
100 m_line(line)
101 {
102 }
103
104 static boost::intrusive_ptr<LineChatTranslationReceiver> build(const std::string &toLang,LLLineEditor* line)
105 {
106 return boost::intrusive_ptr<LineChatTranslationReceiver>(new LineChatTranslationReceiver(toLang,line));
107 }
108
109protected:
110 void handleResponse(const std::string &translation, const std::string &detectedLanguage)
111 {
112 static BOOL* rep = rebind_llcontrol<BOOL>("EmeraldTranslateReplace", &gSavedSettings, true);
113 if(*rep)
114 m_line->deleteSelection();
115 m_line->insert(((*rep)?"":" (") + translation + ((*rep)?"":")"),m_line->getCursor());
116 }
117 void handleFailure()
118 {
119 LLTranslate::TranslationReceiver::handleFailure();
120 }
121private:
122 LLLineEditor* m_line;
123};
92 124
93LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect, 125LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect,
94 const std::string& default_text, const LLFontGL* font, 126 const std::string& default_text, const LLFontGL* font,
@@ -104,6 +136,7 @@ LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect,
104 : 136 :
105 LLUICtrl( name, rect, TRUE, commit_callback, userdata, FOLLOWS_TOP | FOLLOWS_LEFT ), 137 LLUICtrl( name, rect, TRUE, commit_callback, userdata, FOLLOWS_TOP | FOLLOWS_LEFT ),
106 mMaxLengthBytes(max_length_bytes), 138 mMaxLengthBytes(max_length_bytes),
139 mPopupMenuHandle(),
107 mCursorPos( 0 ), 140 mCursorPos( 0 ),
108 mScrollHPos( 0 ), 141 mScrollHPos( 0 ),
109 mTextPadLeft(0), 142 mTextPadLeft(0),
@@ -137,7 +170,8 @@ LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect,
137 mReadOnly(FALSE), 170 mReadOnly(FALSE),
138 mHaveHistory(FALSE), 171 mHaveHistory(FALSE),
139 mImage( sImage ), 172 mImage( sImage ),
140 mReplaceNewlinesWithSpaces( TRUE ) 173 mReplaceNewlinesWithSpaces( TRUE ),
174 mOverRideAndShowMisspellings( FALSE )
141{ 175{
142 llassert( max_length_bytes > 0 ); 176 llassert( max_length_bytes > 0 );
143 177
@@ -175,6 +209,59 @@ LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect,
175 sImage = LLUI::getUIImage("sm_rounded_corners_simple.tga"); 209 sImage = LLUI::getUIImage("sm_rounded_corners_simple.tga");
176 } 210 }
177 mImage = sImage; 211 mImage = sImage;
212 // make the popup menu available
213 //LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_texteditor.xml", parent_view);
214 LLMenuGL* menu = new LLMenuGL("wot");
215 /*if (!menu)
216 {
217 menu = new LLMenuGL(LLStringUtil::null);
218 }*/
219 menu->append(new LLMenuItemCallGL("Cut", context_cut, NULL, this));
220 menu->append(new LLMenuItemCallGL("Copy", context_copy, NULL, this));
221 menu->append(new LLMenuItemCallGL("Paste", context_paste, NULL, this));
222 menu->append(new LLMenuItemCallGL("Delete", context_delete, NULL, this));
223 menu->append(new LLMenuItemCallGL("Select All", context_selectall, NULL, this));
224 menu->appendSeparator("Transep");
225 LLMenuGL* translatemenu = new LLMenuGL("Translate To");
226 translatemenu->setCanTearOff(FALSE);
227 SpellMenuBind* t=new SpellMenuBind;t->origin=this;t->word="en";
228 translatemenu->append(new LLMenuItemCallGL("English",translateText, NULL, t));
229 t=new SpellMenuBind;t->origin=this;t->word="da";
230 translatemenu->append(new LLMenuItemCallGL("Danish",translateText, NULL, t));
231 t=new SpellMenuBind;t->origin=this;t->word="de";
232 translatemenu->append(new LLMenuItemCallGL("Deutsch(German)",translateText, NULL, t));
233 t=new SpellMenuBind;t->origin=this;t->word="es";
234 translatemenu->append(new LLMenuItemCallGL("Spanish",translateText, NULL, t));
235 t=new SpellMenuBind;t->origin=this;t->word="fr";
236 translatemenu->append(new LLMenuItemCallGL("French",translateText, NULL, t));
237 t=new SpellMenuBind;t->origin=this;t->word="it";
238 translatemenu->append(new LLMenuItemCallGL("Italian",translateText, NULL, t));
239 t=new SpellMenuBind;t->origin=this;t->word="hu";
240 translatemenu->append(new LLMenuItemCallGL("Hungarian",translateText, NULL, t));
241 t=new SpellMenuBind;t->origin=this;t->word="nl";
242 translatemenu->append(new LLMenuItemCallGL("Dutch",translateText, NULL, t));
243 t=new SpellMenuBind;t->origin=this;t->word="pl";
244 translatemenu->append(new LLMenuItemCallGL("Polish",translateText, NULL, t));
245 t=new SpellMenuBind;t->origin=this;t->word="pt";
246 translatemenu->append(new LLMenuItemCallGL("Portugese",translateText, NULL, t));
247 t=new SpellMenuBind;t->origin=this;t->word="ru";
248 translatemenu->append(new LLMenuItemCallGL("Russian",translateText, NULL, t));
249 t=new SpellMenuBind;t->origin=this;t->word="tr";
250 translatemenu->append(new LLMenuItemCallGL("Turkish",translateText, NULL, t));
251 t=new SpellMenuBind;t->origin=this;t->word="uk";
252 translatemenu->append(new LLMenuItemCallGL("Ukrainian",translateText, NULL, t));
253 t=new SpellMenuBind;t->origin=this;t->word="zh";
254 translatemenu->append(new LLMenuItemCallGL("Chinese",translateText, NULL, t));
255 t=new SpellMenuBind;t->origin=this;t->word="ja";
256 translatemenu->append(new LLMenuItemCallGL("Japanese",translateText, NULL, t));
257 t=new SpellMenuBind;t->origin=this;t->word="ko";
258 translatemenu->append(new LLMenuItemCallGL("Korean",translateText, NULL, t));
259 menu->appendMenu(translatemenu);
260 menu->appendSeparator("Spelsep");
261 //menu->setBackgroundColor(gColors.getColor("MenuPopupBgColor"));
262 menu->setCanTearOff(FALSE);
263 menu->setVisible(FALSE);
264 mPopupMenuHandle = menu->getHandle();
178} 265}
179 266
180 267
@@ -188,6 +275,7 @@ LLLineEditor::~LLLineEditor()
188 { 275 {
189 gEditMenuHandler = NULL; 276 gEditMenuHandler = NULL;
190 } 277 }
278 LLView::deleteViewByHandle(mPopupMenuHandle);
191} 279}
192 280
193 281
@@ -343,7 +431,7 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
343 431
344 432
345// Picks a new cursor position based on the actual screen size of text being drawn. 433// Picks a new cursor position based on the actual screen size of text being drawn.
346void LLLineEditor::setCursorAtLocalPos( S32 local_mouse_x ) 434S32 LLLineEditor::calculateCursorFromMouse( S32 local_mouse_x )
347{ 435{
348 const llwchar* wtext = mText.getWString().c_str(); 436 const llwchar* wtext = mText.getWString().c_str();
349 LLWString asterix_text; 437 LLWString asterix_text;
@@ -351,18 +439,22 @@ void LLLineEditor::setCursorAtLocalPos( S32 local_mouse_x )
351 { 439 {
352 for (S32 i = 0; i < mText.length(); i++) 440 for (S32 i = 0; i < mText.length(); i++)
353 { 441 {
354 asterix_text += (llwchar) 0x2022L; 442 asterix_text += '*';
355 } 443 }
356 wtext = asterix_text.c_str(); 444 wtext = asterix_text.c_str();
357 } 445 }
358 446
359 S32 cursor_pos = 447 return mScrollHPos +
360 mScrollHPos +
361 mGLFont->charFromPixelOffset( 448 mGLFont->charFromPixelOffset(
362 wtext, mScrollHPos, 449 wtext, mScrollHPos,
363 (F32)(local_mouse_x - mMinHPixels), 450 (F32)(local_mouse_x - mMinHPixels),
364 (F32)(mMaxHPixels - mMinHPixels + 1)); // min-max range is inclusive 451 (F32)(mMaxHPixels - mMinHPixels + 1)); // min-max range is inclusive
365 setCursor(cursor_pos); 452
453}
454// Picks a new cursor position based on the actual screen size of text being drawn.
455void LLLineEditor::setCursorAtLocalPos( S32 local_mouse_x )
456{
457 setCursor(calculateCursorFromMouse(local_mouse_x));
366} 458}
367 459
368void LLLineEditor::setCursor( S32 pos ) 460void LLLineEditor::setCursor( S32 pos )
@@ -418,6 +510,125 @@ void LLLineEditor::deselect()
418} 510}
419 511
420 512
513void LLLineEditor::context_cut(void* data)
514{
515 LLLineEditor* line = (LLLineEditor*)data;
516 if(line)line->cut();
517}
518void LLLineEditor::context_copy(void* data)
519{
520 LLLineEditor* line = (LLLineEditor*)data;
521 if(line)line->copy();
522}
523void LLLineEditor::spell_correct(void* data)
524{
525 SpellMenuBind* tempBind = (SpellMenuBind*)data;
526 LLLineEditor* line = tempBind->origin;
527 if(tempBind && line)
528 {
529 llinfos << ((LLMenuItemCallGL *)(tempBind->menuItem))->getName() << " : " << tempBind->origin->getName() << " : " << tempBind->word << llendl;
530 if(line)line->spellReplace(tempBind);
531
532 }
533}
534void LLLineEditor::translateText(void * data)
535{
536 SpellMenuBind* t = (SpellMenuBind*)data;
537 LLLineEditor* line = t->origin;
538 const std::string &toLang = t->word;//LLTranslate::getTranslateLanguage();
539 LLHTTPClient::ResponderPtr result = LineChatTranslationReceiver::build(toLang,line);
540 S32 left_pos = llmin( line->mSelectionStart, line->mSelectionEnd );
541 S32 length = abs( line->mSelectionStart - line->mSelectionEnd );
542 LLTranslate::translateMessage(result,"", toLang, line->mText.getString().substr(left_pos, length));
543}
544void LLLineEditor::spell_show(void * data)
545{
546 SpellMenuBind* tempBind = (SpellMenuBind*)data;
547 LLLineEditor* line = tempBind->origin;
548
549 if(tempBind && line)
550 {
551 if(tempBind->word=="Show Misspellings")
552 {
553 line->setOverRideAndShowMisspellings(TRUE);
554 }else
555 {
556 line->setOverRideAndShowMisspellings(FALSE);
557 }
558 }
559
560
561}
562std::vector<S32> LLLineEditor::getMisspelledWordsPositions()
563{
564 std::vector<S32> thePosesOfBadWords;
565 const LLWString& text = mText.getWString();
566
567 //llinfos << "end of box is at " << cursorloc << " and end of text is at " << text.length() << llendl;
568 S32 wordStart=0;
569 S32 wordEnd=mStartSpellHere;
570 while(wordEnd < mEndSpellHere)
571 {
572 //go through all the chars... XD
573 if( LLTextEditor::isPartOfWord( text[wordEnd] ) )
574
575 {
576 // Select word the cursor is over
577 while ((wordEnd > 0) && LLTextEditor::isPartOfWord(text[wordEnd-1]))
578 {
579 wordEnd--;
580 }
581 wordStart=wordEnd;
582 while ((wordEnd < (S32)text.length()) && LLTextEditor::isPartOfWord( text[wordEnd] ) )
583 {
584 wordEnd++;
585 }
586 //got a word :D
587 std::string selectedWord(std::string(text.begin(),
588 text.end()).substr(wordStart,wordEnd-wordStart));
589
590 if(!glggHunSpell->isSpelledRight(selectedWord))
591 {
592 //misspelled word here, and you have just right clicked on it!
593 //get the center of this word..
594 //S32 center = llround( (wordEnd-wordStart)/2 ) + wordStart;
595 //turn this cursor position into a pixel pos
596 //center = findPixelNearestPos(center-getCursor());
597
598 thePosesOfBadWords.push_back(
599 wordStart);
600 thePosesOfBadWords.push_back(wordEnd);
601 }
602 }
603 wordEnd++;
604 }
605 return thePosesOfBadWords;
606}
607void LLLineEditor::spell_add(void* data)
608{
609 SpellMenuBind* tempBind = (SpellMenuBind*)data;
610 if(tempBind)
611 {
612 glggHunSpell->addWordToCustomDictionary(tempBind->word);
613 tempBind->origin->mPrevSpelledText="";//make it update
614 }
615}
616void LLLineEditor::context_paste(void* data)
617{
618 LLLineEditor* line = (LLLineEditor*)data;
619 if(line)line->paste();
620}
621void LLLineEditor::context_delete(void* data)
622{
623 LLLineEditor* line = (LLLineEditor*)data;
624 if(line)line->doDelete();
625}
626void LLLineEditor::context_selectall(void* data)
627{
628 LLLineEditor* line = (LLLineEditor*)data;
629 if(line)line->selectAll();
630}
631
421void LLLineEditor::startSelection() 632void LLLineEditor::startSelection()
422{ 633{
423 mIsSelecting = TRUE; 634 mIsSelecting = TRUE;
@@ -508,6 +719,112 @@ BOOL LLLineEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
508 return TRUE; 719 return TRUE;
509} 720}
510 721
722
723BOOL LLLineEditor::handleRightMouseDown( S32 x, S32 y, MASK mask )
724{
725 setFocus(TRUE);
726
727 //setCursorAtLocalPos( x);
728 S32 wordStart = 0;
729 S32 wordEnd = calculateCursorFromMouse(x);
730
731
732 LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
733 if (menu)
734 {
735 if(menu->isOpen())
736 menu->setVisible(FALSE);
737 for(int i = 0;i<(int)suggestionMenuItems.size();i++)
738 {
739 SpellMenuBind * tempBind = suggestionMenuItems[i];
740 if(tempBind)
741 {
742 menu->remove((LLMenuItemCallGL *)tempBind->menuItem);
743 ((LLMenuItemCallGL *)tempBind->menuItem)->die();
744 //delete tempBind->menuItem;
745 //tempBind->menuItem = NULL;
746 delete tempBind;
747 }
748 }
749 suggestionMenuItems.clear();
750
751 menu->setItemVisible("Translate To",!mReadOnly);
752 menu->setItemVisible("Transep",!mReadOnly);
753
754 const LLWString& text = mText.getWString();
755 if(( LLTextEditor::isPartOfWord( text[wordEnd] ) )
756 &&(!mReadOnly))
757 {
758 // Select word the cursor is over
759 while ((wordEnd > 0) && LLTextEditor::isPartOfWord(text[wordEnd-1]))
760 {
761 wordEnd--;
762 }
763 wordStart=wordEnd;
764 //startSelection();
765
766 while ((wordEnd < (S32)text.length()) && LLTextEditor::isPartOfWord( text[wordEnd] ) )
767 {
768 wordEnd++;
769 }
770 std::string selectedWord(std::string(text.begin(),
771 text.end()).substr(wordStart,wordEnd-wordStart));
772 if(!glggHunSpell->isSpelledRight(selectedWord))
773 {
774 //misspelled word here, and you have just right clicked on it!
775 std::vector<std::string> suggs = glggHunSpell->getSuggestionList(selectedWord);
776 //menu->setItemVisible("Transep",(suggs.size()>0));
777
778 for(int i = 0;i<(int)suggs.size();i++)
779 {
780 SpellMenuBind * tempStruct = new SpellMenuBind;
781 tempStruct->origin = this;
782 tempStruct->word = suggs[i];
783 tempStruct->wordPositionEnd = wordEnd;
784 tempStruct->wordPositionStart=wordStart;
785 LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL(
786 tempStruct->word, spell_correct, NULL, tempStruct);
787 //new LLMenuItemCallGL("Select All", context_selectall, NULL, this));
788 tempStruct->menuItem = suggMenuItem;
789 suggestionMenuItems.push_back(tempStruct);
790 menu->append(suggMenuItem);
791 }
792 SpellMenuBind * tempStruct = new SpellMenuBind;
793 tempStruct->origin = this;
794 tempStruct->word = selectedWord;
795 tempStruct->wordPositionEnd = wordEnd;
796 tempStruct->wordPositionStart=wordStart;
797 LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL(
798 "Add Word", spell_add, NULL, tempStruct);
799 tempStruct->menuItem = suggMenuItem;
800 suggestionMenuItems.push_back(tempStruct);
801 menu->append(suggMenuItem);
802 }
803
804 }
805 if((!mReadOnly)&&((!glggHunSpell->highlightInRed)
806 ||(mOverRideAndShowMisspellings)))
807 {
808 SpellMenuBind * tempStruct = new SpellMenuBind;
809 tempStruct->origin = this;
810 if(mOverRideAndShowMisspellings)
811 tempStruct->word = "Hide Misspellings";
812 else
813 tempStruct->word = "Show Misspellings";
814 LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL(
815 tempStruct->word, spell_show, NULL, tempStruct);
816 tempStruct->menuItem = suggMenuItem;
817 suggestionMenuItems.push_back(tempStruct);
818 menu->append(suggMenuItem);
819 }
820
821 menu->buildDrawLabels();
822 menu->updateParent(LLMenuGL::sMenuContainer);
823 LLMenuGL::showPopup(this, menu, x, y);
824 }
825 return TRUE;
826}
827
511BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask) 828BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask)
512{ 829{
513 // Check first whether the "clear search" button wants to deal with this. 830 // Check first whether the "clear search" button wants to deal with this.
@@ -912,7 +1229,7 @@ void LLLineEditor::deleteSelection()
912 if( !mReadOnly && hasSelection() ) 1229 if( !mReadOnly && hasSelection() )
913 { 1230 {
914 S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); 1231 S32 left_pos = llmin( mSelectionStart, mSelectionEnd );
915 S32 selection_length = abs( mSelectionStart - mSelectionEnd ); 1232 S32 selection_length = llabs( mSelectionStart - mSelectionEnd );
916 1233
917 mText.erase(left_pos, selection_length); 1234 mText.erase(left_pos, selection_length);
918 deselect(); 1235 deselect();
@@ -935,7 +1252,7 @@ void LLLineEditor::cut()
935 1252
936 1253
937 S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); 1254 S32 left_pos = llmin( mSelectionStart, mSelectionEnd );
938 S32 length = abs( mSelectionStart - mSelectionEnd ); 1255 S32 length = llabs( mSelectionStart - mSelectionEnd );
939 gClipboard.copyFromSubstring( mText.getWString(), left_pos, length ); 1256 gClipboard.copyFromSubstring( mText.getWString(), left_pos, length );
940 deleteSelection(); 1257 deleteSelection();
941 1258
@@ -966,11 +1283,38 @@ void LLLineEditor::copy()
966 if( canCopy() ) 1283 if( canCopy() )
967 { 1284 {
968 S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); 1285 S32 left_pos = llmin( mSelectionStart, mSelectionEnd );
969 S32 length = abs( mSelectionStart - mSelectionEnd ); 1286 S32 length = llabs( mSelectionStart - mSelectionEnd );
970 gClipboard.copyFromSubstring( mText.getWString(), left_pos, length ); 1287 gClipboard.copyFromSubstring( mText.getWString(), left_pos, length );
971 } 1288 }
972} 1289}
973 1290
1291void LLLineEditor::spellReplace(SpellMenuBind* spellData)
1292{
1293 mText.erase(spellData->wordPositionStart,
1294 spellData->wordPositionEnd - spellData->wordPositionStart);
1295 insert(spellData->word,spellData->wordPositionStart);
1296 mCursorPos+=spellData->word.length() - (spellData->wordPositionEnd-spellData->wordPositionStart);
1297
1298
1299}
1300void LLLineEditor::insert(std::string what, S32 wher)
1301{
1302 LLLineEditorRollback rollback(this);
1303 LLWString clean_string(utf8str_to_wstring(what));
1304 LLWStringUtil::replaceTabsWithSpaces(clean_string, 4);
1305 mText.insert(wher, clean_string);
1306 //see if we should move over the cursor acordingly
1307 // Validate new string and rollback the if needed.
1308 BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) );
1309 if( need_to_rollback )
1310 {
1311 rollback.doRollback( this );
1312 reportBadKeystroke();
1313 }
1314 else if( mKeystrokeCallback )
1315 mKeystrokeCallback( this, mCallbackUserData );
1316}
1317
974BOOL LLLineEditor::canPaste() const 1318BOOL LLLineEditor::canPaste() const
975{ 1319{
976 return !mReadOnly && gClipboard.canPasteString(); 1320 return !mReadOnly && gClipboard.canPasteString();
@@ -993,17 +1337,25 @@ void LLLineEditor::pasteHelper(bool is_primary)
993{ 1337{
994 bool can_paste_it; 1338 bool can_paste_it;
995 if (is_primary) 1339 if (is_primary)
1340 {
996 can_paste_it = canPastePrimary(); 1341 can_paste_it = canPastePrimary();
1342 }
997 else 1343 else
1344 {
998 can_paste_it = canPaste(); 1345 can_paste_it = canPaste();
1346 }
999 1347
1000 if (can_paste_it) 1348 if (can_paste_it)
1001 { 1349 {
1002 LLWString paste; 1350 LLWString paste;
1003 if (is_primary) 1351 if (is_primary)
1352 {
1004 paste = gClipboard.getPastePrimaryWString(); 1353 paste = gClipboard.getPastePrimaryWString();
1354 }
1005 else 1355 else
1356 {
1006 paste = gClipboard.getPasteWString(); 1357 paste = gClipboard.getPasteWString();
1358 }
1007 1359
1008 if (!paste.empty()) 1360 if (!paste.empty())
1009 { 1361 {
@@ -1018,7 +1370,7 @@ void LLLineEditor::pasteHelper(bool is_primary)
1018 1370
1019 // Clean up string (replace tabs and returns and remove characters that our fonts don't support.) 1371 // Clean up string (replace tabs and returns and remove characters that our fonts don't support.)
1020 LLWString clean_string(paste); 1372 LLWString clean_string(paste);
1021 LLWStringUtil::replaceTabsWithSpaces(clean_string, 1); 1373 LLWStringUtil::replaceTabsWithSpaces(clean_string, 4);
1022 //clean_string = wstring_detabify(paste, 1); 1374 //clean_string = wstring_detabify(paste, 1);
1023 LLWStringUtil::replaceChar(clean_string, '\n', mReplaceNewlinesWithSpaces ? ' ' : 182); // 182 == paragraph character 1375 LLWStringUtil::replaceChar(clean_string, '\n', mReplaceNewlinesWithSpaces ? ' ' : 182); // 182 == paragraph character
1024 1376
@@ -1074,7 +1426,7 @@ void LLLineEditor::copyPrimary()
1074 if( canCopy() ) 1426 if( canCopy() )
1075 { 1427 {
1076 S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); 1428 S32 left_pos = llmin( mSelectionStart, mSelectionEnd );
1077 S32 length = abs( mSelectionStart - mSelectionEnd ); 1429 S32 length = llabs( mSelectionStart - mSelectionEnd );
1078 gClipboard.copyFromPrimarySubstring( mText.getWString(), left_pos, length ); 1430 gClipboard.copyFromPrimarySubstring( mText.getWString(), left_pos, length );
1079 } 1431 }
1080} 1432}
@@ -1322,6 +1674,14 @@ BOOL LLLineEditor::handleKeyHere(KEY key, MASK mask )
1322 BOOL handled = FALSE; 1674 BOOL handled = FALSE;
1323 BOOL selection_modified = FALSE; 1675 BOOL selection_modified = FALSE;
1324 1676
1677 // SL-51858: Key presses are not being passed to the Popup menu.
1678 // A proper fix is non-trivial so instead just close the menu.
1679 LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
1680 if (menu && menu->isOpen())
1681 {
1682 LLMenuGL::sMenuContainer->hideMenus();
1683 }
1684
1325 if ( gFocusMgr.getKeyboardFocus() == this ) 1685 if ( gFocusMgr.getKeyboardFocus() == this )
1326 { 1686 {
1327 LLLineEditorRollback rollback( this ); 1687 LLLineEditorRollback rollback( this );
@@ -1396,6 +1756,13 @@ BOOL LLLineEditor::handleUnicodeCharHere(llwchar uni_char)
1396 1756
1397 if ( (gFocusMgr.getKeyboardFocus() == this) && getVisible() && !mReadOnly) 1757 if ( (gFocusMgr.getKeyboardFocus() == this) && getVisible() && !mReadOnly)
1398 { 1758 {
1759 // SL-51858: Key presses are not being passed to the Popup menu.
1760 // A proper fix is non-trivial so instead just close the menu.
1761 LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
1762 if (menu && menu->isOpen())
1763 {
1764 LLMenuGL::sMenuContainer->hideMenus();
1765 }
1399 handled = TRUE; 1766 handled = TRUE;
1400 1767
1401 LLLineEditorRollback rollback( this ); 1768 LLLineEditorRollback rollback( this );
@@ -1471,10 +1838,97 @@ void LLLineEditor::doDelete()
1471 } 1838 }
1472 } 1839 }
1473} 1840}
1841void LLLineEditor::autoCorrectText()
1842{
1843 static BOOL *doAnything = rebind_llcontrol<BOOL>("EmeraldEnableAutoCorrect", &gSavedSettings, true);
1844 if( (!mReadOnly) && (*doAnything) && (isSpellDirty()))
1845 {
1846 S32 wordStart = 0;
1847 S32 wordEnd = mCursorPos-1;
1848 //llinfos <<"Checking Word, Cursor is at "<<mCursorPos<<" and text is "<<mText.getString().c_str()<<llendl;
1849 if(wordEnd<1)return;
1850 const LLWString& text = mText.getWString();
1851 if(text.size()<1)return;
1852 if( LLTextEditor::isPartOfWord( text[wordEnd] )) return;//we only check on word breaks
1853 wordEnd--;
1854 if( LLTextEditor::isPartOfWord( text[wordEnd] ) )
1855 {
1856 while ((wordEnd > 0) && (' '!=text[wordEnd-1]))
1857 {
1858 wordEnd--;
1859 }
1860 wordStart=wordEnd;
1861 while ((wordEnd < (S32)text.length()) && (' '!=text[wordEnd] ) )
1862 {
1863 wordEnd++;
1864 }
1865 std::string lastTypedWord(std::string(text.begin(),
1866 text.end()).substr(wordStart,wordEnd-wordStart));
1867 //llinfos << " The last typed word has been chosen, it is "<<lastTypedWord.c_str()<<llendl;
1868
1869 std::string correctedWord(LGGAutoCorrect::getInstance()->replaceWord(lastTypedWord));
1870 if(correctedWord!=lastTypedWord)
1871 {
1872 int dif = correctedWord.length()-lastTypedWord.length();
1873 std::string regText(mText);
1874 //int wordStart = regText.find(lastTypedWord);
1875 regText.replace(wordStart,lastTypedWord.length(),correctedWord);
1876 mText=regText;
1877 mCursorPos+=dif;
1878 }
1879 }
1880 }
1881}
1882void LLLineEditor::drawMisspelled(LLRect background)
1883{
1884 if((glggHunSpell->highlightInRed || mOverRideAndShowMisspellings)
1885 &&(!mReadOnly))
1886 {
1887 S32 newStartSpellHere =mScrollHPos;
1888 S32 cursorloc =calculateCursorFromMouse(mMaxHPixels);
1889 S32 newStopSpellHere = ( ((S32)mText.length())>cursorloc)?cursorloc:(S32)mText.length();
1890
1891 F32 elapsed = mSpellTimer.getElapsedTimeF32();
1892 if(S32(elapsed / 1) & 1)
1893 {
1894 if(isSpellDirty()||(newStartSpellHere!=mStartSpellHere)||(newStopSpellHere!=mEndSpellHere))
1895 {
1896 mStartSpellHere=newStartSpellHere;
1897 mEndSpellHere= newStopSpellHere;
1898 resetSpellDirty();
1899 misspellLocations=getMisspelledWordsPositions();
1900 }
1901 }
1902 for(int i =0;i<(int)misspellLocations.size();i++)
1903 {
1904 S32 wstart =findPixelNearestPos( misspellLocations[i]-getCursor());
1905 S32 wend = findPixelNearestPos(misspellLocations[++i]-getCursor());
1906 S32 maxw = getRect().getWidth();
1907
1908 if(wend > maxw)
1909 {
1910 wend=maxw;
1911 }
1912 if(wstart > maxw)
1913 {
1914 wstart=maxw;
1915 }
1916 gGL.color4ub(255,0,0,200);
1917 //3 line zig zags..
1918 while(wstart<wend)
1919 {
1920 gl_line_2d(wstart,background.mBottom-1,wstart+3,background.mBottom+2);
1921 gl_line_2d(wstart+3,background.mBottom+2,wstart+6,background.mBottom-1);
1922 wstart+=6;
1923 }
1474 1924
1925 }
1926 }
1475 1927
1928}
1476void LLLineEditor::draw() 1929void LLLineEditor::draw()
1477{ 1930{
1931 autoCorrectText();
1478 S32 text_len = mText.length(); 1932 S32 text_len = mText.length();
1479 1933
1480 std::string saved_text; 1934 std::string saved_text;
@@ -1484,7 +1938,7 @@ void LLLineEditor::draw()
1484 std::string text; 1938 std::string text;
1485 for (S32 i = 0; i < mText.length(); i++) 1939 for (S32 i = 0; i < mText.length(); i++)
1486 { 1940 {
1487 text += "\xe2\x80\xa2"; 1941 text += '*';
1488 } 1942 }
1489 mText = text; 1943 mText = text;
1490 } 1944 }
@@ -1661,6 +2115,9 @@ void LLLineEditor::draw()
1661 mBorder->setVisible(FALSE); // no more programmatic art. 2115 mBorder->setVisible(FALSE); // no more programmatic art.
1662#endif 2116#endif
1663 2117
2118 drawMisspelled(background);
2119 resetSpellDirty();
2120
1664 // If we're editing... 2121 // If we're editing...
1665 if( gFocusMgr.getKeyboardFocus() == this) 2122 if( gFocusMgr.getKeyboardFocus() == this)
1666 { 2123 {
@@ -2164,36 +2621,28 @@ BOOL LLLineEditor::prevalidateASCII(const LLWString &str)
2164 2621
2165BOOL LLLineEditor::evaluateFloat() 2622BOOL LLLineEditor::evaluateFloat()
2166{ 2623{
2167 bool success = false; 2624 bool success;
2625 F32 result = 0.f;
2168 std::string expr = getText(); 2626 std::string expr = getText();
2627 LLStringUtil::toUpper(expr);
2169 2628
2170 // user deleted the contents, nothing to evaluate -- MC 2629 success = LLCalc::getInstance()->evalString(expr, result);
2171 if (expr.empty()) 2630
2631 if (!success)
2172 { 2632 {
2173 return success; 2633 // Move the cursor to near the error on failure
2634 setCursor(LLCalc::getInstance()->getLastErrorPos());
2635 // *TODO: Translated error message indicating the type of error? Select error text?
2174 } 2636 }
2175 else 2637 else
2176 { 2638 {
2177 F32 result = 0.f; 2639 // Replace the expression with the result
2178 success = LLCalc::getInstance()->evalString(expr, result); 2640 std::string result_str = llformat("%f",result);
2179 2641 setText(result_str);
2180 if (!success) 2642 selectAll();
2181 {
2182 // Move the cursor to near the error on failure
2183 setCursor(LLCalc::getInstance()->getLastErrorPos());
2184 // *TODO: Translated error message indicating the type of error? Select error text?
2185 }
2186 else
2187 {
2188 // Replace the expression with the result
2189 std::ostringstream result_str;
2190 result_str << result;
2191 setText(result_str.str());
2192 selectAll();
2193 }
2194
2195 return success;
2196 } 2643 }
2644
2645 return success;
2197} 2646}
2198 2647
2199void LLLineEditor::onMouseCaptureLost() 2648void LLLineEditor::onMouseCaptureLost()
diff --git a/linden/indra/llui/lllineeditor.h b/linden/indra/llui/lllineeditor.h
index fc1b75f..6de57ec 100644
--- a/linden/indra/llui/lllineeditor.h
+++ b/linden/indra/llui/lllineeditor.h
@@ -78,6 +78,7 @@ public:
78 LLViewBorder::EStyle border_style = LLViewBorder::STYLE_LINE, 78 LLViewBorder::EStyle border_style = LLViewBorder::STYLE_LINE,
79 S32 border_thickness = 1); 79 S32 border_thickness = 1);
80 80
81
81 virtual ~LLLineEditor(); 82 virtual ~LLLineEditor();
82 83
83 virtual LLXMLNodePtr getXML(bool save_children = true) const; 84 virtual LLXMLNodePtr getXML(bool save_children = true) const;
@@ -91,15 +92,30 @@ public:
91 /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); 92 /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
92 /*virtual*/ BOOL handleDoubleClick(S32 x,S32 y,MASK mask); 93 /*virtual*/ BOOL handleDoubleClick(S32 x,S32 y,MASK mask);
93 /*virtual*/ BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); 94 /*virtual*/ BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask);
95 /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
94 /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask ); 96 /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask );
95 /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); 97 /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char);
96 /*virtual*/ void onMouseCaptureLost(); 98 /*virtual*/ void onMouseCaptureLost();
97 99
100 struct SpellMenuBind
101 {
102 LLLineEditor* origin;
103 void * menuItem;
104 std::string word;
105 S32 wordPositionStart;
106 S32 wordPositionEnd;
107 };
108
109 virtual void spellReplace(SpellMenuBind* spellData);
110 virtual void insert(std::string what,S32 wher);
111
98 // LLEditMenuHandler overrides 112 // LLEditMenuHandler overrides
99 virtual void cut(); 113 virtual void cut();
100 virtual BOOL canCut() const; 114 virtual BOOL canCut() const;
115
101 virtual void copy(); 116 virtual void copy();
102 virtual BOOL canCopy() const; 117 virtual BOOL canCopy() const;
118
103 virtual void paste(); 119 virtual void paste();
104 virtual BOOL canPaste() const; 120 virtual BOOL canPaste() const;
105 121
@@ -117,8 +133,20 @@ public:
117 virtual void deselect(); 133 virtual void deselect();
118 virtual BOOL canDeselect() const; 134 virtual BOOL canDeselect() const;
119 135
136 static void context_cut(void* data);
137 static void context_copy(void* data);
138 static void spell_correct(void* data);
139 static void spell_show(void* data);
140 static void translateText(void * data);
141 static void spell_add(void* data);
142 static void context_paste(void* data);
143 static void context_delete(void* data);
144 static void context_selectall(void* data);
145 std::vector<S32> getMisspelledWordsPositions();
120 // view overrides 146 // view overrides
121 virtual void draw(); 147 virtual void draw();
148 void autoCorrectText();
149 void drawMisspelled(LLRect background);
122 virtual void reshape(S32 width,S32 height,BOOL called_from_parent=TRUE); 150 virtual void reshape(S32 width,S32 height,BOOL called_from_parent=TRUE);
123 virtual void onFocusReceived(); 151 virtual void onFocusReceived();
124 virtual void onFocusLost(); 152 virtual void onFocusLost();
@@ -133,6 +161,8 @@ public:
133 virtual void onCommit(); 161 virtual void onCommit();
134 virtual BOOL isDirty() const { return mText.getString() != mPrevText; } // Returns TRUE if user changed value at all 162 virtual BOOL isDirty() const { return mText.getString() != mPrevText; } // Returns TRUE if user changed value at all
135 virtual void resetDirty() { mPrevText = mText.getString(); } // Clear dirty state 163 virtual void resetDirty() { mPrevText = mText.getString(); } // Clear dirty state
164 virtual BOOL isSpellDirty() const { return mText.getString() != mPrevSpelledText; } // Returns TRUE if user changed value at all
165 virtual void resetSpellDirty() { mPrevSpelledText = mText.getString(); } // Clear dirty state
136 166
137 // assumes UTF8 text 167 // assumes UTF8 text
138 virtual void setValue(const LLSD& value ) { setText(value.asString()); } 168 virtual void setValue(const LLSD& value ) { setText(value.asString()); }
@@ -168,6 +198,7 @@ public:
168 void setWriteableBgColor( const LLColor4& c ) { mWriteableBgColor = c; } 198 void setWriteableBgColor( const LLColor4& c ) { mWriteableBgColor = c; }
169 void setReadOnlyBgColor( const LLColor4& c ) { mReadOnlyBgColor = c; } 199 void setReadOnlyBgColor( const LLColor4& c ) { mReadOnlyBgColor = c; }
170 void setFocusBgColor(const LLColor4& c) { mFocusBgColor = c; } 200 void setFocusBgColor(const LLColor4& c) { mFocusBgColor = c; }
201 void setOverRideAndShowMisspellings(BOOL b) { mOverRideAndShowMisspellings =b;}
171 202
172 const LLColor4& getFgColor() const { return mFgColor; } 203 const LLColor4& getFgColor() const { return mFgColor; }
173 const LLColor4& getReadOnlyFgColor() const { return mReadOnlyFgColor; } 204 const LLColor4& getReadOnlyFgColor() const { return mReadOnlyFgColor; }
@@ -213,7 +244,7 @@ public:
213 static BOOL prevalidateASCII(const LLWString &str); 244 static BOOL prevalidateASCII(const LLWString &str);
214 245
215 static BOOL postvalidateFloat(const std::string &str); 246 static BOOL postvalidateFloat(const std::string &str);
216 247
217 BOOL evaluateFloat(); 248 BOOL evaluateFloat();
218 249
219 // line history support: 250 // line history support:
@@ -225,11 +256,12 @@ public:
225private: 256private:
226 // private helper methods 257 // private helper methods
227 258
228 void pasteHelper(bool is_primary); 259 void pasteHelper(bool is_primary);
229 260
230 void removeChar(); 261 void removeChar();
231 void addChar(const llwchar c); 262 void addChar(const llwchar c);
232 void setCursorAtLocalPos(S32 local_mouse_x); 263 void setCursorAtLocalPos(S32 local_mouse_x);
264 S32 calculateCursorFromMouse(S32 local_mouse_x);
233 S32 findPixelNearestPos(S32 cursor_offset = 0) const; 265 S32 findPixelNearestPos(S32 cursor_offset = 0) const;
234 void reportBadKeystroke(); 266 void reportBadKeystroke();
235 BOOL handleSpecialKey(KEY key, MASK mask); 267 BOOL handleSpecialKey(KEY key, MASK mask);
@@ -253,9 +285,18 @@ private:
253 virtual S32 getPreeditFontSize() const; 285 virtual S32 getPreeditFontSize() const;
254 286
255protected: 287protected:
288 LLHandle<LLView> mPopupMenuHandle;
256 LLUIString mText; // The string being edited. 289 LLUIString mText; // The string being edited.
257 std::string mPrevText; // Saved string for 'ESC' revert 290 std::string mPrevText; // Saved string for 'ESC' revert
258 LLUIString mLabel; // text label that is visible when no user text provided 291 LLUIString mLabel; // text label that is visible when no user text provided
292 std::string mPrevSpelledText; // saved string so we know whether to respell or not
293 std::vector<S32> misspellLocations; // where all the mispelled words are
294 S32 mStartSpellHere; // the position of the first char on the screen, stored so we know when to update
295 S32 mEndSpellHere; // the location of the last char on the screen
296 BOOL mOverRideAndShowMisspellings;
297 LLFrameTimer mSpellTimer;
298 //to keep track of what we have to remove before showing menu
299 std::vector<SpellMenuBind* > suggestionMenuItems;
259 300
260 // line history support: 301 // line history support:
261 BOOL mHaveHistory; // flag for enabled line history 302 BOOL mHaveHistory; // flag for enabled line history
@@ -364,6 +405,8 @@ private:
364 BOOL mIsSelecting; 405 BOOL mIsSelecting;
365 S32 mSelectionStart; 406 S32 mSelectionStart;
366 S32 mSelectionEnd; 407 S32 mSelectionEnd;
408
409
367 }; // end class LLLineEditorRollback 410 }; // end class LLLineEditorRollback
368 411
369}; // end class LLLineEditor 412}; // end class LLLineEditor
diff --git a/linden/indra/llui/llmenugl.cpp b/linden/indra/llui/llmenugl.cpp
index b70f98b..e00700a 100644
--- a/linden/indra/llui/llmenugl.cpp
+++ b/linden/indra/llui/llmenugl.cpp
@@ -2582,6 +2582,31 @@ BOOL LLMenuGL::appendMenu( LLMenuGL* menu )
2582 return success; 2582 return success;
2583} 2583}
2584 2584
2585// Remove a menu item from this menu.
2586BOOL LLMenuGL::remove( LLMenuItemGL* item )
2587{
2588 if (mSpilloverMenu)
2589 {
2590 cleanupSpilloverBranch();
2591 }
2592
2593 item_list_t::iterator found_iter = std::find(mItems.begin(), mItems.end(), item);
2594 if (found_iter != mItems.end())
2595 {
2596 mItems.erase(found_iter);
2597 }
2598
2599 removeChild( item );
2600
2601 // We keep it around in case someone is pointing at it.
2602 // The caller can delete it if it's safe.
2603 // Note that getMenu() will still not work since its parent isn't a menu.
2604 sMenuContainer->addChild( item );
2605
2606 arrange();
2607 return TRUE;
2608}
2609
2585void LLMenuGL::setEnabledSubMenus(BOOL enable) 2610void LLMenuGL::setEnabledSubMenus(BOOL enable)
2586{ 2611{
2587 setEnabled(enable); 2612 setEnabled(enable);
diff --git a/linden/indra/llui/llmenugl.h b/linden/indra/llui/llmenugl.h
index 26fc294..63f9d55 100644
--- a/linden/indra/llui/llmenugl.h
+++ b/linden/indra/llui/llmenugl.h
@@ -442,6 +442,9 @@ public:
442 // Add the menu item to this menu. 442 // Add the menu item to this menu.
443 virtual BOOL append( LLMenuItemGL* item ); 443 virtual BOOL append( LLMenuItemGL* item );
444 444
445 // Remove a menu item from this menu.
446 virtual BOOL remove( LLMenuItemGL* item );
447
445 // *NOTE:Mani - appendNoArrange() should be removed when merging to skinning/viewer2.0 448 // *NOTE:Mani - appendNoArrange() should be removed when merging to skinning/viewer2.0
446 // Its added as a fix to a viewer 1.23 bug that has already been address by skinning work. 449 // Its added as a fix to a viewer 1.23 bug that has already been address by skinning work.
447 virtual BOOL appendNoArrange( LLMenuItemGL* item ); 450 virtual BOOL appendNoArrange( LLMenuItemGL* item );
diff --git a/linden/indra/llui/lltexteditor.cpp b/linden/indra/llui/lltexteditor.cpp
index 2d46943..be6d3ef 100644
--- a/linden/indra/llui/lltexteditor.cpp
+++ b/linden/indra/llui/lltexteditor.cpp
@@ -36,7 +36,6 @@
36 36
37#include "lltexteditor.h" 37#include "lltexteditor.h"
38 38
39#include "llerror.h"
40#include "llfontgl.h" 39#include "llfontgl.h"
41#include "llrender.h" 40#include "llrender.h"
42#include "llui.h" 41#include "llui.h"
@@ -46,7 +45,6 @@
46#include "lltimer.h" 45#include "lltimer.h"
47#include "llmath.h" 46#include "llmath.h"
48 47
49#include "audioengine.h"
50#include "llclipboard.h" 48#include "llclipboard.h"
51#include "llscrollbar.h" 49#include "llscrollbar.h"
52#include "llstl.h" 50#include "llstl.h"
@@ -60,7 +58,13 @@
60#include "llwindow.h" 58#include "llwindow.h"
61#include "lltextparser.h" 59#include "lltextparser.h"
62#include <queue> 60#include <queue>
63#include <stdexcept> 61
62#include "llmenugl.h"
63#include <boost/regex.hpp>
64#include "../newview/lgghunspell_wrapper.h"
65#include "../newview/lltranslate.h"
66#include "../newview/llviewercontrol.h"
67#include "../newview/lggautocorrect.h"
64 68
65// 69//
66// Globals 70// Globals
@@ -96,7 +100,34 @@ LLColor4 LLTextEditor::mLinkColor = LLColor4::blue;
96void (* LLTextEditor::mURLcallback)(const std::string&) = NULL; 100void (* LLTextEditor::mURLcallback)(const std::string&) = NULL;
97bool (* LLTextEditor::mSecondlifeURLcallback)(const std::string&) = NULL; 101bool (* LLTextEditor::mSecondlifeURLcallback)(const std::string&) = NULL;
98bool (* LLTextEditor::mSecondlifeURLcallbackRightClick)(const std::string&) = NULL; 102bool (* LLTextEditor::mSecondlifeURLcallbackRightClick)(const std::string&) = NULL;
103///////////////////////////////////////////////////////////////////
104
105class TextChatTranslationReceiver : public LLTranslate::TranslationReceiver
106{
107public :
108 TextChatTranslationReceiver(const std::string &toLang, LLTextEditor* line): LLTranslate::TranslationReceiver("", toLang),
109 m_line(line)
110 {
111 }
112
113 static boost::intrusive_ptr<TextChatTranslationReceiver> build(const std::string &toLang,LLTextEditor* line)
114 {
115 return boost::intrusive_ptr<TextChatTranslationReceiver>(new TextChatTranslationReceiver(toLang,line));
116 }
99 117
118protected:
119 void handleResponse(const std::string &translation, const std::string &detectedLanguage)
120 {
121 BOOL rep = gSavedSettings.getBOOL("EmeraldTranslateReplace");
122 m_line->insertText((rep?"":" (") + translation +(rep?"":")"),rep);
123 }
124 void handleFailure()
125 {
126 LLTranslate::TranslationReceiver::handleFailure();
127 }
128private:
129 LLTextEditor* m_line;
130};
100 131
101/////////////////////////////////////////////////////////////////// 132///////////////////////////////////////////////////////////////////
102 133
@@ -257,6 +288,7 @@ LLTextEditor::LLTextEditor(
257 LLUICtrl( name, rect, TRUE, NULL, NULL, FOLLOWS_TOP | FOLLOWS_LEFT ), 288 LLUICtrl( name, rect, TRUE, NULL, NULL, FOLLOWS_TOP | FOLLOWS_LEFT ),
258 mTextIsUpToDate(TRUE), 289 mTextIsUpToDate(TRUE),
259 mMaxTextByteLength( max_length ), 290 mMaxTextByteLength( max_length ),
291 mPopupMenuHandle(),
260 mBaseDocIsPristine(TRUE), 292 mBaseDocIsPristine(TRUE),
261 mPristineCmd( NULL ), 293 mPristineCmd( NULL ),
262 mLastCmd( NULL ), 294 mLastCmd( NULL ),
@@ -290,7 +322,8 @@ LLTextEditor::LLTextEditor(
290 mLastSelectionX(-1), 322 mLastSelectionX(-1),
291 mLastSelectionY(-1), 323 mLastSelectionY(-1),
292 mReflowNeeded(FALSE), 324 mReflowNeeded(FALSE),
293 mScrollNeeded(FALSE) 325 mScrollNeeded(FALSE),
326 mOverRideAndShowMisspellings(FALSE)
294{ 327{
295 mSourceID.generate(); 328 mSourceID.generate();
296 329
@@ -342,6 +375,60 @@ LLTextEditor::LLTextEditor(
342 375
343 mParseHTML=FALSE; 376 mParseHTML=FALSE;
344 mHTML.clear(); 377 mHTML.clear();
378 // make the popup menu available
379 //LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_texteditor.xml", parent_view);
380 LLMenuGL* menu = new LLMenuGL("wot");
381 /*if (!menu)
382 {
383 menu = new LLMenuGL(LLStringUtil::null);
384 }*/
385 menu->append(new LLMenuItemCallGL("Cut", context_cut, NULL, this));
386 menu->append(new LLMenuItemCallGL("Copy", context_copy, NULL, this));
387 menu->append(new LLMenuItemCallGL("Paste", context_paste, NULL, this));
388 menu->append(new LLMenuItemCallGL("Delete", context_delete, NULL, this));
389 menu->append(new LLMenuItemCallGL("Select All", context_selectall, NULL, this));
390 menu->appendSeparator("transep");
391 LLMenuGL* translatemenu = new LLMenuGL("Translate To");
392 translatemenu->setCanTearOff(FALSE);
393 SpellMenuBind* t=new SpellMenuBind;t->origin=this;t->word="en";
394 translatemenu->append(new LLMenuItemCallGL("English",translateText, NULL, t));
395 t=new SpellMenuBind;t->origin=this;t->word="da";
396 translatemenu->append(new LLMenuItemCallGL("Danish",translateText, NULL, t));
397 t=new SpellMenuBind;t->origin=this;t->word="de";
398 translatemenu->append(new LLMenuItemCallGL("Deutsch(German)",translateText, NULL, t));
399 t=new SpellMenuBind;t->origin=this;t->word="es";
400 translatemenu->append(new LLMenuItemCallGL("Spanish",translateText, NULL, t));
401 t=new SpellMenuBind;t->origin=this;t->word="fr";
402 translatemenu->append(new LLMenuItemCallGL("French",translateText, NULL, t));
403 t=new SpellMenuBind;t->origin=this;t->word="it";
404 translatemenu->append(new LLMenuItemCallGL("Italian",translateText, NULL, t));
405 t=new SpellMenuBind;t->origin=this;t->word="hu";
406 translatemenu->append(new LLMenuItemCallGL("Hungarian",translateText, NULL, t));
407 t=new SpellMenuBind;t->origin=this;t->word="nl";
408 translatemenu->append(new LLMenuItemCallGL("Dutch",translateText, NULL, t));
409 t=new SpellMenuBind;t->origin=this;t->word="pl";
410 translatemenu->append(new LLMenuItemCallGL("Polish",translateText, NULL, t));
411 t=new SpellMenuBind;t->origin=this;t->word="pt";
412 translatemenu->append(new LLMenuItemCallGL("Portugese",translateText, NULL, t));
413 t=new SpellMenuBind;t->origin=this;t->word="ru";
414 translatemenu->append(new LLMenuItemCallGL("Russian",translateText, NULL, t));
415 t=new SpellMenuBind;t->origin=this;t->word="tr";
416 translatemenu->append(new LLMenuItemCallGL("Turkish",translateText, NULL, t));
417 t=new SpellMenuBind;t->origin=this;t->word="uk";
418 translatemenu->append(new LLMenuItemCallGL("Ukrainian",translateText, NULL, t));
419 t=new SpellMenuBind;t->origin=this;t->word="zh";
420 translatemenu->append(new LLMenuItemCallGL("Chinese",translateText, NULL, t));
421 t=new SpellMenuBind;t->origin=this;t->word="ja";
422 translatemenu->append(new LLMenuItemCallGL("Japanese",translateText, NULL, t));
423 t=new SpellMenuBind;t->origin=this;t->word="ko";
424 translatemenu->append(new LLMenuItemCallGL("Korean",translateText, NULL, t));
425
426 menu->appendMenu(translatemenu);
427 menu->appendSeparator("Spelsep");
428 //menu->setBackgroundColor(gColors.getColor("MenuPopupBgColor"));
429 menu->setCanTearOff(FALSE);
430 menu->setVisible(FALSE);
431 mPopupMenuHandle = menu->getHandle();
345} 432}
346 433
347 434
@@ -360,6 +447,119 @@ LLTextEditor::~LLTextEditor()
360 std::for_each(mSegments.begin(), mSegments.end(), DeletePointer()); 447 std::for_each(mSegments.begin(), mSegments.end(), DeletePointer());
361 448
362 std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer()); 449 std::for_each(mUndoStack.begin(), mUndoStack.end(), DeletePointer());
450 LLView::deleteViewByHandle(mPopupMenuHandle);
451}
452void LLTextEditor::context_cut(void* data)
453{
454 LLTextEditor* line = (LLTextEditor*)data;
455 if(line)line->cut();
456}
457void LLTextEditor::context_copy(void* data)
458{
459 LLTextEditor* line = (LLTextEditor*)data;
460 if(line)line->copy();
461}
462void LLTextEditor::translateText(void * data)
463{
464 SpellMenuBind* t = (SpellMenuBind*)data;
465 LLTextEditor* line = t->origin;
466 const std::string &toLang = t->word;//LLTranslate::getTranslateLanguage();
467 LLHTTPClient::ResponderPtr result = TextChatTranslationReceiver::build(toLang,line);
468
469 S32 left_pos = llmin( line->mSelectionStart, line->mSelectionEnd );
470 S32 length = abs( line->mSelectionStart - line->mSelectionEnd );
471 LLTranslate::translateMessage(result,"", toLang, line->getText().substr(left_pos, length));
472}
473void LLTextEditor::spell_correct(void* data)
474{
475 SpellMenuBind* tempBind = (SpellMenuBind*)data;
476 LLTextEditor* line = tempBind->origin;
477 if(tempBind && line)
478 {
479 llinfos << tempBind->menuItem->getName() << " : " << tempBind->origin->getName() << " : " << tempBind->word << llendl;
480 if(line)line->spellReplace(tempBind);
481
482 }
483}
484void LLTextEditor::spell_show(void * data)
485{
486 SpellMenuBind* tempBind = (SpellMenuBind*)data;
487 LLTextEditor* line = tempBind->origin;
488
489 if(tempBind && line)
490 {
491 if(tempBind->word=="Show Misspellings")
492 {
493 line->setOverRideAndShowMisspellings(TRUE);
494 }else
495 {
496 line->setOverRideAndShowMisspellings(FALSE);
497 }
498 }
499}
500
501std::vector<S32> LLTextEditor::getMisspelledWordsPositions()
502{
503 resetSpellDirty();
504 std::vector<S32> thePosesOfBadWords;
505 LLWString& text = mWText;
506 S32 wordStart=0;
507 S32 wordEnd=spellStart;//start at the scroll start
508 while(wordEnd < spellEnd)
509 {
510 //go through all the chars... XD
511 if( LLTextEditor::isPartOfWord( text[wordEnd] ) )
512 {
513 // Select word the cursor is over
514 while ((wordEnd > 0) && LLTextEditor::isPartOfWord(text[wordEnd-1]))
515 {
516 wordEnd--;
517 }
518 wordStart=wordEnd;
519 while ((wordEnd < (S32)text.length()) && LLTextEditor::isPartOfWord( text[wordEnd] ) )
520 {
521 wordEnd++;
522 }
523 //got a word :D
524
525 std::string regText(text.begin(),text.end());
526 std::string selectedWord(regText.substr(wordStart,wordEnd-wordStart));
527
528 if(!glggHunSpell->isSpelledRight(selectedWord))
529 {
530 //misspelled word here, and you have just right clicked on it
531
532 thePosesOfBadWords.push_back(wordStart);
533 thePosesOfBadWords.push_back(wordEnd);
534 }
535 }
536 wordEnd++;
537 }
538 return thePosesOfBadWords;
539}
540void LLTextEditor::spell_add(void* data)
541{
542 SpellMenuBind* tempBind = (SpellMenuBind*)data;
543 if(tempBind)
544 {
545 glggHunSpell->addWordToCustomDictionary(tempBind->word);
546 tempBind->origin->mPrevSpelledText.erase();//make it update
547 }
548}
549void LLTextEditor::context_paste(void* data)
550{
551 LLTextEditor* line = (LLTextEditor*)data;
552 if(line)line->paste();
553}
554void LLTextEditor::context_delete(void* data)
555{
556 LLTextEditor* line = (LLTextEditor*)data;
557 if(line)line->doDelete();
558}
559void LLTextEditor::context_selectall(void* data)
560{
561 LLTextEditor* line = (LLTextEditor*)data;
562 if(line)line->selectAll();
363} 563}
364 564
365void LLTextEditor::setTrackColor( const LLColor4& color ) 565void LLTextEditor::setTrackColor( const LLColor4& color )
@@ -751,14 +951,7 @@ S32 LLTextEditor::getLineStart( S32 line ) const
751 S32 segoffset = mLineStartList[line].mOffset; 951 S32 segoffset = mLineStartList[line].mOffset;
752 LLTextSegment* seg = mSegments[segidx]; 952 LLTextSegment* seg = mSegments[segidx];
753 S32 res = seg->getStart() + segoffset; 953 S32 res = seg->getStart() + segoffset;
754 if (res > seg->getEnd()) 954 if (res > seg->getEnd()) llerrs << "wtf" << llendl;
755 {
756 //llerrs << "wtf" << llendl;
757 // This happens when creating a new notecard using the AO on certain opensims.
758 // Play it safe instead of bringing down the viewer - MC
759 llwarns << "BAD JOOJOO! Text length (" << res << ") greater than text end (" << seg->getEnd() << "). Setting line start to " << seg->getEnd() << llendl;
760 res = seg->getEnd();
761 }
762 return res; 955 return res;
763} 956}
764 957
@@ -886,11 +1079,6 @@ S32 LLTextEditor::getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL rou
886 1079
887void LLTextEditor::setCursor(S32 row, S32 column) 1080void LLTextEditor::setCursor(S32 row, S32 column)
888{ 1081{
889 // Make sure we're not trying to set the cursor anywhere
890 // it can't go by always setting the min to 0 -- MC
891 row = (row < 0) ? 0 : row;
892 column = (column < 0) ? 0 : column;
893
894 const llwchar* doc = mWText.c_str(); 1082 const llwchar* doc = mWText.c_str();
895 const char CR = 10; 1083 const char CR = 10;
896 while(row--) 1084 while(row--)
@@ -1142,6 +1330,14 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
1142{ 1330{
1143 BOOL handled = FALSE; 1331 BOOL handled = FALSE;
1144 1332
1333 // SL-51858: Key presses are not being passed to the Popup menu.
1334 // A proper fix is non-trivial so instead just close the menu.
1335 LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
1336 if (menu && menu->isOpen())
1337 {
1338 LLMenuGL::sMenuContainer->hideMenus();
1339 }
1340
1145 // Let scrollbar have first dibs 1341 // Let scrollbar have first dibs
1146 handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL; 1342 handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
1147 1343
@@ -1216,6 +1412,107 @@ BOOL LLTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
1216 1412
1217 return handled; 1413 return handled;
1218} 1414}
1415BOOL LLTextEditor::handleRightMouseDown( S32 x, S32 y, MASK mask )
1416{
1417
1418 setFocus(TRUE);
1419
1420 //setCursorAtLocalPos( x, y, TRUE );
1421 S32 wordStart = 0;
1422 S32 wordEnd = getCursorPosFromLocalCoord(x,y,TRUE);
1423
1424 LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
1425 if (menu)
1426 {
1427 for(int i = 0;i<(int)suggestionMenuItems.size();i++)
1428 {
1429 SpellMenuBind * tempBind = suggestionMenuItems[i];
1430 if(tempBind)
1431 {
1432 menu->remove(tempBind->menuItem);
1433 tempBind->menuItem->die();
1434 //delete tempBind->menuItem;
1435 //tempBind->menuItem = NULL;
1436 delete tempBind;
1437 }
1438 }
1439 suggestionMenuItems.clear();
1440
1441 menu->setItemVisible("Translate To",!mReadOnly);
1442 menu->setItemVisible("Transep",!mReadOnly);
1443
1444 const LLWString &text = mWText;
1445
1446 if(( isPartOfWord( text[wordEnd] ) )&&(!mReadOnly))
1447 {
1448 // Select word the cursor is over
1449 while ((wordEnd > 0) && isPartOfWord(text[wordEnd-1]))
1450 {
1451 wordEnd--;
1452 }
1453 wordStart=wordEnd;
1454 //startSelection();
1455
1456 while ((wordEnd < (S32)text.length()) && isPartOfWord( text[wordEnd] ) )
1457 {
1458 wordEnd++;
1459 }
1460 std::string selectedWord(std::string(text.begin(), text.end()).substr(wordStart,wordEnd-wordStart));
1461 if(!glggHunSpell->isSpelledRight(selectedWord))
1462 {
1463 //misspelled word here, and you have just right clicked on it!
1464 std::vector<std::string> suggs = glggHunSpell->getSuggestionList(selectedWord);
1465
1466 //menu->setItemVisible("Transep",(suggs.size()>0));
1467 for(int i = 0;i<(int)suggs.size();i++)
1468 {
1469 SpellMenuBind * tempStruct = new SpellMenuBind;
1470 tempStruct->origin = this;
1471 tempStruct->word = suggs[i];
1472 tempStruct->wordPositionEnd = wordEnd;
1473 tempStruct->wordPositionStart=wordStart;
1474 tempStruct->wordY=y;
1475 LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL(
1476 tempStruct->word, spell_correct, NULL, tempStruct);
1477 tempStruct->menuItem = suggMenuItem;
1478 suggestionMenuItems.push_back(tempStruct);
1479 menu->append(suggMenuItem);
1480 }
1481 SpellMenuBind * tempStruct = new SpellMenuBind;
1482 tempStruct->origin = this;
1483 tempStruct->word = selectedWord;
1484 tempStruct->wordPositionEnd = wordEnd;
1485 tempStruct->wordPositionStart=wordStart;
1486 tempStruct->wordY=y;
1487 LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL(
1488 "Add Word", spell_add, NULL, tempStruct);
1489 tempStruct->menuItem = suggMenuItem;
1490 suggestionMenuItems.push_back(tempStruct);
1491 menu->append(suggMenuItem);
1492 }
1493
1494 }
1495 if((!mReadOnly)&&((!glggHunSpell->highlightInRed)
1496 ||(mOverRideAndShowMisspellings)||(mShowLineNumbers)))
1497 {
1498 SpellMenuBind * tempStruct = new SpellMenuBind;
1499 tempStruct->origin = this;
1500 if(mOverRideAndShowMisspellings)
1501 tempStruct->word = "Hide Misspellings";
1502 else
1503 tempStruct->word = "Show Misspellings";
1504 LLMenuItemCallGL * suggMenuItem = new LLMenuItemCallGL(
1505 tempStruct->word, spell_show, NULL, tempStruct);
1506 tempStruct->menuItem = suggMenuItem;
1507 suggestionMenuItems.push_back(tempStruct);
1508 menu->append(suggMenuItem);
1509 }
1510 menu->buildDrawLabels();
1511 menu->updateParent(LLMenuGL::sMenuContainer);
1512 LLMenuGL::showPopup(this, menu, x, y);
1513 }
1514 return TRUE;
1515}
1219 1516
1220 1517
1221BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) 1518BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask)
@@ -1350,11 +1647,6 @@ BOOL LLTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)
1350 1647
1351 setCursorAtLocalPos( x, y, TRUE ); 1648 setCursorAtLocalPos( x, y, TRUE );
1352 endSelection(); 1649 endSelection();
1353
1354 updateScrollFromCursor();
1355
1356 // take selection to primary clipboard
1357 updatePrimary();
1358 } 1650 }
1359 1651
1360 if( !hasSelection() ) 1652 if( !hasSelection() )
@@ -1432,7 +1724,6 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
1432 1724
1433 handled = TRUE; 1725 handled = TRUE;
1434 } 1726 }
1435
1436 return handled; 1727 return handled;
1437} 1728}
1438 1729
@@ -1913,6 +2204,16 @@ BOOL LLTextEditor::canPaste() const
1913 return !mReadOnly && gClipboard.canPasteString(); 2204 return !mReadOnly && gClipboard.canPasteString();
1914} 2205}
1915 2206
2207void LLTextEditor::spellReplace(SpellMenuBind* spellData)
2208{
2209 remove( spellData->wordPositionStart,
2210 spellData->wordPositionEnd - spellData->wordPositionStart, TRUE );
2211 LLWString clean_string = utf8str_to_wstring(spellData->word);
2212 insert(spellData->wordPositionStart, clean_string, FALSE);
2213 mCursorPos+=clean_string.length() - (spellData->wordPositionEnd-spellData->wordPositionStart);
2214 needsReflow();
2215}
2216
1916// paste from clipboard 2217// paste from clipboard
1917void LLTextEditor::paste() 2218void LLTextEditor::paste()
1918{ 2219{
@@ -1932,25 +2233,35 @@ void LLTextEditor::pasteHelper(bool is_primary)
1932{ 2233{
1933 bool can_paste_it; 2234 bool can_paste_it;
1934 if (is_primary) 2235 if (is_primary)
2236 {
1935 can_paste_it = canPastePrimary(); 2237 can_paste_it = canPastePrimary();
2238 }
1936 else 2239 else
2240 {
1937 can_paste_it = canPaste(); 2241 can_paste_it = canPaste();
2242 }
1938 2243
1939 if (!can_paste_it) 2244 if (!can_paste_it)
1940 { 2245 {
1941 return; 2246 return;
1942 } 2247 }
2248
1943 LLUUID source_id; 2249 LLUUID source_id;
1944 LLWString paste; 2250 LLWString paste;
1945 if (is_primary) 2251 if (is_primary)
2252 {
1946 paste = gClipboard.getPastePrimaryWString(&source_id); 2253 paste = gClipboard.getPastePrimaryWString(&source_id);
2254 }
1947 else 2255 else
2256 {
1948 paste = gClipboard.getPasteWString(&source_id); 2257 paste = gClipboard.getPasteWString(&source_id);
2258 }
1949 2259
1950 if (paste.empty()) 2260 if (paste.empty())
1951 { 2261 {
1952 return; 2262 return;
1953 } 2263 }
2264
1954 // Delete any selected characters (the paste replaces them) 2265 // Delete any selected characters (the paste replaces them)
1955 if( (!is_primary) && hasSelection() ) 2266 if( (!is_primary) && hasSelection() )
1956 { 2267 {
@@ -1995,7 +2306,7 @@ void LLTextEditor::copyPrimary()
1995 return; 2306 return;
1996 } 2307 }
1997 S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); 2308 S32 left_pos = llmin( mSelectionStart, mSelectionEnd );
1998 S32 length = abs( mSelectionStart - mSelectionEnd ); 2309 S32 length = llabs( mSelectionStart - mSelectionEnd );
1999 gClipboard.copyFromPrimarySubstring(mWText, left_pos, length, mSourceID); 2310 gClipboard.copyFromPrimarySubstring(mWText, left_pos, length, mSourceID);
2000} 2311}
2001 2312
@@ -2262,6 +2573,13 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )
2262 BOOL selection_modified = FALSE; 2573 BOOL selection_modified = FALSE;
2263 BOOL return_key_hit = FALSE; 2574 BOOL return_key_hit = FALSE;
2264 BOOL text_may_have_changed = TRUE; 2575 BOOL text_may_have_changed = TRUE;
2576 // SL-51858: Key presses are not being passed to the Popup menu.
2577 // A proper fix is non-trivial so instead just close the menu.
2578 LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
2579 if (menu && menu->isOpen())
2580 {
2581 LLMenuGL::sMenuContainer->hideMenus();
2582 }
2265 2583
2266 if ( gFocusMgr.getKeyboardFocus() == this ) 2584 if ( gFocusMgr.getKeyboardFocus() == this )
2267 { 2585 {
@@ -2306,6 +2624,14 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )
2306 } 2624 }
2307 } 2625 }
2308 2626
2627 // SL-51858: Key presses are not being passed to the Popup menu.
2628 // A proper fix is non-trivial so instead just close the menu.
2629 LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
2630 if (menu && menu->isOpen())
2631 {
2632 LLMenuGL::sMenuContainer->hideMenus();
2633 }
2634
2309 // Handle most keys only if the text editor is writeable. 2635 // Handle most keys only if the text editor is writeable.
2310 if( !mReadOnly ) 2636 if( !mReadOnly )
2311 { 2637 {
@@ -2739,6 +3065,140 @@ void LLTextEditor::drawSelectionBackground()
2739 } 3065 }
2740 } 3066 }
2741} 3067}
3068void LLTextEditor::autoCorrectText()
3069{
3070
3071 static BOOL *doAnything = rebind_llcontrol<BOOL>("EmeraldEnableAutoCorrect", &gSavedSettings, true);
3072 if( (!mReadOnly) && (*doAnything) && (isSpellDirty()) )
3073 {
3074 S32 wordStart = 0;
3075 S32 wordEnd = mCursorPos-1;
3076 if(wordEnd<1)return;
3077 LLWString& text = mWText;
3078 if(text.size()<1)return;
3079 if( LLTextEditor::isPartOfWord( text[wordEnd] )) return;//we only check on word breaks
3080 wordEnd--;
3081 if( LLTextEditor::isPartOfWord( text[wordEnd] ) )
3082 {
3083 while ((wordEnd > 0) && (text[wordEnd-1]!=' '))
3084 {
3085 wordEnd--;
3086 }
3087 wordStart=wordEnd;
3088 while ((wordEnd < (S32)text.length()) && (' '!= text[wordEnd] ) )
3089 {
3090 wordEnd++;
3091 }
3092 std::string lastTypedWord(std::string(text.begin(),
3093 text.end()).substr(wordStart,wordEnd-wordStart));
3094
3095 std::string regText(text.begin(),text.end());
3096
3097 std::string correctedWord(LGGAutoCorrect::getInstance()->replaceWord(lastTypedWord));
3098 if(correctedWord!=lastTypedWord)
3099 {
3100 int dif = correctedWord.length()-lastTypedWord.length();
3101 regText.replace(wordStart,lastTypedWord.length(),correctedWord);
3102 mWText=utf8str_to_wstring(regText);
3103 mCursorPos+=dif;
3104 needsReflow();
3105 }
3106 }
3107 }
3108}
3109void LLTextEditor::drawMisspelled()
3110{
3111 if(mReadOnly)return;
3112 if(glggHunSpell->highlightInRed || mOverRideAndShowMisspellings)
3113 {
3114 if(
3115 ( ((getLength()<400)||(false)) &&( (S32(mSpellTimer.getElapsedTimeF32() / 1) & 1) ))
3116 ||
3117 (S32(mKeystrokeTimer.getElapsedTimeF32() / 1) & 1)
3118 )
3119 {
3120 S32 newSpellStart = getLineStart(mScrollbar->getDocPos());//start at the scroll start
3121 S32 newSpellEnd = getLineStart(mScrollbar->getDocPos() + 1 + mScrollbar->getDocSize()-mScrollbar->getDocPosMax());//end at the end o.o
3122
3123 if(mScrollbar->getDocPos() == mScrollbar->getDocPosMax())
3124 {
3125 newSpellEnd=(S32)mWText.length();
3126 }
3127 if((isSpellDirty())||(newSpellEnd!=spellEnd || newSpellStart!=spellStart))
3128 {
3129 spellEnd = newSpellEnd;
3130 spellStart = newSpellStart;
3131 misspellLocations=getMisspelledWordsPositions();
3132 }
3133 }
3134 //draw
3135 for(int i =0;i<(int)misspellLocations.size();i++)
3136 {
3137 S32 wstart = misspellLocations[i];
3138 S32 wend = misspellLocations[++i];
3139 //start curor code mod
3140 const LLWString &text = mWText;
3141 const S32 text_len = getLength();
3142 // Skip through the lines we aren't drawing.
3143 S32 search_pos = mScrollbar->getDocPos();
3144 S32 num_lines = getLineCount();
3145 if (search_pos >= num_lines)return;
3146 S32 line_start = getLineStart(search_pos);
3147 F32 line_height = mGLFont->getLineHeight();
3148 F32 text_y = (F32)(mTextRect.mTop) - line_height;
3149
3150 F32 word_left = 0.f;
3151 F32 word_right = 0.f;
3152 F32 word_bottom = 0.f;
3153 BOOL word_visible = FALSE;
3154
3155 S32 line_end = 0;
3156 // Determine if the cursor is visible and if so what its coordinates are.
3157 while( (mTextRect.mBottom <= llround(text_y)) && (search_pos < num_lines))
3158 {
3159 line_end = text_len + 1;
3160 S32 next_line = -1;
3161
3162 if ((search_pos + 1) < num_lines)
3163 {
3164 next_line = getLineStart(search_pos + 1);
3165 line_end = next_line - 1;
3166 }
3167 const llwchar* line = text.c_str() + line_start;
3168 // Find the cursor and selection bounds
3169 if( line_start <= wstart && wend <= line_end )
3170 {
3171 word_visible = TRUE;
3172 word_left = (F32)mTextRect.mLeft + mGLFont->getWidthF32(line, 0, wstart - line_start, mAllowEmbeddedItems )-1.f;
3173 word_right = (F32)mTextRect.mLeft + mGLFont->getWidthF32(line, 0, wend - line_start, mAllowEmbeddedItems )+1.f;
3174 word_bottom = text_y;
3175 break;
3176 }
3177 // move down one line
3178 text_y -= line_height;
3179 line_start = next_line;
3180 search_pos++;
3181 }
3182 if(mShowLineNumbers)
3183 {
3184 word_left += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
3185 word_right += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
3186 }
3187 // Draw the cursor
3188 if( word_visible )
3189 {
3190 //end cursos code mod
3191 gGL.color4ub(255,0,0,200);
3192 while(word_left<word_right)
3193 {
3194 gl_line_2d(word_left,word_bottom-2,word_left+3,word_bottom+1);
3195 gl_line_2d(word_left+3,word_bottom+1,word_left+6,word_bottom-2);
3196 word_left+=6;
3197 }
3198 }
3199 }
3200 }
3201}
2742 3202
2743void LLTextEditor::drawCursor() 3203void LLTextEditor::drawCursor()
2744{ 3204{
@@ -3205,6 +3665,8 @@ void LLTextEditor::draw()
3205 mReflowNeeded = FALSE; 3665 mReflowNeeded = FALSE;
3206 } 3666 }
3207 3667
3668 autoCorrectText();
3669
3208 // then update scroll position, as cursor may have moved 3670 // then update scroll position, as cursor may have moved
3209 if (mScrollNeeded) 3671 if (mScrollNeeded)
3210 { 3672 {
@@ -3222,7 +3684,11 @@ void LLTextEditor::draw()
3222 drawPreeditMarker(); 3684 drawPreeditMarker();
3223 drawText(); 3685 drawText();
3224 drawCursor(); 3686 drawCursor();
3225 3687 if(!mShowLineNumbers || mOverRideAndShowMisspellings)
3688 {
3689 drawMisspelled();
3690 }
3691 resetSpellDirty();
3226 unbindEmbeddedChars(mGLFont); 3692 unbindEmbeddedChars(mGLFont);
3227 3693
3228 //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret 3694 //RN: the decision was made to always show the orange border for keyboard focus but do not put an insertion caret
@@ -3250,6 +3716,8 @@ void LLTextEditor::onTabInto()
3250void LLTextEditor::clear() 3716void LLTextEditor::clear()
3251{ 3717{
3252 setText(LLStringUtil::null); 3718 setText(LLStringUtil::null);
3719 std::for_each(mSegments.begin(), mSegments.end(), DeletePointer());
3720 mSegments.clear();
3253} 3721}
3254 3722
3255// Start or stop the editor from accepting text-editing keystrokes 3723// Start or stop the editor from accepting text-editing keystrokes
@@ -3598,13 +4066,13 @@ void LLTextEditor::autoIndent()
3598} 4066}
3599 4067
3600// Inserts new text at the cursor position 4068// Inserts new text at the cursor position
3601void LLTextEditor::insertText(const std::string &new_text) 4069void LLTextEditor::insertText(const std::string &new_text,BOOL deleteCurrentSelection)
3602{ 4070{
3603 BOOL enabled = getEnabled(); 4071 BOOL enabled = getEnabled();
3604 setEnabled( TRUE ); 4072 setEnabled( TRUE );
3605 4073
3606 // Delete any selected characters (the insertion replaces them) 4074 // Delete any selected characters (the insertion replaces them)
3607 if( hasSelection() ) 4075 if( hasSelection() && (deleteCurrentSelection))
3608 { 4076 {
3609 deleteSelection(TRUE); 4077 deleteSelection(TRUE);
3610 } 4078 }
@@ -3638,9 +4106,9 @@ void LLTextEditor::appendColoredText(const std::string &new_text,
3638} 4106}
3639 4107
3640void LLTextEditor::appendStyledText(const std::string &new_text, 4108void LLTextEditor::appendStyledText(const std::string &new_text,
3641 bool allow_undo, 4109 bool allow_undo,
3642 bool prepend_newline, 4110 bool prepend_newline,
3643 const LLStyleSP stylep) 4111 LLStyleSP stylep)
3644{ 4112{
3645 S32 part = (S32)LLTextParser::WHOLE; 4113 S32 part = (S32)LLTextParser::WHOLE;
3646 if(mParseHTML) 4114 if(mParseHTML)
@@ -3648,9 +4116,9 @@ void LLTextEditor::appendStyledText(const std::string &new_text,
3648 4116
3649 S32 start=0,end=0; 4117 S32 start=0,end=0;
3650 std::string text = new_text; 4118 std::string text = new_text;
3651 while ( findHTML(text, &start, &end) ) 4119 std::string url;
4120 while ( findHTML(text, &start, &end, url) )
3652 { 4121 {
3653
3654 LLStyleSP html(new LLStyle); 4122 LLStyleSP html(new LLStyle);
3655 html->setVisible(true); 4123 html->setVisible(true);
3656 html->setColor(mLinkColor); 4124 html->setColor(mLinkColor);
@@ -3675,9 +4143,9 @@ void LLTextEditor::appendStyledText(const std::string &new_text,
3675 appendHighlightedText(subtext,allow_undo, prepend_newline, part, stylep); 4143 appendHighlightedText(subtext,allow_undo, prepend_newline, part, stylep);
3676 } 4144 }
3677 4145
3678 html->setLinkHREF(text.substr(start,end-start)); 4146 html->setLinkHREF(url);
3679 appendText(text.substr(start, end-start),allow_undo, prepend_newline, html); 4147 appendText(text.substr(start, end-start),allow_undo, prepend_newline, html);
3680 if (end < (S32)text.length()) 4148 if (end < (S32)text.length())
3681 { 4149 {
3682 text = text.substr(end,text.length() - end); 4150 text = text.substr(end,text.length() - end);
3683 end=0; 4151 end=0;
@@ -3688,6 +4156,7 @@ void LLTextEditor::appendStyledText(const std::string &new_text,
3688 break; 4156 break;
3689 } 4157 }
3690 } 4158 }
4159
3691 if (part != (S32)LLTextParser::WHOLE) part=(S32)LLTextParser::END; 4160 if (part != (S32)LLTextParser::WHOLE) part=(S32)LLTextParser::END;
3692 if (end < (S32)text.length()) appendHighlightedText(text,allow_undo, prepend_newline, part, stylep); 4161 if (end < (S32)text.length()) appendHighlightedText(text,allow_undo, prepend_newline, part, stylep);
3693 } 4162 }
@@ -3784,6 +4253,10 @@ void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool
3784 { 4253 {
3785 mSelectionStart = selection_start; 4254 mSelectionStart = selection_start;
3786 mSelectionEnd = selection_end; 4255 mSelectionEnd = selection_end;
4256
4257
4258
4259
3787 mIsSelecting = was_selecting; 4260 mIsSelecting = was_selecting;
3788 setCursorPos(cursor_pos); 4261 setCursorPos(cursor_pos);
3789 } 4262 }
@@ -3952,6 +4425,15 @@ void LLTextEditor::loadKeywords(const std::string& filename,
3952 } 4425 }
3953} 4426}
3954 4427
4428void LLTextEditor::addToken(LLKeywordToken::TOKEN_TYPE type,
4429 const std::string& key,
4430 const LLColor3& color,
4431 const std::string& tool_tip,
4432 const std::string& delimiter)
4433{
4434 mKeywords.addToken(type,key,color,tool_tip);
4435}
4436
3955void LLTextEditor::updateSegments() 4437void LLTextEditor::updateSegments()
3956{ 4438{
3957 if (mKeywords.isLoaded()) 4439 if (mKeywords.isLoaded())
@@ -4417,11 +4899,9 @@ S32 LLTextEditor::findHTMLToken(const std::string &line, S32 pos, BOOL reverse)
4417 std::string openers=" \t\n('\"[{<>"; 4899 std::string openers=" \t\n('\"[{<>";
4418 std::string closers=" \t\n)'\"]}><;"; 4900 std::string closers=" \t\n)'\"]}><;";
4419 4901
4420 S32 index = 0;
4421
4422 if (reverse) 4902 if (reverse)
4423 { 4903 {
4424 for (index=pos; index >= 0; index--) 4904 for (int index=pos; index >= 0; index--)
4425 { 4905 {
4426 char c = line[index]; 4906 char c = line[index];
4427 S32 m2 = openers.find(c); 4907 S32 m2 = openers.find(c);
@@ -4430,13 +4910,13 @@ S32 LLTextEditor::findHTMLToken(const std::string &line, S32 pos, BOOL reverse)
4430 return index+1; 4910 return index+1;
4431 } 4911 }
4432 } 4912 }
4433 index = 0; // Can't be before first charater 4913 return 0; // index is -1, don't want to return that.
4434 } 4914 }
4435 else 4915 else
4436 { 4916 {
4437 // adjust the search slightly, to allow matching parenthesis inside the URL 4917 // adjust the search slightly, to allow matching parenthesis inside the URL
4438 S32 paren_count = 0; 4918 S32 paren_count = 0;
4439 for (index=pos; index<(S32)line.length(); index++) 4919 for (int index=pos; index<(S32)line.length(); index++)
4440 { 4920 {
4441 char c = line[index]; 4921 char c = line[index];
4442 4922
@@ -4464,12 +4944,11 @@ S32 LLTextEditor::findHTMLToken(const std::string &line, S32 pos, BOOL reverse)
4464 } 4944 }
4465 } 4945 }
4466 } 4946 }
4947 return line.length();
4467 } 4948 }
4468
4469 return index;
4470} 4949}
4471 4950
4472BOOL LLTextEditor::findHTML(const std::string &line, S32 *begin, S32 *end) const 4951BOOL LLTextEditor::findHTML(const std::string &line, S32 *begin, S32 *end, std::string& url) const
4473{ 4952{
4474 4953
4475 S32 m1,m2,m3; 4954 S32 m1,m2,m3;
@@ -4481,34 +4960,21 @@ BOOL LLTextEditor::findHTML(const std::string &line, S32 *begin, S32 *end) const
4481 { 4960 {
4482 *begin = findHTMLToken(line, m1, TRUE); 4961 *begin = findHTMLToken(line, m1, TRUE);
4483 *end = findHTMLToken(line, m1, FALSE); 4962 *end = findHTMLToken(line, m1, FALSE);
4484
4485 // Can't start before the first char
4486 if(*begin < 0)
4487 {
4488 //*begin = 0;
4489 }
4490 4963
4491 //Load_url only handles http and https so don't hilite ftp, smb, etc. 4964 //Load_url only handles http and https so don't hilite ftp, smb, etc.
4492 try 4965 m2 = line.substr(*begin,(m1 - *begin)).find("http");
4966 m3 = line.substr(*begin,(m1 - *begin)).find("secondlife");
4967
4968 std::string badneighbors=".,<>?';\"][}{=-+_)(*&^%$#@!~`\t\r\n\\";
4969
4970 if (m2 >= 0 || m3>=0)
4493 { 4971 {
4494 m2 = line.substr(*begin,(m1 - *begin)).find("http"); 4972 S32 bn = badneighbors.find(line.substr(m1+3,1));
4495 m3 = line.substr(*begin,(m1 - *begin)).find("secondlife"); 4973
4496 4974 if (bn < 0)
4497 std::string badneighbors=".,<>?';\"][}{=-+_)(*&^%$#@!~`\t\r\n\\"; 4975 {
4498 4976 matched = TRUE;
4499 if (m2 >= 0 || m3>=0)
4500 {
4501 S32 bn = badneighbors.find(line.substr(m1+3,1));
4502
4503 if (bn < 0)
4504 {
4505 matched = TRUE;
4506 }
4507 } 4977 }
4508 }
4509 catch ( std::out_of_range outOfRange )
4510 {
4511 LL_WARNS("TextEditor") << "got std::out_of_range exception \"" << line << "\"" << LL_ENDL;
4512 } 4978 }
4513 } 4979 }
4514/* matches things like secondlife.com (no http://) needs a whitelist to really be effective. 4980/* matches things like secondlife.com (no http://) needs a whitelist to really be effective.
@@ -4541,11 +5007,46 @@ BOOL LLTextEditor::findHTML(const std::string &line, S32 *begin, S32 *end) const
4541 { 5007 {
4542 S32 strpos, strpos2; 5008 S32 strpos, strpos2;
4543 5009
4544 try 5010 url = line.substr(*begin,*end - *begin);
5011 std::string slurlID = "slurl.com/secondlife/";
5012 strpos = url.find(slurlID);
5013
5014 if (strpos < 0)
4545 { 5015 {
4546 std::string url = line.substr(*begin,*end - *begin); 5016 slurlID="maps.secondlife.com/secondlife/";
4547 std::string slurlID = "slurl.com/secondlife/"; 5017 strpos = url.find(slurlID);
4548 strpos = url.find(slurlID); 5018 }
5019
5020 if (strpos < 0)
5021 {
5022 slurlID="secondlife://";
5023 strpos = url.find(slurlID);
5024 }
5025
5026 if (strpos < 0)
5027 {
5028 slurlID="sl://";
5029 strpos = url.find(slurlID);
5030 }
5031
5032 if (strpos >= 0)
5033 {
5034 strpos+=slurlID.length();
5035
5036 while ( ( strpos2=url.find("/",strpos) ) == -1 )
5037 {
5038 if ((*end+2) >= (S32)line.length() || line.substr(*end,1) != " " )
5039 {
5040 matched=FALSE;
5041 break;
5042 }
5043
5044 strpos = (*end + 1) - *begin;
5045
5046 *end = findHTMLToken(line,(*begin + strpos),FALSE);
5047 url = line.substr(*begin,*end - *begin);
5048 }
5049 }
4549 5050
4550 if (strpos < 0) 5051 if (strpos < 0)
4551 { 5052 {
diff --git a/linden/indra/llui/lltexteditor.h b/linden/indra/llui/lltexteditor.h
index f26bf3b..6b372d7 100644
--- a/linden/indra/llui/lltexteditor.h
+++ b/linden/indra/llui/lltexteditor.h
@@ -45,6 +45,7 @@
45#include "lldarray.h" 45#include "lldarray.h"
46 46
47#include "llpreeditor.h" 47#include "llpreeditor.h"
48#include "llmenugl.h"
48 49
49class LLFontGL; 50class LLFontGL;
50class LLScrollbar; 51class LLScrollbar;
@@ -84,6 +85,7 @@ public:
84 virtual BOOL handleHover(S32 x, S32 y, MASK mask); 85 virtual BOOL handleHover(S32 x, S32 y, MASK mask);
85 virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); 86 virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
86 virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask ); 87 virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask );
88 virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask );
87 virtual BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask); 89 virtual BOOL handleMiddleMouseDown(S32 x,S32 y,MASK mask);
88 90
89 virtual BOOL handleKeyHere(KEY key, MASK mask ); 91 virtual BOOL handleKeyHere(KEY key, MASK mask );
@@ -108,29 +110,55 @@ public:
108 virtual void setFocus( BOOL b ); 110 virtual void setFocus( BOOL b );
109 virtual BOOL acceptsTextInput() const; 111 virtual BOOL acceptsTextInput() const;
110 virtual BOOL isDirty() const { return( mLastCmd != NULL || (mPristineCmd && (mPristineCmd != mLastCmd)) ); } 112 virtual BOOL isDirty() const { return( mLastCmd != NULL || (mPristineCmd && (mPristineCmd != mLastCmd)) ); }
113 BOOL isSpellDirty() const { return mWText != mPrevSpelledText; } // Returns TRUE if user changed value at all
114 void resetSpellDirty() { mPrevSpelledText = mWText; } // Clear dirty state
111 115
116 struct SpellMenuBind
117 {
118 LLTextEditor* origin;
119 LLMenuItemCallGL * menuItem;
120 std::string word;
121 S32 wordPositionStart;
122 S32 wordPositionEnd;
123 S32 wordY;
124 };
125
112 // LLEditMenuHandler interface 126 // LLEditMenuHandler interface
113 virtual void undo(); 127 virtual void undo();
114 virtual BOOL canUndo() const; 128 virtual BOOL canUndo() const;
115 virtual void redo(); 129 virtual void redo();
116 virtual BOOL canRedo() const; 130 virtual BOOL canRedo() const;
117
118 virtual void cut(); 131 virtual void cut();
119 virtual BOOL canCut() const; 132 virtual BOOL canCut() const;
120 virtual void copy(); 133 virtual void copy();
121 virtual BOOL canCopy() const; 134 virtual BOOL canCopy() const;
122 virtual void paste(); 135 virtual void paste();
123 virtual BOOL canPaste() const; 136 virtual BOOL canPaste() const;
137
138 virtual void spellReplace(SpellMenuBind* spellData);
139
124 virtual void updatePrimary(); 140 virtual void updatePrimary();
125 virtual void copyPrimary(); 141 virtual void copyPrimary();
126 virtual void pastePrimary(); 142 virtual void pastePrimary();
127 virtual BOOL canPastePrimary() const; 143 virtual BOOL canPastePrimary() const;
144
128 virtual void doDelete(); 145 virtual void doDelete();
129 virtual BOOL canDoDelete() const; 146 virtual BOOL canDoDelete() const;
130 virtual void selectAll(); 147 virtual void selectAll();
131 virtual BOOL canSelectAll() const; 148 virtual BOOL canSelectAll() const;
132 virtual void deselect(); 149 virtual void deselect();
133 virtual BOOL canDeselect() const; 150 virtual BOOL canDeselect() const;
151 static void context_cut(void* data);
152
153 static void context_copy(void* data);
154 static void context_paste(void* data);
155 static void context_delete(void* data);
156 static void context_selectall(void* data);
157 static void translateText(void * data);
158 static void spell_correct(void* data);
159 static void spell_add(void* data);
160 static void spell_show(void* data);
161 std::vector<S32> getMisspelledWordsPositions();
134 162
135 void selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE); 163 void selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE);
136 BOOL replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE); 164 BOOL replaceText(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive, BOOL wrap = TRUE);
@@ -145,17 +173,17 @@ public:
145 BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; } 173 BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; }
146 174
147 // inserts text at cursor 175 // inserts text at cursor
148 void insertText(const std::string &text); 176 void insertText(const std::string &text, BOOL deleteSelection = TRUE);
149 // appends text at end 177 // appends text at end
150 void appendText(const std::string &wtext, bool allow_undo, bool prepend_newline, 178 void appendText(const std::string &wtext, bool allow_undo, bool prepend_newline,
151 const LLStyleSP stylep = NULL); 179 const LLStyleSP stylep = NULL);
152 180
153 void appendColoredText(const std::string &wtext, bool allow_undo, 181 void appendColoredText(const std::string &wtext, bool allow_undo,
154 bool prepend_newline, 182 bool prepend_newline,
155 const LLColor4 &color, 183 const LLColor4 &color,
156 const std::string& font_name = LLStringUtil::null); 184 const std::string& font_name = LLStringUtil::null);
157 // if styled text starts a line, you need to prepend a newline. 185 // if styled text starts a line, you need to prepend a newline.
158 void appendStyledText(const std::string &new_text, bool allow_undo, 186 void appendStyledText(const std::string &new_text, bool allow_undo,
159 bool prepend_newline, 187 bool prepend_newline,
160 LLStyleSP stylep = NULL); 188 LLStyleSP stylep = NULL);
161 void appendHighlightedText(const std::string &new_text, bool allow_undo, 189 void appendHighlightedText(const std::string &new_text, bool allow_undo,
@@ -182,6 +210,11 @@ public:
182 const std::vector<std::string>& funcs, 210 const std::vector<std::string>& funcs,
183 const std::vector<std::string>& tooltips, 211 const std::vector<std::string>& tooltips,
184 const LLColor3& func_color); 212 const LLColor3& func_color);
213 void addToken(LLKeywordToken::TOKEN_TYPE type,
214 const std::string& key,
215 const LLColor3& color,
216 const std::string& tool_tip = LLStringUtil::null,
217 const std::string& delimiter = LLStringUtil::null);
185 LLKeywords::keyword_iterator_t keywordsBegin() { return mKeywords.begin(); } 218 LLKeywords::keyword_iterator_t keywordsBegin() { return mKeywords.begin(); }
186 LLKeywords::keyword_iterator_t keywordsEnd() { return mKeywords.end(); } 219 LLKeywords::keyword_iterator_t keywordsEnd() { return mKeywords.end(); }
187 220
@@ -196,6 +229,7 @@ public:
196 void setThumbColor( const LLColor4& color ); 229 void setThumbColor( const LLColor4& color );
197 void setHighlightColor( const LLColor4& color ); 230 void setHighlightColor( const LLColor4& color );
198 void setShadowColor( const LLColor4& color ); 231 void setShadowColor( const LLColor4& color );
232 void setOverRideAndShowMisspellings(BOOL b){ mOverRideAndShowMisspellings =b;}
199 233
200 // Hacky methods to make it into a word-wrapping, potentially scrolling, 234 // Hacky methods to make it into a word-wrapping, potentially scrolling,
201 // read-only text box. 235 // read-only text box.
@@ -262,7 +296,7 @@ public:
262 const LLTextSegment* getPreviousSegment() const; 296 const LLTextSegment* getPreviousSegment() const;
263 void getSelectedSegments(std::vector<const LLTextSegment*>& segments) const; 297 void getSelectedSegments(std::vector<const LLTextSegment*>& segments) const;
264 298
265 static bool isPartOfWord(llwchar c) { return (c == '_') || LLStringOps::isAlnum((char)c); } 299 static bool isPartOfWord(llwchar c) { return ( (c == '_') || (c == '\'') || LLStringOps::isAlnum((char)c)); }
266 300
267 BOOL isReadOnly() { return mReadOnly; } 301 BOOL isReadOnly() { return mReadOnly; }
268protected: 302protected:
@@ -270,11 +304,14 @@ protected:
270 // Methods 304 // Methods
271 // 305 //
272 306
307 LLHandle<LLView> mPopupMenuHandle;
308
273 S32 getLength() const { return mWText.length(); } 309 S32 getLength() const { return mWText.length(); }
274 void getSegmentAndOffset( S32 startpos, S32* segidxp, S32* offsetp ) const; 310 void getSegmentAndOffset( S32 startpos, S32* segidxp, S32* offsetp ) const;
275 void drawPreeditMarker(); 311 void drawPreeditMarker();
276 312public:
277 void updateLineStartList(S32 startpos = 0); 313 void updateLineStartList(S32 startpos = 0);
314protected:
278 void updateScrollFromCursor(); 315 void updateScrollFromCursor();
279 void updateTextRect(); 316 void updateTextRect();
280 const LLRect& getTextRect() const { return mTextRect; } 317 const LLRect& getTextRect() const { return mTextRect; }
@@ -301,8 +338,13 @@ protected:
301 BOOL handleSelectionKey(const KEY key, const MASK mask); 338 BOOL handleSelectionKey(const KEY key, const MASK mask);
302 BOOL handleControlKey(const KEY key, const MASK mask); 339 BOOL handleControlKey(const KEY key, const MASK mask);
303 BOOL handleEditKey(const KEY key, const MASK mask); 340 BOOL handleEditKey(const KEY key, const MASK mask);
304 341 // <edit>
342public:
343 // </edit>
305 BOOL hasSelection() const { return (mSelectionStart !=mSelectionEnd); } 344 BOOL hasSelection() const { return (mSelectionStart !=mSelectionEnd); }
345 // <edit>
346 protected:
347 // </edit>
306 BOOL selectionContainsLineBreaks(); 348 BOOL selectionContainsLineBreaks();
307 void startSelection(); 349 void startSelection();
308 void endSelection(); 350 void endSelection();
@@ -330,7 +372,7 @@ protected:
330 virtual void unbindEmbeddedChars(const LLFontGL* font) const {} 372 virtual void unbindEmbeddedChars(const LLFontGL* font) const {}
331 373
332 S32 findHTMLToken(const std::string &line, S32 pos, BOOL reverse) const; 374 S32 findHTMLToken(const std::string &line, S32 pos, BOOL reverse) const;
333 BOOL findHTML(const std::string &line, S32 *begin, S32 *end) const; 375 BOOL findHTML(const std::string &line, S32 *begin, S32 *end, std::string& url) const;
334 376
335 // Abstract inner base class representing an undoable editor command. 377 // Abstract inner base class representing an undoable editor command.
336 // Concrete sub-classes can be defined for operations such as insert, remove, etc. 378 // Concrete sub-classes can be defined for operations such as insert, remove, etc.
@@ -400,8 +442,9 @@ protected:
400 // 442 //
401 443
402 // I-beam is just after the mCursorPos-th character. 444 // I-beam is just after the mCursorPos-th character.
445public:
403 S32 mCursorPos; 446 S32 mCursorPos;
404 447protected:
405 // Use these to determine if a click on an embedded item is a drag or not. 448 // Use these to determine if a click on an embedded item is a drag or not.
406 S32 mMouseDownX; 449 S32 mMouseDownX;
407 S32 mMouseDownY; 450 S32 mMouseDownY;
@@ -447,6 +490,8 @@ private:
447 void drawBackground(); 490 void drawBackground();
448 void drawSelectionBackground(); 491 void drawSelectionBackground();
449 void drawCursor(); 492 void drawCursor();
493 void autoCorrectText();
494 void drawMisspelled();
450 void drawText(); 495 void drawText();
451 void drawClippedSegment(const LLWString &wtext, S32 seg_start, S32 seg_end, F32 x, F32 y, S32 selection_left, S32 selection_right, const LLStyleSP& color, F32* right_x); 496 void drawClippedSegment(const LLWString &wtext, S32 seg_start, S32 seg_end, F32 x, F32 y, S32 selection_left, S32 selection_right, const LLStyleSP& color, F32* right_x);
452 497
@@ -477,6 +522,12 @@ private:
477 mutable std::string mUTF8Text; 522 mutable std::string mUTF8Text;
478 mutable BOOL mTextIsUpToDate; 523 mutable BOOL mTextIsUpToDate;
479 524
525 LLWString mPrevSpelledText; // saved string so we know whether to respell or not
526 S32 spellStart;
527 S32 spellEnd;
528 std::vector<S32> misspellLocations; // where all the mispelled words are
529 BOOL mOverRideAndShowMisspellings;
530
480 S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes 531 S32 mMaxTextByteLength; // Maximum length mText is allowed to be in bytes
481 532
482 const LLFontGL* mGLFont; 533 const LLFontGL* mGLFont;
@@ -513,11 +564,16 @@ private:
513 } 564 }
514 }; 565 };
515 typedef std::vector<line_info> line_list_t; 566 typedef std::vector<line_info> line_list_t;
567
568 //to keep track of what we have to remove before showing menu
569 std::vector<SpellMenuBind* > suggestionMenuItems;
570
516 line_list_t mLineStartList; 571 line_list_t mLineStartList;
517 BOOL mReflowNeeded; 572 BOOL mReflowNeeded;
518 BOOL mScrollNeeded; 573 BOOL mScrollNeeded;
519 574
520 LLFrameTimer mKeystrokeTimer; 575 LLFrameTimer mKeystrokeTimer;
576 LLFrameTimer mSpellTimer;
521 577
522 LLColor4 mCursorColor; 578 LLColor4 mCursorColor;
523 579