00001
00032
00033
00034 #ifndef LL_LLTEXTEDITOR_H
00035 #define LL_LLTEXTEDITOR_H
00036
00037 #include "llrect.h"
00038 #include "llkeywords.h"
00039 #include "lluictrl.h"
00040 #include "llframetimer.h"
00041 #include "lldarray.h"
00042 #include "llstyle.h"
00043 #include "lleditmenuhandler.h"
00044 #include "lldarray.h"
00045
00046 #include "llpreeditor.h"
00047
00048 class LLFontGL;
00049 class LLScrollbar;
00050 class LLViewBorder;
00051 class LLKeywordToken;
00052 class LLTextCmd;
00053 class LLUICtrlFactory;
00054
00055 class LLTextEditor : public LLUICtrl, LLEditMenuHandler, protected LLPreeditor
00056 {
00057 public:
00058
00059
00060
00061 static const llwchar FIRST_EMBEDDED_CHAR = 0x100000;
00062 static const llwchar LAST_EMBEDDED_CHAR = 0x10ffff;
00063 static const S32 MAX_EMBEDDED_ITEMS = LAST_EMBEDDED_CHAR - FIRST_EMBEDDED_CHAR + 1;
00064
00065 LLTextEditor(const LLString& name,
00066 const LLRect& rect,
00067 S32 max_length,
00068 const LLString &default_text,
00069 const LLFontGL* glfont = NULL,
00070 BOOL allow_embedded_items = FALSE);
00071
00072 virtual ~LLTextEditor();
00073
00074 virtual LLXMLNodePtr getXML(bool save_children = true) const;
00075 static LLView* fromXML(LLXMLNodePtr node, LLView *parent, class LLUICtrlFactory *factory);
00076 void setTextEditorParameters(LLXMLNodePtr node);
00077 void setParseHTML(BOOL parsing) {mParseHTML=parsing;}
00078
00079
00080 virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask);
00081 virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask);
00082 virtual BOOL handleHover(S32 x, S32 y, MASK mask);
00083 virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks);
00084 virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask );
00085 virtual BOOL handleKeyHere(KEY key, MASK mask );
00086 virtual BOOL handleUnicodeCharHere(llwchar uni_char);
00087
00088 virtual BOOL handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect);
00089 virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
00090 EDragAndDropType cargo_type, void *cargo_data,
00091 EAcceptance *accept, LLString& tooltip_msg);
00092 virtual void onMouseCaptureLost();
00093
00094
00095 virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
00096 virtual void draw();
00097 virtual void onFocusReceived();
00098 virtual void onFocusLost();
00099 virtual void setEnabled(BOOL enabled);
00100
00101
00102 virtual void onTabInto();
00103 virtual void clear();
00104 virtual void setFocus( BOOL b );
00105 virtual BOOL acceptsTextInput() const;
00106 virtual BOOL isDirty() const { return( mLastCmd != NULL || (mPristineCmd && (mPristineCmd != mLastCmd)) ); }
00107
00108
00109 virtual void undo();
00110 virtual BOOL canUndo() const;
00111 virtual void redo();
00112 virtual BOOL canRedo() const;
00113 virtual void cut();
00114 virtual BOOL canCut() const;
00115 virtual void copy();
00116 virtual BOOL canCopy() const;
00117 virtual void paste();
00118 virtual BOOL canPaste() const;
00119 virtual void doDelete();
00120 virtual BOOL canDoDelete() const;
00121 virtual void selectAll();
00122 virtual BOOL canSelectAll() const;
00123 virtual void deselect();
00124 virtual BOOL canDeselect() const;
00125
00126 void selectNext(const LLString& search_text_in, BOOL case_insensitive, BOOL wrap = TRUE);
00127 BOOL replaceText(const LLString& search_text, const LLString& replace_text, BOOL case_insensitive, BOOL wrap = TRUE);
00128 void replaceTextAll(const LLString& search_text, const LLString& replace_text, BOOL case_insensitive);
00129
00130
00131 void blockUndo();
00132
00133
00134 virtual void makePristine();
00135 BOOL isPristine() const;
00136 BOOL allowsEmbeddedItems() const { return mAllowEmbeddedItems; }
00137
00138
00139 void insertText(const LLString &text);
00140
00141 void appendText(const LLString &wtext, bool allow_undo, bool prepend_newline,
00142 const LLStyleSP *stylep = NULL);
00143
00144 void appendColoredText(const LLString &wtext, bool allow_undo,
00145 bool prepend_newline,
00146 const LLColor4 &color,
00147 const LLString& font_name = LLString::null);
00148
00149 void appendStyledText(const LLString &new_text, bool allow_undo,
00150 bool prepend_newline,
00151 const LLStyleSP *stylep = NULL);
00152
00153
00154
00155 void removeTextFromEnd(S32 num_chars);
00156
00157 BOOL tryToRevertToPristineState();
00158
00159 void setCursor(S32 row, S32 column);
00160 void setCursorPos(S32 offset);
00161 void setCursorAndScrollToEnd();
00162
00163 void getCurrentLineAndColumn( S32* line, S32* col, BOOL include_wordwrap );
00164
00165
00166 void loadKeywords(const LLString& filename,
00167 const LLDynamicArray<const char*>& funcs,
00168 const LLDynamicArray<const char*>& tooltips,
00169 const LLColor3& func_color);
00170 LLKeywords::keyword_iterator_t keywordsBegin() { return mKeywords.begin(); }
00171 LLKeywords::keyword_iterator_t keywordsEnd() { return mKeywords.end(); }
00172
00173
00174 void setCursorColor(const LLColor4& c) { mCursorColor = c; }
00175 void setFgColor( const LLColor4& c ) { mFgColor = c; }
00176 void setTextDefaultColor( const LLColor4& c ) { mDefaultColor = c; }
00177 void setReadOnlyFgColor( const LLColor4& c ) { mReadOnlyFgColor = c; }
00178 void setWriteableBgColor( const LLColor4& c ) { mWriteableBgColor = c; }
00179 void setReadOnlyBgColor( const LLColor4& c ) { mReadOnlyBgColor = c; }
00180 void setTrackColor( const LLColor4& color );
00181 void setThumbColor( const LLColor4& color );
00182 void setHighlightColor( const LLColor4& color );
00183 void setShadowColor( const LLColor4& color );
00184
00185
00186
00187 void setBorderVisible(BOOL b);
00188 BOOL isBorderVisible() const;
00189 void setTakesNonScrollClicks(BOOL b) { mTakesNonScrollClicks = b; }
00190 void setHideScrollbarForShortDocs(BOOL b);
00191
00192 void setWordWrap( BOOL b );
00193 void setTabsToNextField(BOOL b) { mTabsToNextField = b; }
00194 BOOL tabsToNextField() const { return mTabsToNextField; }
00195 void setCommitOnFocusLost(BOOL b) { mCommitOnFocusLost = b; }
00196
00197
00198 virtual BOOL importBuffer(const LLString& buffer );
00199 virtual BOOL exportBuffer(LLString& buffer );
00200
00201
00202 void setTakesFocus(BOOL b) { mTakesFocus = b; }
00203
00204 void setSourceID(const LLUUID& id) { mSourceID = id; }
00205 const LLUUID& getSourceID() const { return mSourceID; }
00206 void setAcceptCallingCardNames(BOOL enable) { mAcceptCallingCardNames = enable; }
00207 BOOL acceptsCallingCardNames() const { return mAcceptCallingCardNames; }
00208
00209 void setHandleEditKeysDirectly( BOOL b ) { mHandleEditKeysDirectly = b; }
00210
00211
00212 static void setLinkColor(LLColor4 color) { mLinkColor = color; }
00213 static void setURLCallbacks(void (*callback1) (const char* url),
00214 bool (*callback2) (const std::string& url),
00215 bool (*callback3) (const std::string& url) )
00216 { mURLcallback = callback1; mSecondlifeURLcallback = callback2; mSecondlifeURLcallbackRightClick = callback3;}
00217
00218 void setOnScrollEndCallback(void (*callback)(void*), void* userdata);
00219
00220
00221 void setValue(const LLSD& value);
00222 LLSD getValue() const;
00223
00224 const LLString& getText() const;
00225
00226
00227 void setText(const LLStringExplicit &utf8str);
00228 void setWText(const LLWString &wtext);
00229
00230
00231 S32 getMaxLength() const { return mMaxTextByteLength; }
00232
00233
00234 void startOfLine();
00235 void endOfLine();
00236 void endOfDoc();
00237
00238 BOOL isScrolledToTop();
00239 BOOL isScrolledToBottom();
00240
00241
00242 const LLWString& getWText() const { return mWText; }
00243 llwchar getWChar(S32 pos) const { return mWText[pos]; }
00244 LLWString getWSubString(S32 pos, S32 len) const { return mWText.substr(pos, len); }
00245
00246 const LLTextSegment* getCurrentSegment() { return getSegmentAtOffset(mCursorPos); }
00247 const LLTextSegment* getPreviousSegment();
00248 void getSelectedSegments(std::vector<const LLTextSegment*>& segments);
00249
00250 protected:
00251
00252
00253
00254
00255 S32 getLength() const { return mWText.length(); }
00256 void getSegmentAndOffset( S32 startpos, S32* segidxp, S32* offsetp ) const;
00257 void drawPreeditMarker();
00258
00259 void updateLineStartList(S32 startpos = 0);
00260 void updateScrollFromCursor();
00261 void updateTextRect();
00262 const LLRect& getTextRect() const { return mTextRect; }
00263
00264 void assignEmbedded(const LLString &s);
00265 BOOL truncate();
00266
00267 static BOOL isPartOfWord(llwchar c) { return (c == '_') || isalnum(c); }
00268
00269 void removeCharOrTab();
00270 void setCursorAtLocalPos(S32 x, S32 y, BOOL round);
00271 S32 getCursorPosFromLocalCoord( S32 local_x, S32 local_y, BOOL round ) const;
00272
00273 void indentSelectedLines( S32 spaces );
00274 S32 indentLine( S32 pos, S32 spaces );
00275 void unindentLineBeforeCloseBrace();
00276
00277 S32 getSegmentIdxAtOffset(S32 offset) const;
00278 const LLTextSegment* getSegmentAtLocalPos(S32 x, S32 y) const;
00279 const LLTextSegment* getSegmentAtOffset(S32 offset) const;
00280
00281 void reportBadKeystroke() { make_ui_sound("UISndBadKeystroke"); }
00282
00283 BOOL handleNavigationKey(const KEY key, const MASK mask);
00284 BOOL handleSpecialKey(const KEY key, const MASK mask, BOOL* return_key_hit);
00285 BOOL handleSelectionKey(const KEY key, const MASK mask);
00286 BOOL handleControlKey(const KEY key, const MASK mask);
00287 BOOL handleEditKey(const KEY key, const MASK mask);
00288
00289 BOOL hasSelection() const { return (mSelectionStart !=mSelectionEnd); }
00290 BOOL selectionContainsLineBreaks();
00291 void startSelection();
00292 void endSelection();
00293 void deleteSelection(BOOL transient_operation);
00294
00295 S32 prevWordPos(S32 cursorPos) const;
00296 S32 nextWordPos(S32 cursorPos) const;
00297
00298 S32 getLineCount() const { return mLineStartList.size(); }
00299 S32 getLineStart( S32 line ) const;
00300 void getLineAndOffset(S32 pos, S32* linep, S32* offsetp) const;
00301 S32 getPos(S32 line, S32 offset);
00302
00303 void changePage(S32 delta);
00304 void changeLine(S32 delta);
00305
00306 void autoIndent();
00307
00308 void findEmbeddedItemSegments();
00309
00310 virtual BOOL handleMouseUpOverSegment(S32 x, S32 y, MASK mask);
00311
00312 virtual llwchar pasteEmbeddedItem(llwchar ext_char) { return ext_char; }
00313 virtual void bindEmbeddedChars(LLFontGL* font) const {}
00314 virtual void unbindEmbeddedChars(LLFontGL* font) const {}
00315
00316 S32 findHTMLToken(const LLString &line, S32 pos, BOOL reverse) const;
00317 BOOL findHTML(const LLString &line, S32 *begin, S32 *end) const;
00318
00319
00320
00321
00322 class LLTextCmd
00323 {
00324 public:
00325 LLTextCmd( S32 pos, BOOL group_with_next ) : mPos(pos), mGroupWithNext(group_with_next) {}
00326 virtual ~LLTextCmd() {}
00327 virtual BOOL execute(LLTextEditor* editor, S32* delta) = 0;
00328 virtual S32 undo(LLTextEditor* editor) = 0;
00329 virtual S32 redo(LLTextEditor* editor) = 0;
00330 virtual BOOL canExtend(S32 pos) const { return FALSE; }
00331 virtual void blockExtensions() {}
00332 virtual BOOL extendAndExecute( LLTextEditor* editor, S32 pos, llwchar c, S32* delta ) { llassert(0); return 0; }
00333 virtual BOOL hasExtCharValue( llwchar value ) const { return FALSE; }
00334
00335
00336 S32 insert(LLTextEditor* editor, S32 pos, const LLWString &wstr) { return editor->insertStringNoUndo( pos, wstr ); }
00337 S32 remove(LLTextEditor* editor, S32 pos, S32 length) { return editor->removeStringNoUndo( pos, length ); }
00338 S32 overwrite(LLTextEditor* editor, S32 pos, llwchar wc) { return editor->overwriteCharNoUndo(pos, wc); }
00339
00340 S32 getPosition() const { return mPos; }
00341 BOOL groupWithNext() const { return mGroupWithNext; }
00342
00343 private:
00344 const S32 mPos;
00345 BOOL mGroupWithNext;
00346 };
00347
00348 S32 execute(LLTextCmd* cmd);
00349
00350
00351 void addChar(llwchar c);
00352 S32 addChar(S32 pos, llwchar wc);
00353 S32 overwriteChar(S32 pos, llwchar wc);
00354 void removeChar();
00355 S32 removeChar(S32 pos);
00356 S32 insert(const S32 pos, const LLWString &wstr, const BOOL group_with_next_op);
00357 S32 remove(const S32 pos, const S32 length, const BOOL group_with_next_op);
00358 S32 append(const LLWString &wstr, const BOOL group_with_next_op);
00359
00360
00361 S32 insertStringNoUndo(S32 pos, const LLWString &wstr);
00362 S32 removeStringNoUndo(S32 pos, S32 length);
00363 S32 overwriteCharNoUndo(S32 pos, llwchar wc);
00364
00365 void resetKeystrokeTimer() { mKeystrokeTimer.reset(); }
00366
00367 void updateAllowingLanguageInput();
00368 BOOL hasPreeditString() const;
00369
00370
00371 virtual void resetPreedit();
00372 virtual void updatePreedit(const LLWString &preedit_string,
00373 const segment_lengths_t &preedit_segment_lengths, const standouts_t &preedit_standouts, S32 caret_position);
00374 virtual void markAsPreedit(S32 position, S32 length);
00375 virtual void getPreeditRange(S32 *position, S32 *length) const;
00376 virtual void getSelectionRange(S32 *position, S32 *length) const;
00377 virtual BOOL getPreeditLocation(S32 query_offset, LLCoordGL *coord, LLRect *bounds, LLRect *control) const;
00378 virtual S32 getPreeditFontSize() const;
00379
00380
00381
00382
00383
00384
00385
00386
00387 S32 mCursorPos;
00388
00389
00390 S32 mMouseDownX;
00391 S32 mMouseDownY;
00392
00393
00394
00395 BOOL mIsSelecting;
00396 S32 mSelectionStart;
00397 S32 mSelectionEnd;
00398 S32 mLastSelectionX;
00399 S32 mLastSelectionY;
00400
00401 BOOL mParseHTML;
00402 LLString mHTML;
00403
00404 typedef std::vector<LLTextSegment *> segment_list_t;
00405 segment_list_t mSegments;
00406 const LLTextSegment* mHoverSegment;
00407
00408
00409 class LLScrollbar* mScrollbar;
00410 BOOL mHideScrollbarForShortDocs;
00411 BOOL mTakesNonScrollClicks;
00412 void (*mOnScrollEndCallback)(void*);
00413 void *mOnScrollEndData;
00414
00415 LLWString mPreeditWString;
00416 LLWString mPreeditOverwrittenWString;
00417 std::vector<S32> mPreeditPositions;
00418 std::vector<BOOL> mPreeditStandouts;
00419
00420 private:
00421
00422
00423
00424
00425 void updateSegments();
00426 void pruneSegments();
00427
00428 void drawBackground();
00429 void drawSelectionBackground();
00430 void drawCursor();
00431 void drawText();
00432 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);
00433
00434
00435
00436
00437 LLKeywords mKeywords;
00438 static LLColor4 mLinkColor;
00439 static void (*mURLcallback) (const char* url);
00440 static bool (*mSecondlifeURLcallback) (const std::string& url);
00441 static bool (*mSecondlifeURLcallbackRightClick) (const std::string& url);
00442
00443
00444 class LLTextCmdInsert;
00445 class LLTextCmdAddChar;
00446 class LLTextCmdOverwriteChar;
00447 class LLTextCmdRemove;
00448
00449 LLWString mWText;
00450 mutable LLString mUTF8Text;
00451 mutable BOOL mTextIsUpToDate;
00452
00453 S32 mMaxTextByteLength;
00454
00455 const LLFontGL* mGLFont;
00456
00457 class LLViewBorder* mBorder;
00458
00459 BOOL mBaseDocIsPristine;
00460 LLTextCmd* mPristineCmd;
00461
00462 LLTextCmd* mLastCmd;
00463
00464 typedef std::deque<LLTextCmd*> undo_stack_t;
00465 undo_stack_t mUndoStack;
00466
00467 S32 mDesiredXPixel;
00468 LLRect mTextRect;
00469
00470 struct line_info
00471 {
00472 line_info(S32 segment, S32 offset) : mSegment(segment), mOffset(offset) {}
00473 S32 mSegment;
00474 S32 mOffset;
00475 };
00476 struct line_info_compare
00477 {
00478 bool operator()(const line_info& a, const line_info& b) const
00479 {
00480 if (a.mSegment < b.mSegment)
00481 return true;
00482 else if (a.mSegment > b.mSegment)
00483 return false;
00484 else
00485 return a.mOffset < b.mOffset;
00486 }
00487 };
00488 typedef std::vector<line_info> line_list_t;
00489 line_list_t mLineStartList;
00490
00491 LLFrameTimer mKeystrokeTimer;
00492
00493 LLColor4 mCursorColor;
00494
00495 LLColor4 mFgColor;
00496 LLColor4 mDefaultColor;
00497 LLColor4 mReadOnlyFgColor;
00498 LLColor4 mWriteableBgColor;
00499 LLColor4 mReadOnlyBgColor;
00500 LLColor4 mFocusBgColor;
00501
00502 BOOL mReadOnly;
00503 BOOL mWordWrap;
00504
00505 BOOL mTabsToNextField;
00506 BOOL mCommitOnFocusLost;
00507 BOOL mTakesFocus;
00508 BOOL mTrackBottom;
00509 BOOL mScrolledToBottom;
00510
00511 BOOL mAllowEmbeddedItems;
00512
00513 BOOL mAcceptCallingCardNames;
00514
00515 LLUUID mSourceID;
00516
00517
00518
00519 BOOL mHandleEditKeysDirectly;
00520
00521 LLCoordGL mLastIMEPosition;
00522 };
00523
00524
00525
00526 class LLTextSegment
00527 {
00528 public:
00529
00530 LLTextSegment(S32 start);
00531 LLTextSegment( const LLStyleSP& style, S32 start, S32 end );
00532 LLTextSegment( const LLColor4& color, S32 start, S32 end, BOOL is_visible);
00533 LLTextSegment( const LLColor4& color, S32 start, S32 end );
00534 LLTextSegment( const LLColor3& color, S32 start, S32 end );
00535
00536 S32 getStart() const { return mStart; }
00537 S32 getEnd() const { return mEnd; }
00538 void setEnd( S32 end ) { mEnd = end; }
00539 const LLColor4& getColor() const { return mStyle->getColor(); }
00540 void setColor(const LLColor4 &color) { mStyle->setColor(color); }
00541 const LLStyleSP& getStyle() const { return mStyle; }
00542 void setStyle(const LLStyleSP &style) { mStyle = style; }
00543 void setIsDefault(BOOL b) { mIsDefault = b; }
00544 BOOL getIsDefault() const { return mIsDefault; }
00545 void setToken( LLKeywordToken* token ) { mToken = token; }
00546 LLKeywordToken* getToken() const { return mToken; }
00547 BOOL getToolTip( LLString& msg ) const;
00548
00549 void dump() const;
00550
00551 struct compare
00552 {
00553 bool operator()(const LLTextSegment* a, const LLTextSegment* b) const
00554 {
00555 return a->mStart < b->mStart;
00556 }
00557 };
00558
00559 private:
00560 LLStyleSP mStyle;
00561 S32 mStart;
00562 S32 mEnd;
00563 LLKeywordToken* mToken;
00564 BOOL mIsDefault;
00565 };
00566
00567
00568 #endif // LL_TEXTEDITOR_