diff options
author | Patrick Sapinski | 2010-08-24 03:04:20 -0400 |
---|---|---|
committer | McCabe Maxsted | 2010-08-30 17:04:59 -0700 |
commit | ded1245db74ae4c97d174c5779f8572ee2f032fa (patch) | |
tree | f42c33f233ed68e715a0ac4c74ddc043f43a68da /linden/indra/llui | |
parent | Added debug setting UseLegacyChatLogsFolder for saving chat.txt and IM logs i... (diff) | |
download | meta-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.cpp | 521 | ||||
-rw-r--r-- | linden/indra/llui/lllineeditor.h | 47 | ||||
-rw-r--r-- | linden/indra/llui/llmenugl.cpp | 25 | ||||
-rw-r--r-- | linden/indra/llui/llmenugl.h | 3 | ||||
-rw-r--r-- | linden/indra/llui/lltexteditor.cpp | 639 | ||||
-rw-r--r-- | linden/indra/llui/lltexteditor.h | 74 |
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 | // |
96 | class LineChatTranslationReceiver : public LLTranslate::TranslationReceiver | ||
97 | { | ||
98 | public : | ||
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 | |||
109 | protected: | ||
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 | } | ||
121 | private: | ||
122 | LLLineEditor* m_line; | ||
123 | }; | ||
92 | 124 | ||
93 | LLLineEditor::LLLineEditor(const std::string& name, const LLRect& rect, | 125 | LLLineEditor::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. |
346 | void LLLineEditor::setCursorAtLocalPos( S32 local_mouse_x ) | 434 | S32 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. | ||
455 | void LLLineEditor::setCursorAtLocalPos( S32 local_mouse_x ) | ||
456 | { | ||
457 | setCursor(calculateCursorFromMouse(local_mouse_x)); | ||
366 | } | 458 | } |
367 | 459 | ||
368 | void LLLineEditor::setCursor( S32 pos ) | 460 | void LLLineEditor::setCursor( S32 pos ) |
@@ -418,6 +510,125 @@ void LLLineEditor::deselect() | |||
418 | } | 510 | } |
419 | 511 | ||
420 | 512 | ||
513 | void LLLineEditor::context_cut(void* data) | ||
514 | { | ||
515 | LLLineEditor* line = (LLLineEditor*)data; | ||
516 | if(line)line->cut(); | ||
517 | } | ||
518 | void LLLineEditor::context_copy(void* data) | ||
519 | { | ||
520 | LLLineEditor* line = (LLLineEditor*)data; | ||
521 | if(line)line->copy(); | ||
522 | } | ||
523 | void 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 | } | ||
534 | void 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 | } | ||
544 | void 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 | } | ||
562 | std::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 | } | ||
607 | void 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 | } | ||
616 | void LLLineEditor::context_paste(void* data) | ||
617 | { | ||
618 | LLLineEditor* line = (LLLineEditor*)data; | ||
619 | if(line)line->paste(); | ||
620 | } | ||
621 | void LLLineEditor::context_delete(void* data) | ||
622 | { | ||
623 | LLLineEditor* line = (LLLineEditor*)data; | ||
624 | if(line)line->doDelete(); | ||
625 | } | ||
626 | void LLLineEditor::context_selectall(void* data) | ||
627 | { | ||
628 | LLLineEditor* line = (LLLineEditor*)data; | ||
629 | if(line)line->selectAll(); | ||
630 | } | ||
631 | |||
421 | void LLLineEditor::startSelection() | 632 | void 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 | |||
723 | BOOL 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 | |||
511 | BOOL LLLineEditor::handleMouseDown(S32 x, S32 y, MASK mask) | 828 | BOOL 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 | ||
1291 | void 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 | } | ||
1300 | void 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 | |||
974 | BOOL LLLineEditor::canPaste() const | 1318 | BOOL 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 | } |
1841 | void 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 | } | ||
1882 | void 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 | } | ||
1476 | void LLLineEditor::draw() | 1929 | void 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 | ||
2165 | BOOL LLLineEditor::evaluateFloat() | 2622 | BOOL 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 | ||
2199 | void LLLineEditor::onMouseCaptureLost() | 2648 | void 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: | |||
225 | private: | 256 | private: |
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 | ||
255 | protected: | 287 | protected: |
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. | ||
2586 | BOOL 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 | |||
2585 | void LLMenuGL::setEnabledSubMenus(BOOL enable) | 2610 | void 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; | |||
96 | void (* LLTextEditor::mURLcallback)(const std::string&) = NULL; | 100 | void (* LLTextEditor::mURLcallback)(const std::string&) = NULL; |
97 | bool (* LLTextEditor::mSecondlifeURLcallback)(const std::string&) = NULL; | 101 | bool (* LLTextEditor::mSecondlifeURLcallback)(const std::string&) = NULL; |
98 | bool (* LLTextEditor::mSecondlifeURLcallbackRightClick)(const std::string&) = NULL; | 102 | bool (* LLTextEditor::mSecondlifeURLcallbackRightClick)(const std::string&) = NULL; |
103 | /////////////////////////////////////////////////////////////////// | ||
104 | |||
105 | class TextChatTranslationReceiver : public LLTranslate::TranslationReceiver | ||
106 | { | ||
107 | public : | ||
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 | ||
118 | protected: | ||
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 | } | ||
128 | private: | ||
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 | } | ||
452 | void LLTextEditor::context_cut(void* data) | ||
453 | { | ||
454 | LLTextEditor* line = (LLTextEditor*)data; | ||
455 | if(line)line->cut(); | ||
456 | } | ||
457 | void LLTextEditor::context_copy(void* data) | ||
458 | { | ||
459 | LLTextEditor* line = (LLTextEditor*)data; | ||
460 | if(line)line->copy(); | ||
461 | } | ||
462 | void 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 | } | ||
473 | void 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 | } | ||
484 | void 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 | |||
501 | std::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 | } | ||
540 | void 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 | } | ||
549 | void LLTextEditor::context_paste(void* data) | ||
550 | { | ||
551 | LLTextEditor* line = (LLTextEditor*)data; | ||
552 | if(line)line->paste(); | ||
553 | } | ||
554 | void LLTextEditor::context_delete(void* data) | ||
555 | { | ||
556 | LLTextEditor* line = (LLTextEditor*)data; | ||
557 | if(line)line->doDelete(); | ||
558 | } | ||
559 | void LLTextEditor::context_selectall(void* data) | ||
560 | { | ||
561 | LLTextEditor* line = (LLTextEditor*)data; | ||
562 | if(line)line->selectAll(); | ||
363 | } | 563 | } |
364 | 564 | ||
365 | void LLTextEditor::setTrackColor( const LLColor4& color ) | 565 | void 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 | ||
887 | void LLTextEditor::setCursor(S32 row, S32 column) | 1080 | void 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 | } |
1415 | BOOL 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 | ||
1221 | BOOL LLTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) | 1518 | BOOL 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 | ||
2207 | void 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 |
1917 | void LLTextEditor::paste() | 2218 | void 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 | } |
3068 | void 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 | } | ||
3109 | void 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 | ||
2743 | void LLTextEditor::drawCursor() | 3203 | void 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() | |||
3250 | void LLTextEditor::clear() | 3716 | void 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 |
3601 | void LLTextEditor::insertText(const std::string &new_text) | 4069 | void 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 | ||
3640 | void LLTextEditor::appendStyledText(const std::string &new_text, | 4108 | void 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 | ||
4428 | void 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 | |||
3955 | void LLTextEditor::updateSegments() | 4437 | void 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 | ||
4472 | BOOL LLTextEditor::findHTML(const std::string &line, S32 *begin, S32 *end) const | 4951 | BOOL 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 | ||
49 | class LLFontGL; | 50 | class LLFontGL; |
50 | class LLScrollbar; | 51 | class 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; } |
268 | protected: | 302 | protected: |
@@ -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 | 312 | public: | |
277 | void updateLineStartList(S32 startpos = 0); | 313 | void updateLineStartList(S32 startpos = 0); |
314 | protected: | ||
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> | |
342 | public: | ||
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. |
445 | public: | ||
403 | S32 mCursorPos; | 446 | S32 mCursorPos; |
404 | 447 | protected: | |
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 | ||