aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/llui/lltexteditor.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-09-06 18:24:57 -0500
committerJacek Antonelli2008-09-06 18:25:07 -0500
commit798d367d54a6c6379ad355bd8345fa40e31e7fe9 (patch)
tree1921f1708cd0240648c97bc02df2c2ab5f2fc41e /linden/indra/llui/lltexteditor.cpp
parentSecond Life viewer sources 1.20.15 (diff)
downloadmeta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.zip
meta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.tar.gz
meta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.tar.bz2
meta-impy-798d367d54a6c6379ad355bd8345fa40e31e7fe9.tar.xz
Second Life viewer sources 1.21.0-RC
Diffstat (limited to 'linden/indra/llui/lltexteditor.cpp')
-rw-r--r--linden/indra/llui/lltexteditor.cpp328
1 files changed, 211 insertions, 117 deletions
diff --git a/linden/indra/llui/lltexteditor.cpp b/linden/indra/llui/lltexteditor.cpp
index 71522e5..e56002f 100644
--- a/linden/indra/llui/lltexteditor.cpp
+++ b/linden/indra/llui/lltexteditor.cpp
@@ -36,13 +36,11 @@
36#include "lltexteditor.h" 36#include "lltexteditor.h"
37 37
38#include "llfontgl.h" 38#include "llfontgl.h"
39#include "llgl.h"
40#include "llrender.h" 39#include "llrender.h"
41#include "llui.h" 40#include "llui.h"
42#include "lluictrlfactory.h" 41#include "lluictrlfactory.h"
43#include "llrect.h" 42#include "llrect.h"
44#include "llfocusmgr.h" 43#include "llfocusmgr.h"
45#include "sound_ids.h"
46#include "lltimer.h" 44#include "lltimer.h"
47#include "llmath.h" 45#include "llmath.h"
48 46
@@ -58,7 +56,6 @@
58#include "llcontrol.h" 56#include "llcontrol.h"
59#include "llimagegl.h" 57#include "llimagegl.h"
60#include "llwindow.h" 58#include "llwindow.h"
61#include "llglheaders.h"
62#include <queue> 59#include <queue>
63 60
64// 61//
@@ -75,6 +72,8 @@ const S32 UI_TEXTEDITOR_BUFFER_BLOCK_SIZE = 512;
75const S32 UI_TEXTEDITOR_BORDER = 1; 72const S32 UI_TEXTEDITOR_BORDER = 1;
76const S32 UI_TEXTEDITOR_H_PAD = 4; 73const S32 UI_TEXTEDITOR_H_PAD = 4;
77const S32 UI_TEXTEDITOR_V_PAD_TOP = 4; 74const S32 UI_TEXTEDITOR_V_PAD_TOP = 4;
75const S32 UI_TEXTEDITOR_LINE_NUMBER_MARGIN = 32;
76const S32 UI_TEXTEDITOR_LINE_NUMBER_DIGITS = 4;
78const F32 CURSOR_FLASH_DELAY = 1.0f; // in seconds 77const F32 CURSOR_FLASH_DELAY = 1.0f; // in seconds
79const S32 CURSOR_THICKNESS = 2; 78const S32 CURSOR_THICKNESS = 2;
80const S32 SPACES_PER_TAB = 4; 79const S32 SPACES_PER_TAB = 4;
@@ -88,8 +87,9 @@ const S32 PREEDIT_STANDOUT_GAP = 1;
88const S32 PREEDIT_STANDOUT_POSITION = 2; 87const S32 PREEDIT_STANDOUT_POSITION = 2;
89const S32 PREEDIT_STANDOUT_THICKNESS = 2; 88const S32 PREEDIT_STANDOUT_THICKNESS = 2;
90 89
90
91LLColor4 LLTextEditor::mLinkColor = LLColor4::blue; 91LLColor4 LLTextEditor::mLinkColor = LLColor4::blue;
92void (* LLTextEditor::mURLcallback)(const char*) = NULL; 92void (* LLTextEditor::mURLcallback)(const std::string&) = NULL;
93bool (* LLTextEditor::mSecondlifeURLcallback)(const std::string&) = NULL; 93bool (* LLTextEditor::mSecondlifeURLcallback)(const std::string&) = NULL;
94bool (* LLTextEditor::mSecondlifeURLcallbackRightClick)(const std::string&) = NULL; 94bool (* LLTextEditor::mSecondlifeURLcallbackRightClick)(const std::string&) = NULL;
95 95
@@ -107,7 +107,7 @@ public:
107 virtual BOOL execute( LLTextEditor* editor, S32* delta ) 107 virtual BOOL execute( LLTextEditor* editor, S32* delta )
108 { 108 {
109 *delta = insert(editor, getPosition(), mWString ); 109 *delta = insert(editor, getPosition(), mWString );
110 LLWString::truncate(mWString, *delta); 110 LLWStringUtil::truncate(mWString, *delta);
111 //mWString = wstring_truncate(mWString, *delta); 111 //mWString = wstring_truncate(mWString, *delta);
112 return (*delta != 0); 112 return (*delta != 0);
113 } 113 }
@@ -145,7 +145,7 @@ public:
145 virtual BOOL execute( LLTextEditor* editor, S32* delta ) 145 virtual BOOL execute( LLTextEditor* editor, S32* delta )
146 { 146 {
147 *delta = insert(editor, getPosition(), mWString); 147 *delta = insert(editor, getPosition(), mWString);
148 LLWString::truncate(mWString, *delta); 148 LLWStringUtil::truncate(mWString, *delta);
149 //mWString = wstring_truncate(mWString, *delta); 149 //mWString = wstring_truncate(mWString, *delta);
150 return (*delta != 0); 150 return (*delta != 0);
151 } 151 }
@@ -243,10 +243,10 @@ private:
243/////////////////////////////////////////////////////////////////// 243///////////////////////////////////////////////////////////////////
244 244
245LLTextEditor::LLTextEditor( 245LLTextEditor::LLTextEditor(
246 const LLString& name, 246 const std::string& name,
247 const LLRect& rect, 247 const LLRect& rect,
248 S32 max_length, // In bytes 248 S32 max_length, // In bytes
249 const LLString &default_text, 249 const std::string &default_text,
250 const LLFontGL* font, 250 const LLFontGL* font,
251 BOOL allow_embedded_items) 251 BOOL allow_embedded_items)
252 : 252 :
@@ -260,6 +260,7 @@ LLTextEditor::LLTextEditor(
260 mIsSelecting( FALSE ), 260 mIsSelecting( FALSE ),
261 mSelectionStart( 0 ), 261 mSelectionStart( 0 ),
262 mSelectionEnd( 0 ), 262 mSelectionEnd( 0 ),
263 mScrolledToBottom( FALSE ),
263 mOnScrollEndCallback( NULL ), 264 mOnScrollEndCallback( NULL ),
264 mOnScrollEndData( NULL ), 265 mOnScrollEndData( NULL ),
265 mCursorColor( LLUI::sColorsGroup->getColor( "TextCursorColor" ) ), 266 mCursorColor( LLUI::sColorsGroup->getColor( "TextCursorColor" ) ),
@@ -271,6 +272,7 @@ LLTextEditor::LLTextEditor(
271 mFocusBgColor( LLUI::sColorsGroup->getColor( "TextBgFocusColor" ) ), 272 mFocusBgColor( LLUI::sColorsGroup->getColor( "TextBgFocusColor" ) ),
272 mReadOnly(FALSE), 273 mReadOnly(FALSE),
273 mWordWrap( FALSE ), 274 mWordWrap( FALSE ),
275 mShowLineNumbers ( FALSE ),
274 mTabsToNextField( TRUE ), 276 mTabsToNextField( TRUE ),
275 mCommitOnFocusLost( FALSE ), 277 mCommitOnFocusLost( FALSE ),
276 mHideScrollbarForShortDocs( FALSE ), 278 mHideScrollbarForShortDocs( FALSE ),
@@ -311,7 +313,7 @@ LLTextEditor::LLTextEditor(
311 SCROLLBAR_SIZE, 313 SCROLLBAR_SIZE,
312 getRect().getHeight() - 1); 314 getRect().getHeight() - 1);
313 S32 lines_in_doc = getLineCount(); 315 S32 lines_in_doc = getLineCount();
314 mScrollbar = new LLScrollbar( "Scrollbar", scroll_rect, 316 mScrollbar = new LLScrollbar( std::string("Scrollbar"), scroll_rect,
315 LLScrollbar::VERTICAL, 317 LLScrollbar::VERTICAL,
316 lines_in_doc, 318 lines_in_doc,
317 0, 319 0,
@@ -325,7 +327,7 @@ LLTextEditor::LLTextEditor(
325 mScrollbar->setOnScrollEndCallback(mOnScrollEndCallback, mOnScrollEndData); 327 mScrollbar->setOnScrollEndCallback(mOnScrollEndCallback, mOnScrollEndData);
326 addChild(mScrollbar); 328 addChild(mScrollbar);
327 329
328 mBorder = new LLViewBorder( "text ed border", LLRect(0, getRect().getHeight(), getRect().getWidth(), 0), LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, UI_TEXTEDITOR_BORDER ); 330 mBorder = new LLViewBorder( std::string("text ed border"), LLRect(0, getRect().getHeight(), getRect().getWidth(), 0), LLViewBorder::BEVEL_IN, LLViewBorder::STYLE_LINE, UI_TEXTEDITOR_BORDER );
329 addChild( mBorder ); 331 addChild( mBorder );
330 332
331 appendText(default_text, FALSE, FALSE); 333 appendText(default_text, FALSE, FALSE);
@@ -333,7 +335,7 @@ LLTextEditor::LLTextEditor(
333 resetDirty(); // Update saved text state 335 resetDirty(); // Update saved text state
334 336
335 mParseHTML=FALSE; 337 mParseHTML=FALSE;
336 mHTML=""; 338 mHTML.clear();
337} 339}
338 340
339 341
@@ -399,7 +401,8 @@ void LLTextEditor::updateLineStartList(S32 startpos)
399 { 401 {
400 mLineStartList.push_back(line_info(seg_idx,seg_offset)); 402 mLineStartList.push_back(line_info(seg_idx,seg_offset));
401 BOOL line_ended = FALSE; 403 BOOL line_ended = FALSE;
402 S32 line_width = 0; 404 S32 start_x = mShowLineNumbers ? UI_TEXTEDITOR_LINE_NUMBER_MARGIN : 0;
405 S32 line_width = start_x;
403 while(!line_ended && seg_idx < seg_num) 406 while(!line_ended && seg_idx < seg_num)
404 { 407 {
405 LLTextSegment* segment = mSegments[seg_idx]; 408 LLTextSegment* segment = mSegments[seg_idx];
@@ -429,7 +432,7 @@ void LLTextEditor::updateLineStartList(S32 startpos)
429 const llwchar* str = mWText.c_str() + start_idx; 432 const llwchar* str = mWText.c_str() + start_idx;
430 S32 drawn = mGLFont->maxDrawableChars(str, (F32)abs(mTextRect.getWidth()) - line_width, 433 S32 drawn = mGLFont->maxDrawableChars(str, (F32)abs(mTextRect.getWidth()) - line_width,
431 end_idx - start_idx, mWordWrap, mAllowEmbeddedItems ); 434 end_idx - start_idx, mWordWrap, mAllowEmbeddedItems );
432 if( 0 == drawn && line_width == 0) 435 if( 0 == drawn && line_width == start_x)
433 { 436 {
434 // If at the beginning of a line, draw at least one character, even if it doesn't all fit. 437 // If at the beginning of a line, draw at least one character, even if it doesn't all fit.
435 drawn = 1; 438 drawn = 1;
@@ -496,7 +499,7 @@ BOOL LLTextEditor::truncate()
496 499
497void LLTextEditor::setText(const LLStringExplicit &utf8str) 500void LLTextEditor::setText(const LLStringExplicit &utf8str)
498{ 501{
499 // LLString::removeCRLF(utf8str); 502 // LLStringUtil::removeCRLF(utf8str);
500 mUTF8Text = utf8str_removeCRLF(utf8str); 503 mUTF8Text = utf8str_removeCRLF(utf8str);
501 // mUTF8Text = utf8str; 504 // mUTF8Text = utf8str;
502 mWText = utf8str_to_wstring(mUTF8Text); 505 mWText = utf8str_to_wstring(mUTF8Text);
@@ -538,7 +541,7 @@ void LLTextEditor::setValue(const LLSD& value)
538 setText(value.asString()); 541 setText(value.asString());
539} 542}
540 543
541const LLString& LLTextEditor::getText() const 544const std::string& LLTextEditor::getText() const
542{ 545{
543 if (!mTextIsUpToDate) 546 if (!mTextIsUpToDate)
544 { 547 {
@@ -591,7 +594,7 @@ void LLTextEditor::setHideScrollbarForShortDocs(BOOL b)
591 } 594 }
592} 595}
593 596
594void LLTextEditor::selectNext(const LLString& search_text_in, BOOL case_insensitive, BOOL wrap) 597void LLTextEditor::selectNext(const std::string& search_text_in, BOOL case_insensitive, BOOL wrap)
595{ 598{
596 if (search_text_in.empty()) 599 if (search_text_in.empty())
597 { 600 {
@@ -602,8 +605,8 @@ void LLTextEditor::selectNext(const LLString& search_text_in, BOOL case_insensit
602 LLWString search_text = utf8str_to_wstring(search_text_in); 605 LLWString search_text = utf8str_to_wstring(search_text_in);
603 if (case_insensitive) 606 if (case_insensitive)
604 { 607 {
605 LLWString::toLower(text); 608 LLWStringUtil::toLower(text);
606 LLWString::toLower(search_text); 609 LLWStringUtil::toLower(search_text);
607 } 610 }
608 611
609 if (mIsSelecting) 612 if (mIsSelecting)
@@ -641,7 +644,7 @@ void LLTextEditor::selectNext(const LLString& search_text_in, BOOL case_insensit
641 mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size())); 644 mSelectionStart = llmin((S32)getLength(), (S32)(mCursorPos + search_text.size()));
642} 645}
643 646
644BOOL LLTextEditor::replaceText(const LLString& search_text_in, const LLString& replace_text, 647BOOL LLTextEditor::replaceText(const std::string& search_text_in, const std::string& replace_text,
645 BOOL case_insensitive, BOOL wrap) 648 BOOL case_insensitive, BOOL wrap)
646{ 649{
647 BOOL replaced = FALSE; 650 BOOL replaced = FALSE;
@@ -659,8 +662,8 @@ BOOL LLTextEditor::replaceText(const LLString& search_text_in, const LLString& r
659 662
660 if (case_insensitive) 663 if (case_insensitive)
661 { 664 {
662 LLWString::toLower(selected_text); 665 LLWStringUtil::toLower(selected_text);
663 LLWString::toLower(search_text); 666 LLWStringUtil::toLower(search_text);
664 } 667 }
665 668
666 if (selected_text == search_text) 669 if (selected_text == search_text)
@@ -674,7 +677,7 @@ BOOL LLTextEditor::replaceText(const LLString& search_text_in, const LLString& r
674 return replaced; 677 return replaced;
675} 678}
676 679
677void LLTextEditor::replaceTextAll(const LLString& search_text, const LLString& replace_text, BOOL case_insensitive) 680void LLTextEditor::replaceTextAll(const std::string& search_text, const std::string& replace_text, BOOL case_insensitive)
678{ 681{
679 S32 cur_pos = mScrollbar->getDocPos(); 682 S32 cur_pos = mScrollbar->getDocPos();
680 683
@@ -800,7 +803,12 @@ void LLTextEditor::getSelectedSegments(std::vector<const LLTextSegment*>& segmen
800 803
801S32 LLTextEditor::getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const 804S32 LLTextEditor::getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const
802{ 805{
803 // If round is true, if the position is on the right half of a character, the cursor 806 if(mShowLineNumbers)
807 {
808 local_x -= UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
809 }
810
811 // If round is true, if the position is on the right half of a character, the cursor
804 // will be put to its right. If round is false, the cursor will always be put to the 812 // will be put to its right. If round is false, the cursor will always be put to the
805 // character's left. 813 // character's left.
806 814
@@ -1061,7 +1069,7 @@ void LLTextEditor::selectAll()
1061} 1069}
1062 1070
1063 1071
1064BOOL LLTextEditor::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen) 1072BOOL LLTextEditor::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen)
1065{ 1073{
1066 for ( child_list_const_iter_t child_it = getChildList()->begin(); 1074 for ( child_list_const_iter_t child_it = getChildList()->begin();
1067 child_it != getChildList()->end(); ++child_it) 1075 child_it != getChildList()->end(); ++child_it)
@@ -1392,7 +1400,7 @@ BOOL LLTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
1392BOOL LLTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask, 1400BOOL LLTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask,
1393 BOOL drop, EDragAndDropType cargo_type, void *cargo_data, 1401 BOOL drop, EDragAndDropType cargo_type, void *cargo_data,
1394 EAcceptance *accept, 1402 EAcceptance *accept,
1395 LLString& tooltip_msg) 1403 std::string& tooltip_msg)
1396{ 1404{
1397 *accept = ACCEPT_NO; 1405 *accept = ACCEPT_NO;
1398 1406
@@ -1879,7 +1887,7 @@ void LLTextEditor::paste()
1879 1887
1880 // Clean up string (replace tabs and remove characters that our fonts don't support). 1888 // Clean up string (replace tabs and remove characters that our fonts don't support).
1881 LLWString clean_string(paste); 1889 LLWString clean_string(paste);
1882 LLWString::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB); 1890 LLWStringUtil::replaceTabsWithSpaces(clean_string, SPACES_PER_TAB);
1883 if( mAllowEmbeddedItems ) 1891 if( mAllowEmbeddedItems )
1884 { 1892 {
1885 const llwchar LF = 10; 1893 const llwchar LF = 10;
@@ -2469,20 +2477,15 @@ void LLTextEditor::drawBackground()
2469 S32 right = getRect().getWidth(); 2477 S32 right = getRect().getWidth();
2470 S32 bottom = 0; 2478 S32 bottom = 0;
2471 2479
2472 LLColor4 bg_color = mReadOnlyBgColor; 2480 LLColor4 bg_color = mReadOnly ? mReadOnlyBgColor
2473 2481 : gFocusMgr.getKeyboardFocus() == this ? mFocusBgColor : mWriteableBgColor;
2474 if( !mReadOnly ) 2482 if( mShowLineNumbers ) {
2475 { 2483 gl_rect_2d(left, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN, bottom, mReadOnlyBgColor ); // line number area always read-only
2476 if (gFocusMgr.getKeyboardFocus() == this) 2484 gl_rect_2d(UI_TEXTEDITOR_LINE_NUMBER_MARGIN, top, right, bottom, bg_color); // body text area to the right of line numbers
2477 { 2485 gl_rect_2d(UI_TEXTEDITOR_LINE_NUMBER_MARGIN, top, UI_TEXTEDITOR_LINE_NUMBER_MARGIN-1, bottom, LLColor4::grey3); // separator
2478 bg_color = mFocusBgColor; 2486 } else {
2479 } 2487 gl_rect_2d(left, top, right, bottom, bg_color); // body text area
2480 else
2481 {
2482 bg_color = mWriteableBgColor;
2483 }
2484 } 2488 }
2485 gl_rect_2d(left, top, right, bottom, bg_color);
2486 2489
2487 LLView::draw(); 2490 LLView::draw();
2488} 2491}
@@ -2570,7 +2573,7 @@ void LLTextEditor::drawSelectionBackground()
2570 { 2573 {
2571 // extend selection slightly beyond end of line 2574 // extend selection slightly beyond end of line
2572 // to indicate selection of newline character (use "n" character to determine width) 2575 // to indicate selection of newline character (use "n" character to determine width)
2573 const LLWString nstr(utf8str_to_wstring(LLString("n"))); 2576 const LLWString nstr(utf8str_to_wstring(std::string("n")));
2574 line_endings.push(mTextRect.mLeft + mGLFont->getWidth(line, 0, line_end - line_start, mAllowEmbeddedItems) + mGLFont->getWidth(nstr.c_str())); 2577 line_endings.push(mTextRect.mLeft + mGLFont->getWidth(line, 0, line_end - line_start, mAllowEmbeddedItems) + mGLFont->getWidth(nstr.c_str()));
2575 } 2578 }
2576 2579
@@ -2595,12 +2598,13 @@ void LLTextEditor::drawSelectionBackground()
2595 const LLColor4& color = mReadOnly ? mReadOnlyBgColor : mWriteableBgColor; 2598 const LLColor4& color = mReadOnly ? mReadOnlyBgColor : mWriteableBgColor;
2596 F32 alpha = hasFocus() ? 1.f : 0.5f; 2599 F32 alpha = hasFocus() ? 1.f : 0.5f;
2597 gGL.color4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha ); 2600 gGL.color4f( 1.f - color.mV[0], 1.f - color.mV[1], 1.f - color.mV[2], alpha );
2601 S32 margin_offset = mShowLineNumbers ? UI_TEXTEDITOR_LINE_NUMBER_MARGIN : 0;
2598 2602
2599 if( selection_left_y == selection_right_y ) 2603 if( selection_left_y == selection_right_y )
2600 { 2604 {
2601 // Draw from selection start to selection end 2605 // Draw from selection start to selection end
2602 gl_rect_2d( selection_left_x, selection_left_y + line_height + 1, 2606 gl_rect_2d( selection_left_x + margin_offset, selection_left_y + line_height + 1,
2603 selection_right_x, selection_right_y); 2607 selection_right_x + margin_offset, selection_right_y);
2604 } 2608 }
2605 else 2609 else
2606 { 2610 {
@@ -2612,16 +2616,16 @@ void LLTextEditor::drawSelectionBackground()
2612 2616
2613 S32 line_end = line_endings.front(); 2617 S32 line_end = line_endings.front();
2614 line_endings.pop(); 2618 line_endings.pop();
2615 gl_rect_2d( selection_left_x, selection_left_y + line_height + 1, 2619 gl_rect_2d( selection_left_x + margin_offset, selection_left_y + line_height + 1,
2616 line_end, selection_left_y ); 2620 line_end + margin_offset, selection_left_y );
2617 2621
2618 S32 line_num = left_line_num + 1; 2622 S32 line_num = left_line_num + 1;
2619 while(line_endings.size()) 2623 while(line_endings.size())
2620 { 2624 {
2621 S32 vert_offset = -(line_num - left_line_num) * line_height; 2625 S32 vert_offset = -(line_num - left_line_num) * line_height;
2622 // Draw the block between the two lines 2626 // Draw the block between the two lines
2623 gl_rect_2d( mTextRect.mLeft, selection_left_y + vert_offset + line_height + 1, 2627 gl_rect_2d( mTextRect.mLeft + margin_offset, selection_left_y + vert_offset + line_height + 1,
2624 line_endings.front(), selection_left_y + vert_offset); 2628 line_endings.front() + margin_offset, selection_left_y + vert_offset);
2625 line_endings.pop(); 2629 line_endings.pop();
2626 line_num++; 2630 line_num++;
2627 } 2631 }
@@ -2631,8 +2635,8 @@ void LLTextEditor::drawSelectionBackground()
2631 { 2635 {
2632 selection_right_x += CURSOR_THICKNESS; 2636 selection_right_x += CURSOR_THICKNESS;
2633 } 2637 }
2634 gl_rect_2d( mTextRect.mLeft, selection_right_y + line_height + 1, 2638 gl_rect_2d( mTextRect.mLeft + margin_offset, selection_right_y + line_height + 1,
2635 selection_right_x, selection_right_y ); 2639 selection_right_x + margin_offset, selection_right_y );
2636 } 2640 }
2637 } 2641 }
2638 } 2642 }
@@ -2695,6 +2699,11 @@ void LLTextEditor::drawCursor()
2695 cur_pos++; 2699 cur_pos++;
2696 } 2700 }
2697 2701
2702 if(mShowLineNumbers)
2703 {
2704 cursor_left += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
2705 }
2706
2698 // Draw the cursor 2707 // Draw the cursor
2699 if( cursor_visible ) 2708 if( cursor_visible )
2700 { 2709 {
@@ -2707,7 +2716,7 @@ void LLTextEditor::drawCursor()
2707 if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection()) 2716 if (LL_KIM_OVERWRITE == gKeyboard->getInsertMode() && !hasSelection())
2708 { 2717 {
2709 cursor_left += CURSOR_THICKNESS; 2718 cursor_left += CURSOR_THICKNESS;
2710 const LLWString space(utf8str_to_wstring(LLString(" "))); 2719 const LLWString space(utf8str_to_wstring(std::string(" ")));
2711 F32 spacew = mGLFont->getWidthF32(space.c_str()); 2720 F32 spacew = mGLFont->getWidthF32(space.c_str());
2712 if (mCursorPos == line_end) 2721 if (mCursorPos == line_end)
2713 { 2722 {
@@ -2861,10 +2870,7 @@ void LLTextEditor::drawText()
2861{ 2870{
2862 const LLWString &text = mWText; 2871 const LLWString &text = mWText;
2863 const S32 text_len = getLength(); 2872 const S32 text_len = getLength();
2864 if( text_len <= 0 ) 2873 if( text_len <= 0 ) return;
2865 {
2866 return;
2867 }
2868 S32 selection_left = -1; 2874 S32 selection_left = -1;
2869 S32 selection_right = -1; 2875 S32 selection_right = -1;
2870 // Draw selection even if we don't have keyboard focus for search/replace 2876 // Draw selection even if we don't have keyboard focus for search/replace
@@ -2876,14 +2882,26 @@ void LLTextEditor::drawText()
2876 2882
2877 LLGLSUIDefault gls_ui; 2883 LLGLSUIDefault gls_ui;
2878 2884
2879 S32 cur_line = mScrollbar->getDocPos(); 2885 // There are several concepts that are important for understanding the following drawing code.
2886 // The document is logically a sequence of characters (stored in a LLWString).
2887 // Variables below with "start" or "end" in their names refer to positions or offsets into it.
2888 // Next there are two kinds of "line" variables to understand. Newline characters in the
2889 // character sequence represent logical lines. These are what get numbered and so variables
2890 // representing this kind of line have "num" in their names.
2891 // The others represent line fragments or displayed lines which the scrollbar deals with.
2892 // When the "show line numbers" property is turned on, we draw line numbers to the left of the
2893 // beginning of each logical line and not in front of wrapped "continuation" display lines. -MG
2894
2895 S32 cur_line = mScrollbar->getDocPos(); // scrollbar counts each wrap as a new line.
2880 S32 num_lines = getLineCount(); 2896 S32 num_lines = getLineCount();
2881 if (cur_line >= num_lines) 2897 if (cur_line >= num_lines) return;
2882 {
2883 return;
2884 }
2885
2886 S32 line_start = getLineStart(cur_line); 2898 S32 line_start = getLineStart(cur_line);
2899 S32 prev_start = getLineStart(cur_line-1);
2900 S32 cur_line_num = getLineForPosition(line_start); // doesn't count wraps. i.e. only counts newlines.
2901 S32 prev_line_num = getLineForPosition(prev_start);
2902 BOOL cur_line_is_continuation = cur_line_num > 0 && cur_line_num == prev_line_num;
2903 BOOL line_wraps = FALSE;
2904
2887 LLTextSegment t(line_start); 2905 LLTextSegment t(line_start);
2888 segment_list_t::iterator seg_iter; 2906 segment_list_t::iterator seg_iter;
2889 seg_iter = std::upper_bound(mSegments.begin(), mSegments.end(), &t, LLTextSegment::compare()); 2907 seg_iter = std::upper_bound(mSegments.begin(), mSegments.end(), &t, LLTextSegment::compare());
@@ -2902,12 +2920,36 @@ void LLTextEditor::drawText()
2902 next_start = getLineStart(cur_line + 1); 2920 next_start = getLineStart(cur_line + 1);
2903 line_end = next_start; 2921 line_end = next_start;
2904 } 2922 }
2905 if ( text[line_end-1] == '\n' ) 2923 line_wraps = text[line_end-1] != '\n';
2924 if ( ! line_wraps )
2906 { 2925 {
2907 --line_end; 2926 --line_end; // don't attempt to draw the newline char.
2908 } 2927 }
2909 2928
2910 F32 text_x = (F32)mTextRect.mLeft; 2929 F32 text_start = (F32)mTextRect.mLeft;
2930 F32 text_x = text_start + (mShowLineNumbers ? UI_TEXTEDITOR_LINE_NUMBER_MARGIN : 0);
2931
2932 // draw the line numbers
2933 if( mShowLineNumbers && !cur_line_is_continuation)
2934 {
2935 const LLFontGL *num_font = LLFontGL::sMonospace;
2936 F32 y_top = text_y + ((F32)llround(num_font->getLineHeight()) / 2);
2937 const LLWString ltext = utf8str_to_wstring(llformat("%*d", UI_TEXTEDITOR_LINE_NUMBER_DIGITS, cur_line_num ));
2938 BOOL is_cur_line = getCurrentLine() == cur_line_num;
2939 const U8 style = is_cur_line ? LLFontGL::BOLD : LLFontGL::NORMAL;
2940 const LLColor4 fg_color = is_cur_line ? mCursorColor : mReadOnlyFgColor;
2941 num_font->render(
2942 ltext, // string to draw
2943 0, // begin offset
2944 3., // x
2945 y_top, // y
2946 fg_color,
2947 LLFontGL::LEFT, // horizontal alignment
2948 LLFontGL::VCENTER, // vertical alignment
2949 style,
2950 S32_MAX, // max chars
2951 UI_TEXTEDITOR_LINE_NUMBER_MARGIN); // max pixels
2952 }
2911 2953
2912 S32 seg_start = line_start; 2954 S32 seg_start = line_start;
2913 while( seg_start < line_end ) 2955 while( seg_start < line_end )
@@ -2952,16 +2994,28 @@ void LLTextEditor::drawText()
2952 2994
2953 drawClippedSegment( text, seg_start, clipped_end, text_x, text_y, selection_left, selection_right, style, &text_x ); 2995 drawClippedSegment( text, seg_start, clipped_end, text_x, text_y, selection_left, selection_right, style, &text_x );
2954 2996
2997 if( text_x == text_start && mShowLineNumbers )
2998 {
2999 text_x += UI_TEXTEDITOR_LINE_NUMBER_MARGIN;
3000 }
3001
2955 // Note: text_x is incremented by drawClippedSegment() 3002 // Note: text_x is incremented by drawClippedSegment()
2956 seg_start += clipped_len; 3003 seg_start += clipped_len;
2957 } 3004 }
2958 } 3005 }
2959 3006
2960 // move down one line 3007 // move down one line
2961 text_y -= (F32)line_height; 3008 text_y -= (F32)line_height;
3009
3010 if( line_wraps )
3011 {
3012 cur_line_num--;
3013 }
3014 cur_line_is_continuation = line_wraps; // so as to not not number the continuation lines
2962 3015
2963 line_start = next_start; 3016 line_start = next_start;
2964 cur_line++; 3017 cur_line++;
3018 cur_line_num++;
2965 } 3019 }
2966} 3020}
2967 3021
@@ -3083,7 +3137,7 @@ void LLTextEditor::onTabInto()
3083// virtual 3137// virtual
3084void LLTextEditor::clear() 3138void LLTextEditor::clear()
3085{ 3139{
3086 setText(LLString::null); 3140 setText(LLStringUtil::null);
3087} 3141}
3088 3142
3089// Start or stop the editor from accepting text-editing keystrokes 3143// Start or stop the editor from accepting text-editing keystrokes
@@ -3260,8 +3314,7 @@ void LLTextEditor::setCursorAndScrollToEnd()
3260 updateScrollFromCursor(); 3314 updateScrollFromCursor();
3261} 3315}
3262 3316
3263 3317void LLTextEditor::getLineAndColumnForPosition( S32 position, S32* line, S32* col, BOOL include_wordwrap )
3264void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap )
3265{ 3318{
3266 if( include_wordwrap ) 3319 if( include_wordwrap )
3267 { 3320 {
@@ -3273,7 +3326,7 @@ void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wo
3273 S32 line_count = 0; 3326 S32 line_count = 0;
3274 S32 line_start = 0; 3327 S32 line_start = 0;
3275 S32 i; 3328 S32 i;
3276 for( i = 0; text[i] && (i < mCursorPos); i++ ) 3329 for( i = 0; text[i] && (i < position); i++ )
3277 { 3330 {
3278 if( '\n' == text[i] ) 3331 if( '\n' == text[i] )
3279 { 3332 {
@@ -3286,6 +3339,23 @@ void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wo
3286 } 3339 }
3287} 3340}
3288 3341
3342void LLTextEditor::getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap )
3343{
3344 getLineAndColumnForPosition(mCursorPos, line, col, include_wordwrap);
3345}
3346
3347S32 LLTextEditor::getCurrentLine()
3348{
3349 return getLineForPosition(mCursorPos);
3350}
3351
3352S32 LLTextEditor::getLineForPosition(S32 position)
3353{
3354 S32 line, col;
3355 getLineAndColumnForPosition(position, &line, &col, FALSE);
3356 return line;
3357}
3358
3289 3359
3290void LLTextEditor::endOfLine() 3360void LLTextEditor::endOfLine()
3291{ 3361{
@@ -3364,20 +3434,26 @@ void LLTextEditor::reshape(S32 width, S32 height, BOOL called_from_parent)
3364{ 3434{
3365 LLView::reshape( width, height, called_from_parent ); 3435 LLView::reshape( width, height, called_from_parent );
3366 3436
3367 // if scrolled to bottom, stay at bottom 3437 // do this first after reshape, because other things depend on
3368 // unless user is editing text 3438 // up-to-date mTextRect
3369 if (mScrolledToBottom && mTrackBottom && !hasFocus())
3370 {
3371 endOfDoc();
3372 }
3373
3374 updateTextRect(); 3439 updateTextRect();
3440
3441 updateLineStartList();
3442
3443 // propagate shape information to scrollbar
3444 mScrollbar->setDocSize( getLineCount() );
3375 3445
3376 S32 line_height = llround( mGLFont->getLineHeight() ); 3446 S32 line_height = llround( mGLFont->getLineHeight() );
3377 S32 page_lines = mTextRect.getHeight() / line_height; 3447 S32 page_lines = mTextRect.getHeight() / line_height;
3378 mScrollbar->setPageSize( page_lines ); 3448 mScrollbar->setPageSize( page_lines );
3379 3449
3380 updateLineStartList(); 3450 // if scrolled to bottom, stay at bottom
3451 // unless user is editing text
3452 // do this after updating page size
3453 if (mScrolledToBottom && mTrackBottom && !hasFocus())
3454 {
3455 endOfDoc();
3456 }
3381} 3457}
3382 3458
3383void LLTextEditor::autoIndent() 3459void LLTextEditor::autoIndent()
@@ -3411,7 +3487,7 @@ void LLTextEditor::autoIndent()
3411} 3487}
3412 3488
3413// Inserts new text at the cursor position 3489// Inserts new text at the cursor position
3414void LLTextEditor::insertText(const LLString &new_text) 3490void LLTextEditor::insertText(const std::string &new_text)
3415{ 3491{
3416 BOOL enabled = getEnabled(); 3492 BOOL enabled = getEnabled();
3417 setEnabled( TRUE ); 3493 setEnabled( TRUE );
@@ -3431,11 +3507,11 @@ void LLTextEditor::insertText(const LLString &new_text)
3431} 3507}
3432 3508
3433 3509
3434void LLTextEditor::appendColoredText(const LLString &new_text, 3510void LLTextEditor::appendColoredText(const std::string &new_text,
3435 bool allow_undo, 3511 bool allow_undo,
3436 bool prepend_newline, 3512 bool prepend_newline,
3437 const LLColor4 &color, 3513 const LLColor4 &color,
3438 const LLString& font_name) 3514 const std::string& font_name)
3439{ 3515{
3440 LLStyleSP style(new LLStyle); 3516 LLStyleSP style(new LLStyle);
3441 style->setVisible(true); 3517 style->setVisible(true);
@@ -3444,7 +3520,7 @@ void LLTextEditor::appendColoredText(const LLString &new_text,
3444 appendStyledText(new_text, allow_undo, prepend_newline, &style); 3520 appendStyledText(new_text, allow_undo, prepend_newline, &style);
3445} 3521}
3446 3522
3447void LLTextEditor::appendStyledText(const LLString &new_text, 3523void LLTextEditor::appendStyledText(const std::string &new_text,
3448 bool allow_undo, 3524 bool allow_undo,
3449 bool prepend_newline, 3525 bool prepend_newline,
3450 const LLStyleSP *stylep) 3526 const LLStyleSP *stylep)
@@ -3453,7 +3529,7 @@ void LLTextEditor::appendStyledText(const LLString &new_text,
3453 { 3529 {
3454 3530
3455 S32 start=0,end=0; 3531 S32 start=0,end=0;
3456 LLString text = new_text; 3532 std::string text = new_text;
3457 while ( findHTML(text, &start, &end) ) 3533 while ( findHTML(text, &start, &end) )
3458 { 3534 {
3459 LLStyleSP html(new LLStyle); 3535 LLStyleSP html(new LLStyle);
@@ -3487,7 +3563,7 @@ void LLTextEditor::appendStyledText(const LLString &new_text,
3487} 3563}
3488 3564
3489// Appends new text to end of document 3565// Appends new text to end of document
3490void LLTextEditor::appendText(const LLString &new_text, bool allow_undo, bool prepend_newline, 3566void LLTextEditor::appendText(const std::string &new_text, bool allow_undo, bool prepend_newline,
3491 const LLStyleSP *stylep) 3567 const LLStyleSP *stylep)
3492{ 3568{
3493 // Save old state 3569 // Save old state
@@ -3507,7 +3583,7 @@ void LLTextEditor::appendText(const LLString &new_text, bool allow_undo, bool pr
3507 if (getLength() != 0 3583 if (getLength() != 0
3508 && prepend_newline) 3584 && prepend_newline)
3509 { 3585 {
3510 LLString final_text = "\n"; 3586 std::string final_text = "\n";
3511 final_text += new_text; 3587 final_text += new_text;
3512 append(utf8str_to_wstring(final_text), TRUE); 3588 append(utf8str_to_wstring(final_text), TRUE);
3513 } 3589 }
@@ -3543,6 +3619,10 @@ void LLTextEditor::appendText(const LLString &new_text, bool allow_undo, bool pr
3543 { 3619 {
3544 mSelectionStart = selection_start; 3620 mSelectionStart = selection_start;
3545 mSelectionEnd = selection_end; 3621 mSelectionEnd = selection_end;
3622
3623
3624
3625
3546 mIsSelecting = was_selecting; 3626 mIsSelecting = was_selecting;
3547 setCursorPos(cursor_pos); 3627 setCursorPos(cursor_pos);
3548 } 3628 }
@@ -3559,6 +3639,14 @@ void LLTextEditor::appendText(const LLString &new_text, bool allow_undo, bool pr
3559 { 3639 {
3560 blockUndo(); 3640 blockUndo();
3561 } 3641 }
3642
3643 // if scrolled to bottom, stay at bottom
3644 // unless user is editing text
3645 // do this after updating page size
3646 if (mScrolledToBottom && mTrackBottom && !hasFocus())
3647 {
3648 endOfDoc();
3649 }
3562} 3650}
3563 3651
3564void LLTextEditor::removeTextFromEnd(S32 num_chars) 3652void LLTextEditor::removeTextFromEnd(S32 num_chars)
@@ -3688,20 +3776,18 @@ void LLTextEditor::updateTextRect()
3688 getRect().getHeight() - 2 * UI_TEXTEDITOR_BORDER - UI_TEXTEDITOR_V_PAD_TOP ); 3776 getRect().getHeight() - 2 * UI_TEXTEDITOR_BORDER - UI_TEXTEDITOR_V_PAD_TOP );
3689} 3777}
3690 3778
3691void LLTextEditor::loadKeywords(const LLString& filename, 3779void LLTextEditor::loadKeywords(const std::string& filename,
3692 const LLDynamicArray<const char*>& funcs, 3780 const std::vector<std::string>& funcs,
3693 const LLDynamicArray<const char*>& tooltips, 3781 const std::vector<std::string>& tooltips,
3694 const LLColor3& color) 3782 const LLColor3& color)
3695{ 3783{
3696 if(mKeywords.loadFromFile(filename)) 3784 if(mKeywords.loadFromFile(filename))
3697 { 3785 {
3698 S32 count = funcs.count(); 3786 S32 count = llmin(funcs.size(), tooltips.size());
3699 LLString name;
3700 for(S32 i = 0; i < count; i++) 3787 for(S32 i = 0; i < count; i++)
3701 { 3788 {
3702 name = funcs.get(i); 3789 std::string name = utf8str_trim(funcs[i]);
3703 name = utf8str_trim(name); 3790 mKeywords.addToken(LLKeywordToken::WORD, name, color, tooltips[i] );
3704 mKeywords.addToken(LLKeywordToken::WORD, name.c_str(), color, tooltips.get(i) );
3705 } 3791 }
3706 3792
3707 mKeywords.findSegments( &mSegments, mWText, mDefaultColor ); 3793 mKeywords.findSegments( &mSegments, mWText, mDefaultColor );
@@ -3843,9 +3929,9 @@ BOOL LLTextEditor::handleMouseUpOverSegment(S32 x, S32 y, MASK mask)
3843 //Special handling for slurls 3929 //Special handling for slurls
3844 if ( (mSecondlifeURLcallback!=NULL) && !(*mSecondlifeURLcallback)(mHTML) ) 3930 if ( (mSecondlifeURLcallback!=NULL) && !(*mSecondlifeURLcallback)(mHTML) )
3845 { 3931 {
3846 if (mURLcallback!=NULL) (*mURLcallback)(mHTML.c_str()); 3932 if (mURLcallback!=NULL) (*mURLcallback)(mHTML);
3847 } 3933 }
3848 mHTML=""; 3934 mHTML.clear();
3849 } 3935 }
3850 } 3936 }
3851 3937
@@ -3897,7 +3983,7 @@ void LLTextEditor::setOnScrollEndCallback(void (*callback)(void*), void* userdat
3897/////////////////////////////////////////////////////////////////// 3983///////////////////////////////////////////////////////////////////
3898// Hack for Notecards 3984// Hack for Notecards
3899 3985
3900BOOL LLTextEditor::importBuffer(const LLString& buffer ) 3986BOOL LLTextEditor::importBuffer(const char* buffer, S32 length )
3901{ 3987{
3902 std::istringstream instream(buffer); 3988 std::istringstream instream(buffer);
3903 3989
@@ -3986,7 +4072,7 @@ BOOL LLTextEditor::importBuffer(const LLString& buffer )
3986 return success; 4072 return success;
3987} 4073}
3988 4074
3989BOOL LLTextEditor::exportBuffer(LLString &buffer ) 4075BOOL LLTextEditor::exportBuffer(std::string &buffer )
3990{ 4076{
3991 std::ostringstream outstream(buffer); 4077 std::ostringstream outstream(buffer);
3992 4078
@@ -4003,7 +4089,11 @@ BOOL LLTextEditor::exportBuffer(LLString &buffer )
4003////////////////////////////////////////////////////////////////////////// 4089//////////////////////////////////////////////////////////////////////////
4004// LLTextSegment 4090// LLTextSegment
4005 4091
4006LLTextSegment::LLTextSegment(S32 start) : mStart(start) 4092LLTextSegment::LLTextSegment(S32 start) :
4093 mStart(start),
4094 mEnd(0),
4095 mToken(NULL),
4096 mIsDefault(FALSE)
4007{ 4097{
4008} 4098}
4009LLTextSegment::LLTextSegment( const LLStyleSP& style, S32 start, S32 end ) : 4099LLTextSegment::LLTextSegment( const LLStyleSP& style, S32 start, S32 end ) :
@@ -4015,7 +4105,7 @@ LLTextSegment::LLTextSegment( const LLStyleSP& style, S32 start, S32 end ) :
4015{ 4105{
4016} 4106}
4017LLTextSegment::LLTextSegment( const LLColor4& color, S32 start, S32 end, BOOL is_visible) : 4107LLTextSegment::LLTextSegment( const LLColor4& color, S32 start, S32 end, BOOL is_visible) :
4018 mStyle(new LLStyle(is_visible,color,"")), 4108 mStyle(new LLStyle(is_visible,color,LLStringUtil::null)),
4019 mStart( start), 4109 mStart( start),
4020 mEnd( end ), 4110 mEnd( end ),
4021 mToken(NULL), 4111 mToken(NULL),
@@ -4023,7 +4113,7 @@ LLTextSegment::LLTextSegment( const LLColor4& color, S32 start, S32 end, BOOL is
4023{ 4113{
4024} 4114}
4025LLTextSegment::LLTextSegment( const LLColor4& color, S32 start, S32 end ) : 4115LLTextSegment::LLTextSegment( const LLColor4& color, S32 start, S32 end ) :
4026 mStyle(new LLStyle(TRUE, color,"" )), 4116 mStyle(new LLStyle(TRUE, color,LLStringUtil::null )),
4027 mStart( start), 4117 mStart( start),
4028 mEnd( end ), 4118 mEnd( end ),
4029 mToken(NULL), 4119 mToken(NULL),
@@ -4031,7 +4121,7 @@ LLTextSegment::LLTextSegment( const LLColor4& color, S32 start, S32 end ) :
4031{ 4121{
4032} 4122}
4033LLTextSegment::LLTextSegment( const LLColor3& color, S32 start, S32 end ) : 4123LLTextSegment::LLTextSegment( const LLColor3& color, S32 start, S32 end ) :
4034 mStyle(new LLStyle(TRUE, color,"" )), 4124 mStyle(new LLStyle(TRUE, color,LLStringUtil::null )),
4035 mStart( start), 4125 mStart( start),
4036 mEnd( end ), 4126 mEnd( end ),
4037 mToken(NULL), 4127 mToken(NULL),
@@ -4039,7 +4129,7 @@ LLTextSegment::LLTextSegment( const LLColor3& color, S32 start, S32 end ) :
4039{ 4129{
4040} 4130}
4041 4131
4042BOOL LLTextSegment::getToolTip(LLString& msg) const 4132BOOL LLTextSegment::getToolTip(std::string& msg) const
4043{ 4133{
4044 if (mToken && !mToken->getToolTip().empty()) 4134 if (mToken && !mToken->getToolTip().empty())
4045 { 4135 {
@@ -4094,7 +4184,7 @@ LLXMLNodePtr LLTextEditor::getXML(bool save_children) const
4094// static 4184// static
4095LLView* LLTextEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) 4185LLView* LLTextEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
4096{ 4186{
4097 LLString name("text_editor"); 4187 std::string name("text_editor");
4098 node->getAttributeString("name", name); 4188 node->getAttributeString("name", name);
4099 4189
4100 LLRect rect; 4190 LLRect rect;
@@ -4108,7 +4198,7 @@ LLView* LLTextEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory
4108 4198
4109 LLFontGL* font = LLView::selectFont(node); 4199 LLFontGL* font = LLView::selectFont(node);
4110 4200
4111 LLString text = node->getTextContents().substr(0, max_text_length - 1); 4201 std::string text = node->getTextContents().substr(0, max_text_length - 1);
4112 4202
4113 LLTextEditor* text_editor = new LLTextEditor(name, 4203 LLTextEditor* text_editor = new LLTextEditor(name,
4114 rect, 4204 rect,
@@ -4134,6 +4224,8 @@ void LLTextEditor::setTextEditorParameters(LLXMLNodePtr node)
4134 node->getAttributeBOOL("word_wrap", word_wrap); 4224 node->getAttributeBOOL("word_wrap", word_wrap);
4135 setWordWrap(word_wrap); 4225 setWordWrap(word_wrap);
4136 4226
4227 node->getAttributeBOOL("show_line_numbers", mShowLineNumbers);
4228
4137 node->getAttributeBOOL("track_bottom", mTrackBottom); 4229 node->getAttributeBOOL("track_bottom", mTrackBottom);
4138 4230
4139 LLColor4 color; 4231 LLColor4 color;
@@ -4160,26 +4252,29 @@ void LLTextEditor::setTextEditorParameters(LLXMLNodePtr node)
4160} 4252}
4161 4253
4162/////////////////////////////////////////////////////////////////// 4254///////////////////////////////////////////////////////////////////
4163S32 LLTextEditor::findHTMLToken(const LLString &line, S32 pos, BOOL reverse) const 4255// Refactoring note: We may eventually want to replace this with boost::regex or
4256// boost::tokenizer capabilities since we've already fixed at least two JIRAs
4257// concerning logic issues associated with this function.
4258S32 LLTextEditor::findHTMLToken(const std::string &line, S32 pos, BOOL reverse) const
4164{ 4259{
4165 LLString openers=" \t('\"[{<>"; 4260 std::string openers=" \t\n('\"[{<>";
4166 LLString closers=" \t)'\"]}><;"; 4261 std::string closers=" \t\n)'\"]}><;";
4167 4262
4168 S32 m2; 4263 S32 m2 = 0;
4169 S32 retval; 4264 S32 retval = 0;
4170 4265
4171 if (reverse) 4266 if (reverse)
4172 { 4267 {
4173 4268
4174 for (retval=pos; retval>0; retval--) 4269 for (retval=pos; retval >= 0; retval--)
4175 { 4270 {
4176 m2 = openers.find(line.substr(retval,1)); 4271 m2 = openers.find(line.substr(retval,1));
4177 if (m2 >= 0) 4272 if (m2 >= 0)
4178 { 4273 {
4179 retval++;
4180 break; 4274 break;
4181 } 4275 }
4182 } 4276 }
4277 return retval+1;
4183 } 4278 }
4184 else 4279 else
4185 { 4280 {
@@ -4192,12 +4287,11 @@ S32 LLTextEditor::findHTMLToken(const LLString &line, S32 pos, BOOL reverse) con
4192 break; 4287 break;
4193 } 4288 }
4194 } 4289 }
4195 } 4290 return retval;
4196 4291 }
4197 return retval;
4198} 4292}
4199 4293
4200BOOL LLTextEditor::findHTML(const LLString &line, S32 *begin, S32 *end) const 4294BOOL LLTextEditor::findHTML(const std::string &line, S32 *begin, S32 *end) const
4201{ 4295{
4202 4296
4203 S32 m1,m2,m3; 4297 S32 m1,m2,m3;
@@ -4214,7 +4308,7 @@ BOOL LLTextEditor::findHTML(const LLString &line, S32 *begin, S32 *end) const
4214 m2 = line.substr(*begin,(m1 - *begin)).find("http"); 4308 m2 = line.substr(*begin,(m1 - *begin)).find("http");
4215 m3 = line.substr(*begin,(m1 - *begin)).find("secondlife"); 4309 m3 = line.substr(*begin,(m1 - *begin)).find("secondlife");
4216 4310
4217 LLString badneighbors=".,<>?';\"][}{=-+_)(*&^%$#@!~`\t\r\n\\"; 4311 std::string badneighbors=".,<>?';\"][}{=-+_)(*&^%$#@!~`\t\r\n\\";
4218 4312
4219 if (m2 >= 0 || m3>=0) 4313 if (m2 >= 0 || m3>=0)
4220 { 4314 {
@@ -4240,7 +4334,7 @@ BOOL LLTextEditor::findHTML(const LLString &line, S32 *begin, S32 *end) const
4240 4334
4241 if ( ( *end - m1 ) > 2 && m1 > *begin) 4335 if ( ( *end - m1 ) > 2 && m1 > *begin)
4242 { 4336 {
4243 LLString badneighbors=".,<>/?';\"][}{=-+_)(*&^%$#@!~`"; 4337 std::string badneighbors=".,<>/?';\"][}{=-+_)(*&^%$#@!~`";
4244 m2 = badneighbors.find(line.substr(m1+1,1)); 4338 m2 = badneighbors.find(line.substr(m1+1,1));
4245 m3 = badneighbors.find(line.substr(m1-1,1)); 4339 m3 = badneighbors.find(line.substr(m1-1,1));
4246 if (m3<0 && m2<0) 4340 if (m3<0 && m2<0)
@@ -4256,8 +4350,8 @@ BOOL LLTextEditor::findHTML(const LLString &line, S32 *begin, S32 *end) const
4256 { 4350 {
4257 S32 strpos, strpos2; 4351 S32 strpos, strpos2;
4258 4352
4259 LLString url = line.substr(*begin,*end - *begin); 4353 std::string url = line.substr(*begin,*end - *begin);
4260 LLString slurlID = "slurl.com/secondlife/"; 4354 std::string slurlID = "slurl.com/secondlife/";
4261 strpos = url.find(slurlID); 4355 strpos = url.find(slurlID);
4262 4356
4263 if (strpos < 0) 4357 if (strpos < 0)