00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llfocusmgr.h"
00035 #include "audioengine.h"
00036 #include "llagent.h"
00037 #include "llinventory.h"
00038 #include "llinventorymodel.h"
00039 #include "llinventoryview.h"
00040 #include "llinventorybridge.h"
00041
00042 #include "llviewertexteditor.h"
00043
00044 #include "llfloaterchat.h"
00045 #include "llfloaterworldmap.h"
00046 #include "llnotify.h"
00047 #include "llpreview.h"
00048 #include "llpreviewtexture.h"
00049 #include "llpreviewnotecard.h"
00050 #include "llpreviewlandmark.h"
00051 #include "llscrollbar.h"
00052 #include "lltooldraganddrop.h"
00053 #include "llviewercontrol.h"
00054 #include "llviewerimagelist.h"
00055 #include "llviewerwindow.h"
00056 #include "llviewerinventory.h"
00057 #include "lluictrlfactory.h"
00058 #include "llnotecard.h"
00059 #include "llmemorystream.h"
00060 #include "llmenugl.h"
00061
00062 #include "llappviewer.h"
00063
00064 static LLRegisterWidget<LLViewerTextEditor> r("text_editor");
00065
00069 class LLEmbeddedNotecardOpener : public LLInventoryCallback
00070 {
00071 LLViewerTextEditor* mTextEditor;
00072
00073 public:
00074 LLEmbeddedNotecardOpener()
00075 : mTextEditor(NULL)
00076 {
00077 }
00078
00079 void setEditor(LLViewerTextEditor* e) {mTextEditor = e;}
00080
00081
00082 void fire(const LLUUID& inv_item)
00083 {
00084 if(!mTextEditor)
00085 {
00086
00087
00088 return;
00089 }
00090
00091 LLInventoryItem* item = gInventory.getItem(inv_item);
00092 if(!item)
00093 {
00094 llwarns << "Item add reported, but not found in inventory!: " << inv_item << llendl;
00095 }
00096 else
00097 {
00098
00099 if(!LLPreview::show(item->getUUID(), true))
00100 {
00101 if(!gSavedSettings.getBOOL("ShowNewInventory"))
00102 {
00103
00104 S32 left, top;
00105 gFloaterView->getNewFloaterPosition(&left, &top);
00106 LLRect rect = gSavedSettings.getRect("NotecardEditorRect");
00107 rect.translate(left - rect.mLeft, top - rect.mTop);
00108 LLPreviewNotecard* preview;
00109 preview = new LLPreviewNotecard("preview notecard",
00110 rect,
00111 LLString("Embedded Note: ") + item->getName(),
00112 item->getUUID(),
00113 LLUUID::null,
00114 item->getAssetUUID(),
00115 true,
00116 (LLViewerInventoryItem*)item);
00117 preview->setSourceID(LLUUID::null);
00118 preview->setFocus(TRUE);
00119
00120
00121 gFloaterView->adjustToFitScreen(preview, FALSE);
00122 }
00123 }
00124 }
00125 }
00126 };
00127
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 class LLEmbeddedItems
00141 {
00142 public:
00143 LLEmbeddedItems(const LLViewerTextEditor* editor);
00144 ~LLEmbeddedItems();
00145 void clear();
00146
00147
00148 bool empty();
00149
00150 void bindEmbeddedChars(LLFontGL* font) const;
00151 void unbindEmbeddedChars(LLFontGL* font) const;
00152
00153 BOOL insertEmbeddedItem(LLInventoryItem* item, llwchar* value, bool is_new);
00154 BOOL removeEmbeddedItem( llwchar ext_char );
00155
00156 BOOL hasEmbeddedItem(llwchar ext_char);
00157
00158 void getEmbeddedItemList( std::vector<LLPointer<LLInventoryItem> >& items );
00159 void addItems(const std::vector<LLPointer<LLInventoryItem> >& items);
00160
00161 llwchar getEmbeddedCharFromIndex(S32 index);
00162
00163 void removeUnusedChars();
00164 void copyUsedCharsToIndexed();
00165 S32 getIndexFromEmbeddedChar(llwchar wch);
00166
00167 void markSaved();
00168
00169 static LLInventoryItem* getEmbeddedItem(llwchar ext_char);
00170 static BOOL getEmbeddedItemSaved(llwchar ext_char);
00171
00172 private:
00173
00174 struct embedded_info_t
00175 {
00176 LLPointer<LLInventoryItem> mItem;
00177 BOOL mSaved;
00178 };
00179 typedef std::map<llwchar, embedded_info_t > item_map_t;
00180 static item_map_t sEntries;
00181 static std::stack<llwchar> sFreeEntries;
00182
00183 std::set<llwchar> mEmbeddedUsedChars;
00184 std::vector<llwchar> mEmbeddedIndexedChars;
00185 const LLViewerTextEditor* mEditor;
00186 };
00187
00188
00189 LLEmbeddedItems::item_map_t LLEmbeddedItems::sEntries;
00190 std::stack<llwchar> LLEmbeddedItems::sFreeEntries;
00191
00192 LLEmbeddedItems::LLEmbeddedItems(const LLViewerTextEditor* editor)
00193 : mEditor(editor)
00194 {
00195 }
00196
00197 LLEmbeddedItems::~LLEmbeddedItems()
00198 {
00199 clear();
00200 }
00201
00202 void LLEmbeddedItems::clear()
00203 {
00204
00205 for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin();
00206 iter != mEmbeddedUsedChars.end();)
00207 {
00208 std::set<llwchar>::iterator nextiter = iter++;
00209 removeEmbeddedItem(*nextiter);
00210 }
00211 mEmbeddedUsedChars.clear();
00212 mEmbeddedIndexedChars.clear();
00213 }
00214
00215 bool LLEmbeddedItems::empty()
00216 {
00217 removeUnusedChars();
00218 return mEmbeddedUsedChars.empty();
00219 }
00220
00221
00222 BOOL LLEmbeddedItems::insertEmbeddedItem( LLInventoryItem* item, llwchar* ext_char, bool is_new)
00223 {
00224
00225 llwchar wc_emb;
00226 if (!sFreeEntries.empty())
00227 {
00228 wc_emb = sFreeEntries.top();
00229 sFreeEntries.pop();
00230 }
00231 else if (sEntries.empty())
00232 {
00233 wc_emb = LLTextEditor::FIRST_EMBEDDED_CHAR;
00234 }
00235 else
00236 {
00237 item_map_t::iterator last = sEntries.end();
00238 --last;
00239 wc_emb = last->first;
00240 if (wc_emb >= LLTextEditor::LAST_EMBEDDED_CHAR)
00241 {
00242 return FALSE;
00243 }
00244 ++wc_emb;
00245 }
00246
00247 sEntries[wc_emb].mItem = item;
00248 sEntries[wc_emb].mSaved = is_new ? FALSE : TRUE;
00249 *ext_char = wc_emb;
00250 mEmbeddedUsedChars.insert(wc_emb);
00251 return TRUE;
00252 }
00253
00254
00255 BOOL LLEmbeddedItems::removeEmbeddedItem( llwchar ext_char )
00256 {
00257 mEmbeddedUsedChars.erase(ext_char);
00258 item_map_t::iterator iter = sEntries.find(ext_char);
00259 if (iter != sEntries.end())
00260 {
00261 sEntries.erase(ext_char);
00262 sFreeEntries.push(ext_char);
00263 return TRUE;
00264 }
00265 return FALSE;
00266 }
00267
00268
00269 LLInventoryItem* LLEmbeddedItems::getEmbeddedItem(llwchar ext_char)
00270 {
00271 if( ext_char >= LLTextEditor::FIRST_EMBEDDED_CHAR && ext_char <= LLTextEditor::LAST_EMBEDDED_CHAR )
00272 {
00273 item_map_t::iterator iter = sEntries.find(ext_char);
00274 if (iter != sEntries.end())
00275 {
00276 return iter->second.mItem;
00277 }
00278 }
00279 return NULL;
00280 }
00281
00282
00283 BOOL LLEmbeddedItems::getEmbeddedItemSaved(llwchar ext_char)
00284 {
00285 if( ext_char >= LLTextEditor::FIRST_EMBEDDED_CHAR && ext_char <= LLTextEditor::LAST_EMBEDDED_CHAR )
00286 {
00287 item_map_t::iterator iter = sEntries.find(ext_char);
00288 if (iter != sEntries.end())
00289 {
00290 return iter->second.mSaved;
00291 }
00292 }
00293 return FALSE;
00294 }
00295
00296 llwchar LLEmbeddedItems::getEmbeddedCharFromIndex(S32 index)
00297 {
00298 if (index >= (S32)mEmbeddedIndexedChars.size())
00299 {
00300 llwarns << "No item for embedded char " << index << " using LL_UNKNOWN_CHAR" << llendl;
00301 return LL_UNKNOWN_CHAR;
00302 }
00303 return mEmbeddedIndexedChars[index];
00304 }
00305
00306 void LLEmbeddedItems::removeUnusedChars()
00307 {
00308 std::set<llwchar> used = mEmbeddedUsedChars;
00309 const LLWString& wtext = mEditor->getWText();
00310 for (S32 i=0; i<(S32)wtext.size(); i++)
00311 {
00312 llwchar wc = wtext[i];
00313 if( wc >= LLTextEditor::FIRST_EMBEDDED_CHAR && wc <= LLTextEditor::LAST_EMBEDDED_CHAR )
00314 {
00315 used.erase(wc);
00316 }
00317 }
00318
00319 for (std::set<llwchar>::iterator iter = used.begin();
00320 iter != used.end(); ++iter)
00321 {
00322 removeEmbeddedItem(*iter);
00323 }
00324 }
00325
00326 void LLEmbeddedItems::copyUsedCharsToIndexed()
00327 {
00328
00329 removeUnusedChars();
00330
00331
00332 mEmbeddedIndexedChars.clear();
00333 for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin();
00334 iter != mEmbeddedUsedChars.end(); ++iter)
00335 {
00336 mEmbeddedIndexedChars.push_back(*iter);
00337 }
00338 }
00339
00340 S32 LLEmbeddedItems::getIndexFromEmbeddedChar(llwchar wch)
00341 {
00342 S32 idx = 0;
00343 for (std::vector<llwchar>::iterator iter = mEmbeddedIndexedChars.begin();
00344 iter != mEmbeddedIndexedChars.end(); ++iter)
00345 {
00346 if (wch == *iter)
00347 break;
00348 ++idx;
00349 }
00350 if (idx < (S32)mEmbeddedIndexedChars.size())
00351 {
00352 return idx;
00353 }
00354 else
00355 {
00356 llwarns << "Embedded char " << wch << " not found, using 0" << llendl;
00357 return 0;
00358 }
00359 }
00360
00361 BOOL LLEmbeddedItems::hasEmbeddedItem(llwchar ext_char)
00362 {
00363 std::set<llwchar>::iterator iter = mEmbeddedUsedChars.find(ext_char);
00364 if (iter != mEmbeddedUsedChars.end())
00365 {
00366 return TRUE;
00367 }
00368 return FALSE;
00369 }
00370
00371 void LLEmbeddedItems::bindEmbeddedChars( LLFontGL* font ) const
00372 {
00373 if( sEntries.empty() )
00374 {
00375 return;
00376 }
00377
00378 for (std::set<llwchar>::const_iterator iter1 = mEmbeddedUsedChars.begin(); iter1 != mEmbeddedUsedChars.end(); ++iter1)
00379 {
00380 llwchar wch = *iter1;
00381 item_map_t::iterator iter2 = sEntries.find(wch);
00382 if (iter2 == sEntries.end())
00383 {
00384 continue;
00385 }
00386 LLInventoryItem* item = iter2->second.mItem;
00387 if (!item)
00388 {
00389 continue;
00390 }
00391 const char* img_name;
00392 switch( item->getType() )
00393 {
00394 case LLAssetType::AT_TEXTURE:
00395 if(item->getInventoryType() == LLInventoryType::IT_SNAPSHOT)
00396 {
00397 img_name = "inv_item_snapshot.tga";
00398 }
00399 else
00400 {
00401 img_name = "inv_item_texture.tga";
00402 }
00403
00404 break;
00405 case LLAssetType::AT_SOUND: img_name = "inv_item_sound.tga"; break;
00406 case LLAssetType::AT_LANDMARK:
00407 if (item->getFlags() & LLInventoryItem::II_FLAGS_LANDMARK_VISITED)
00408 {
00409 img_name = "inv_item_landmark_visited.tga";
00410 }
00411 else
00412 {
00413 img_name = "inv_item_landmark.tga";
00414 }
00415 break;
00416 case LLAssetType::AT_CLOTHING: img_name = "inv_item_clothing.tga"; break;
00417 case LLAssetType::AT_OBJECT:
00418 if (item->getFlags() & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS)
00419 {
00420 img_name = "inv_item_object_multi.tga";
00421 }
00422 else
00423 {
00424 img_name = "inv_item_object.tga";
00425 }
00426 break;
00427 case LLAssetType::AT_NOTECARD: img_name = "inv_item_notecard.tga"; break;
00428 case LLAssetType::AT_LSL_TEXT: img_name = "inv_item_script.tga"; break;
00429 case LLAssetType::AT_BODYPART: img_name = "inv_item_skin.tga"; break;
00430 case LLAssetType::AT_ANIMATION: img_name = "inv_item_animation.tga";break;
00431 case LLAssetType::AT_GESTURE: img_name = "inv_item_gesture.tga"; break;
00432 default: llassert(0); continue;
00433 }
00434
00435 LLUIImagePtr image = LLUI::getUIImage(img_name);
00436
00437 font->addEmbeddedChar( wch, image->getImage(), item->getName() );
00438 }
00439 }
00440
00441 void LLEmbeddedItems::unbindEmbeddedChars( LLFontGL* font ) const
00442 {
00443 if( sEntries.empty() )
00444 {
00445 return;
00446 }
00447
00448 for (std::set<llwchar>::const_iterator iter1 = mEmbeddedUsedChars.begin(); iter1 != mEmbeddedUsedChars.end(); ++iter1)
00449 {
00450 font->removeEmbeddedChar(*iter1);
00451 }
00452 }
00453
00454 void LLEmbeddedItems::addItems(const std::vector<LLPointer<LLInventoryItem> >& items)
00455 {
00456 for (std::vector<LLPointer<LLInventoryItem> >::const_iterator iter = items.begin();
00457 iter != items.end(); ++iter)
00458 {
00459 LLInventoryItem* item = *iter;
00460 if (item)
00461 {
00462 llwchar wc;
00463 if (!insertEmbeddedItem( item, &wc, false ))
00464 {
00465 break;
00466 }
00467 mEmbeddedIndexedChars.push_back(wc);
00468 }
00469 }
00470 }
00471
00472 void LLEmbeddedItems::getEmbeddedItemList( std::vector<LLPointer<LLInventoryItem> >& items )
00473 {
00474 for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin(); iter != mEmbeddedUsedChars.end(); ++iter)
00475 {
00476 llwchar wc = *iter;
00477 LLPointer<LLInventoryItem> item = getEmbeddedItem(wc);
00478 if (item)
00479 {
00480 items.push_back(item);
00481 }
00482 }
00483 }
00484
00485 void LLEmbeddedItems::markSaved()
00486 {
00487 for (std::set<llwchar>::iterator iter = mEmbeddedUsedChars.begin(); iter != mEmbeddedUsedChars.end(); ++iter)
00488 {
00489 llwchar wc = *iter;
00490 sEntries[wc].mSaved = TRUE;
00491 }
00492 }
00493
00495
00496 class LLViewerTextEditor::LLTextCmdInsertEmbeddedItem : public LLTextEditor::LLTextCmd
00497 {
00498 public:
00499 LLTextCmdInsertEmbeddedItem( S32 pos, LLInventoryItem* item )
00500 : LLTextCmd(pos, FALSE),
00501 mExtCharValue(0)
00502 {
00503 mItem = item;
00504 }
00505
00506 virtual BOOL execute( LLTextEditor* editor, S32* delta )
00507 {
00508 LLViewerTextEditor* viewer_editor = (LLViewerTextEditor*)editor;
00509
00510 viewer_editor->mEmbeddedItemList->removeUnusedChars();
00511 if(viewer_editor->mEmbeddedItemList->insertEmbeddedItem( mItem, &mExtCharValue, true ) )
00512 {
00513 LLWString ws;
00514 ws.assign(1, mExtCharValue);
00515 *delta = insert(editor, getPosition(), ws );
00516 return (*delta != 0);
00517 }
00518 return FALSE;
00519 }
00520
00521 virtual S32 undo( LLTextEditor* editor )
00522 {
00523 remove(editor, getPosition(), 1);
00524 return getPosition();
00525 }
00526
00527 virtual S32 redo( LLTextEditor* editor )
00528 {
00529 LLWString ws;
00530 ws += mExtCharValue;
00531 insert(editor, getPosition(), ws );
00532 return getPosition() + 1;
00533 }
00534 virtual BOOL hasExtCharValue( llwchar value ) const
00535 {
00536 return (value == mExtCharValue);
00537 }
00538
00539 private:
00540 LLPointer<LLInventoryItem> mItem;
00541 llwchar mExtCharValue;
00542 };
00543
00544 struct LLNotecardCopyInfo
00545 {
00546 LLNotecardCopyInfo(LLViewerTextEditor *ed, LLInventoryItem *item)
00547 : mTextEd(ed)
00548 {
00549 mItem = item;
00550 }
00551
00552 LLViewerTextEditor* mTextEd;
00553
00554
00555 LLPointer<LLInventoryItem> mItem;
00556 };
00557
00558
00559
00560
00561
00562
00563
00564 LLViewerTextEditor::LLViewerTextEditor(const LLString& name,
00565 const LLRect& rect,
00566 S32 max_length,
00567 const LLString& default_text,
00568 const LLFontGL* font,
00569 BOOL allow_embedded_items)
00570 : LLTextEditor(name, rect, max_length, default_text, font, allow_embedded_items),
00571 mDragItemSaved(FALSE),
00572 mInventoryCallback(new LLEmbeddedNotecardOpener)
00573 {
00574 mEmbeddedItemList = new LLEmbeddedItems(this);
00575 mInventoryCallback->setEditor(this);
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00588
00589 }
00590
00591 LLViewerTextEditor::~LLViewerTextEditor()
00592 {
00593 delete mEmbeddedItemList;
00594
00595
00596
00597
00598 mInventoryCallback->setEditor(NULL);
00599 }
00600
00602
00603 void LLViewerTextEditor::makePristine()
00604 {
00605 mEmbeddedItemList->markSaved();
00606 LLTextEditor::makePristine();
00607 }
00608
00610
00611 BOOL LLViewerTextEditor::handleToolTip(S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen)
00612 {
00613 for (child_list_const_iter_t child_iter = getChildList()->begin();
00614 child_iter != getChildList()->end(); ++child_iter)
00615 {
00616 LLView *viewp = *child_iter;
00617 S32 local_x = x - viewp->getRect().mLeft;
00618 S32 local_y = y - viewp->getRect().mBottom;
00619 if( viewp->handleToolTip(local_x, local_y, msg, sticky_rect_screen ) )
00620 {
00621 return TRUE;
00622 }
00623 }
00624
00625 if( mSegments.empty() )
00626 {
00627 return TRUE;
00628 }
00629
00630 const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y );
00631 if( cur_segment )
00632 {
00633 BOOL has_tool_tip = FALSE;
00634 if( cur_segment->getStyle()->getIsEmbeddedItem() )
00635 {
00636 LLWString wtip;
00637 has_tool_tip = getEmbeddedItemToolTipAtPos(cur_segment->getStart(), wtip);
00638 msg = wstring_to_utf8str(wtip);
00639 }
00640 else
00641 {
00642 has_tool_tip = cur_segment->getToolTip( msg );
00643 }
00644 if( has_tool_tip )
00645 {
00646
00647
00648 S32 SLOP = 8;
00649 localPointToScreen(
00650 x - SLOP, y - SLOP,
00651 &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
00652 sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP;
00653 sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP;
00654 }
00655 }
00656 return TRUE;
00657 }
00658
00659 BOOL LLViewerTextEditor::handleMouseDown(S32 x, S32 y, MASK mask)
00660 {
00661 BOOL handled = FALSE;
00662
00663
00664 handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
00665
00666
00667 BOOL was_scrolled_to_bottom = (mScrollbar->getDocPos() == mScrollbar->getDocPosMax());
00668 if (mOnScrollEndCallback && was_scrolled_to_bottom)
00669 {
00670 mOnScrollEndCallback(mOnScrollEndData);
00671 }
00672
00673 if( !handled && mTakesNonScrollClicks)
00674 {
00675 if (!(mask & MASK_SHIFT))
00676 {
00677 deselect();
00678 }
00679
00680 BOOL start_select = TRUE;
00681 if( allowsEmbeddedItems() )
00682 {
00683 setCursorAtLocalPos( x, y, FALSE );
00684 llwchar wc = 0;
00685 if (mCursorPos < getLength())
00686 {
00687 wc = getWChar(mCursorPos);
00688 }
00689 LLInventoryItem* item_at_pos = LLEmbeddedItems::getEmbeddedItem(wc);
00690 if (item_at_pos)
00691 {
00692 mDragItem = item_at_pos;
00693 mDragItemSaved = LLEmbeddedItems::getEmbeddedItemSaved(wc);
00694 gFocusMgr.setMouseCapture( this );
00695 mMouseDownX = x;
00696 mMouseDownY = y;
00697 S32 screen_x;
00698 S32 screen_y;
00699 localPointToScreen(x, y, &screen_x, &screen_y );
00700 LLToolDragAndDrop::getInstance()->setDragStart( screen_x, screen_y );
00701
00702 start_select = FALSE;
00703 }
00704 else
00705 {
00706 mDragItem = NULL;
00707 }
00708 }
00709
00710 if( start_select )
00711 {
00712
00713 if (mask & MASK_SHIFT)
00714 {
00715 S32 old_cursor_pos = mCursorPos;
00716 setCursorAtLocalPos( x, y, TRUE );
00717
00718 if (hasSelection())
00719 {
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741 mSelectionEnd = mCursorPos;
00742 }
00743 else
00744 {
00745 mSelectionStart = old_cursor_pos;
00746 mSelectionEnd = mCursorPos;
00747 }
00748
00749 mIsSelecting = TRUE;
00750
00751 }
00752 else
00753 {
00754 setCursorAtLocalPos( x, y, TRUE );
00755 startSelection();
00756 }
00757 gFocusMgr.setMouseCapture( this );
00758 }
00759
00760 handled = TRUE;
00761 }
00762
00763 if (hasTabStop())
00764 {
00765 setFocus(TRUE);
00766 handled = TRUE;
00767 }
00768
00769
00770 resetKeystrokeTimer();
00771
00772 return handled;
00773 }
00774
00775
00776 BOOL LLViewerTextEditor::handleHover(S32 x, S32 y, MASK mask)
00777 {
00778 BOOL handled = FALSE;
00779
00780 if (!mDragItem)
00781 {
00782
00783 mHoverSegment = NULL;
00784 }
00785 if(hasMouseCapture() )
00786 {
00787 if( mIsSelecting )
00788 {
00789 if (x != mLastSelectionX || y != mLastSelectionY)
00790 {
00791 mLastSelectionX = x;
00792 mLastSelectionY = y;
00793 }
00794
00795 if( y > getTextRect().mTop )
00796 {
00797 mScrollbar->setDocPos( mScrollbar->getDocPos() - 1 );
00798 }
00799 else
00800 if( y < getTextRect().mBottom )
00801 {
00802 mScrollbar->setDocPos( mScrollbar->getDocPos() + 1 );
00803 }
00804
00805 setCursorAtLocalPos( x, y, TRUE );
00806 mSelectionEnd = mCursorPos;
00807
00808 updateScrollFromCursor();
00809 getWindow()->setCursor(UI_CURSOR_IBEAM);
00810 }
00811 else if( mDragItem )
00812 {
00813 S32 screen_x;
00814 S32 screen_y;
00815 localPointToScreen(x, y, &screen_x, &screen_y );
00816 if( LLToolDragAndDrop::getInstance()->isOverThreshold( screen_x, screen_y ) )
00817 {
00818 LLToolDragAndDrop::getInstance()->beginDrag(
00819 LLAssetType::lookupDragAndDropType( mDragItem->getType() ),
00820 mDragItem->getUUID(),
00821 LLToolDragAndDrop::SOURCE_NOTECARD,
00822 getSourceID(), mObjectID);
00823
00824 return LLToolDragAndDrop::getInstance()->handleHover( x, y, mask );
00825 }
00826 getWindow()->setCursor(UI_CURSOR_HAND);
00827 }
00828
00829 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl;
00830 handled = TRUE;
00831 }
00832
00833 if( !handled )
00834 {
00835
00836 handled = LLView::childrenHandleHover(x, y, mask) != NULL;
00837 }
00838
00839 if( handled )
00840 {
00841
00842 resetKeystrokeTimer();
00843 }
00844
00845
00846 if( !handled && mTakesNonScrollClicks)
00847 {
00848
00849 if( !mSegments.empty() )
00850 {
00851 const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y );
00852 if( cur_segment )
00853 {
00854 if(cur_segment->getStyle()->isLink())
00855 {
00856 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (over link, inactive)" << llendl;
00857 getWindow()->setCursor(UI_CURSOR_HAND);
00858 handled = TRUE;
00859 }
00860 else
00861 if(cur_segment->getStyle()->getIsEmbeddedItem())
00862 {
00863 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (over embedded item, inactive)" << llendl;
00864 getWindow()->setCursor(UI_CURSOR_HAND);
00865
00866 handled = TRUE;
00867 }
00868 mHoverSegment = cur_segment;
00869 }
00870 }
00871
00872 if( !handled )
00873 {
00874 lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl;
00875 if (!mScrollbar->getVisible() || x < getRect().getWidth() - SCROLLBAR_SIZE)
00876 {
00877 getWindow()->setCursor(UI_CURSOR_IBEAM);
00878 }
00879 else
00880 {
00881 getWindow()->setCursor(UI_CURSOR_ARROW);
00882 }
00883 handled = TRUE;
00884 }
00885 }
00886
00887 return handled;
00888 }
00889
00890
00891 BOOL LLViewerTextEditor::handleMouseUp(S32 x, S32 y, MASK mask)
00892 {
00893 BOOL handled = FALSE;
00894
00895
00896 handled = LLView::childrenHandleMouseUp(x, y, mask) != NULL;
00897
00898
00899 BOOL was_scrolled_to_bottom = (mScrollbar->getDocPos() == mScrollbar->getDocPosMax());
00900 if (mOnScrollEndCallback && was_scrolled_to_bottom)
00901 {
00902 mOnScrollEndCallback(mOnScrollEndData);
00903 }
00904
00905 if( !handled && mTakesNonScrollClicks)
00906 {
00907 if( mIsSelecting )
00908 {
00909
00910 if( y > getTextRect().mTop )
00911 {
00912 mScrollbar->setDocPos( mScrollbar->getDocPos() - 1 );
00913 }
00914 else
00915 if( y < getTextRect().mBottom )
00916 {
00917 mScrollbar->setDocPos( mScrollbar->getDocPos() + 1 );
00918 }
00919
00920 setCursorAtLocalPos( x, y, TRUE );
00921 endSelection();
00922
00923 updateScrollFromCursor();
00924 }
00925
00926 if( !hasSelection() )
00927 {
00928 handleMouseUpOverSegment( x, y, mask );
00929 }
00930
00931 handled = TRUE;
00932 }
00933
00934
00935 resetKeystrokeTimer();
00936
00937 if( hasMouseCapture() )
00938 {
00939 if (mDragItem)
00940 {
00941
00942 S32 dx = x - mMouseDownX;
00943 S32 dy = y - mMouseDownY;
00944 if (-2 < dx && dx < 2 && -2 < dy && dy < 2)
00945 {
00946 if(mDragItemSaved)
00947 {
00948 openEmbeddedItem(mDragItem);
00949 }else
00950 {
00951 showUnsavedAlertDialog(mDragItem);
00952 }
00953 }
00954 }
00955 mDragItem = NULL;
00956 gFocusMgr.setMouseCapture( NULL );
00957 handled = TRUE;
00958 }
00959
00960 return handled;
00961 }
00962
00963 BOOL LLViewerTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask)
00964 {
00965 BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL;
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996 return handled;
00997 }
00998
00999 BOOL LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
01000 {
01001 BOOL handled = FALSE;
01002
01003
01004 handled = LLView::childrenHandleDoubleClick(x, y, mask) != NULL;
01005
01006 if( !handled && mTakesNonScrollClicks)
01007 {
01008 if( allowsEmbeddedItems() )
01009 {
01010 const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y );
01011 if( cur_segment && cur_segment->getStyle()->getIsEmbeddedItem() )
01012 {
01013 if( openEmbeddedItemAtPos( cur_segment->getStart() ) )
01014 {
01015 deselect();
01016 setFocus( FALSE );
01017 return TRUE;
01018 }
01019 }
01020 }
01021
01022
01023 setCursorAtLocalPos( x, y, FALSE );
01024 deselect();
01025
01026 const LLWString &text = getWText();
01027
01028 if( isPartOfWord( text[mCursorPos] ) )
01029 {
01030
01031 while ((mCursorPos > 0) && isPartOfWord(text[mCursorPos-1]))
01032 {
01033 mCursorPos--;
01034 }
01035 startSelection();
01036
01037 while ((mCursorPos < (S32)text.length()) && isPartOfWord( text[mCursorPos] ) )
01038 {
01039 mCursorPos++;
01040 }
01041
01042 mSelectionEnd = mCursorPos;
01043 }
01044 else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) )
01045 {
01046
01047 startSelection();
01048 mCursorPos++;
01049 mSelectionEnd = mCursorPos;
01050 }
01051
01052
01053
01054 mIsSelecting = FALSE;
01055
01056
01057 resetKeystrokeTimer();
01058
01059 handled = TRUE;
01060 }
01061 return handled;
01062 }
01063
01064
01065
01066
01067
01068 BOOL LLViewerTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask,
01069 BOOL drop, EDragAndDropType cargo_type, void *cargo_data,
01070 EAcceptance *accept,
01071 LLString& tooltip_msg)
01072 {
01073 BOOL handled = FALSE;
01074
01075 if (mTakesNonScrollClicks)
01076 {
01077 if (getEnabled() && acceptsTextInput())
01078 {
01079 switch( cargo_type )
01080 {
01081 case DAD_CALLINGCARD:
01082 if(acceptsCallingCardNames())
01083 {
01084 if (drop)
01085 {
01086 LLInventoryItem *item = (LLInventoryItem *)cargo_data;
01087 LLString name = item->getName();
01088 appendText(name, true, true);
01089 }
01090 *accept = ACCEPT_YES_COPY_SINGLE;
01091 }
01092 else
01093 {
01094 *accept = ACCEPT_NO;
01095 }
01096 break;
01097
01098 case DAD_TEXTURE:
01099 case DAD_SOUND:
01100 case DAD_LANDMARK:
01101 case DAD_SCRIPT:
01102 case DAD_CLOTHING:
01103 case DAD_OBJECT:
01104 case DAD_NOTECARD:
01105 case DAD_BODYPART:
01106 case DAD_ANIMATION:
01107 case DAD_GESTURE:
01108 {
01109 LLInventoryItem *item = (LLInventoryItem *)cargo_data;
01110 if( allowsEmbeddedItems() )
01111 {
01112 U32 mask_next = item->getPermissions().getMaskNextOwner();
01113 if((mask_next & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
01114 {
01115 if( drop )
01116 {
01117 deselect();
01118 S32 old_cursor = mCursorPos;
01119 setCursorAtLocalPos( x, y, TRUE );
01120 S32 insert_pos = mCursorPos;
01121 setCursorPos(old_cursor);
01122 BOOL inserted = insertEmbeddedItem( insert_pos, item );
01123 if( inserted && (old_cursor > mCursorPos) )
01124 {
01125 setCursorPos(mCursorPos + 1);
01126 }
01127
01128 updateLineStartList();
01129 }
01130 *accept = ACCEPT_YES_COPY_MULTI;
01131 }
01132 else
01133 {
01134 *accept = ACCEPT_NO;
01135 if (tooltip_msg.empty())
01136 {
01137 tooltip_msg.assign("Only items with unrestricted\n"
01138 "'next owner' permissions \n"
01139 "can be attached to notecards.");
01140 }
01141 }
01142 }
01143 else
01144 {
01145 *accept = ACCEPT_NO;
01146 }
01147 break;
01148 }
01149
01150 default:
01151 *accept = ACCEPT_NO;
01152 break;
01153 }
01154 }
01155 else
01156 {
01157
01158 *accept = ACCEPT_NO;
01159 }
01160
01161 handled = TRUE;
01162 lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLViewerTextEditor " << getName() << llendl;
01163 }
01164
01165 return handled;
01166 }
01167
01168 void LLViewerTextEditor::setASCIIEmbeddedText(const LLString& instr)
01169 {
01170 LLWString wtext;
01171 const U8* buffer = (U8*)(instr.c_str());
01172 while (*buffer)
01173 {
01174 llwchar wch;
01175 U8 c = *buffer++;
01176 if (c >= 0x80)
01177 {
01178 S32 index = (S32)(c - 0x80);
01179 wch = mEmbeddedItemList->getEmbeddedCharFromIndex(index);
01180 }
01181 else
01182 {
01183 wch = (llwchar)c;
01184 }
01185 wtext.push_back(wch);
01186 }
01187 setWText(wtext);
01188 }
01189
01190 void LLViewerTextEditor::setEmbeddedText(const LLString& instr)
01191 {
01192 LLWString wtext = utf8str_to_wstring(instr);
01193 for (S32 i=0; i<(S32)wtext.size(); i++)
01194 {
01195 llwchar wch = wtext[i];
01196 if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR )
01197 {
01198 S32 index = wch - FIRST_EMBEDDED_CHAR;
01199 wtext[i] = mEmbeddedItemList->getEmbeddedCharFromIndex(index);
01200 }
01201 }
01202 setWText(wtext);
01203 }
01204
01205 LLString LLViewerTextEditor::getEmbeddedText()
01206 {
01207 #if 1
01208
01209 mEmbeddedItemList->copyUsedCharsToIndexed();
01210 LLWString outtextw;
01211 for (S32 i=0; i<(S32)getWText().size(); i++)
01212 {
01213 llwchar wch = getWChar(i);
01214 if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR )
01215 {
01216 S32 index = mEmbeddedItemList->getIndexFromEmbeddedChar(wch);
01217 wch = FIRST_EMBEDDED_CHAR + index;
01218 }
01219 outtextw.push_back(wch);
01220 }
01221 LLString outtext = wstring_to_utf8str(outtextw);
01222 return outtext;
01223 #else
01224
01225 mEmbeddedItemList->copyUsedCharsToIndexed();
01226 LLString outtext;
01227 for (S32 i=0; i<(S32)mWText.size(); i++)
01228 {
01229 llwchar wch = mWText[i];
01230 if( wch >= FIRST_EMBEDDED_CHAR && wch <= LAST_EMBEDDED_CHAR )
01231 {
01232 S32 index = mEmbeddedItemList->getIndexFromEmbeddedChar(wch);
01233 wch = 0x80 | index % 128;
01234 }
01235 else if (wch >= 0x80)
01236 {
01237 wch = LL_UNKNOWN_CHAR;
01238 }
01239 outtext.push_back((U8)wch);
01240 }
01241 return outtext;
01242 #endif
01243 }
01244
01245 LLString LLViewerTextEditor::appendTime(bool prepend_newline)
01246 {
01247 U32 utc_time;
01248 utc_time = time_corrected();
01249
01250
01251 struct tm* timep;
01252
01253
01254
01255 timep = utc_to_pacific_time(utc_time, gPacificDaylightTime);
01256
01257 LLString text = llformat("[%d:%02d] ", timep->tm_hour, timep->tm_min);
01258 appendColoredText(text, false, prepend_newline, LLColor4::grey);
01259
01260 return text;
01261 }
01262
01263
01264
01265
01266 llwchar LLViewerTextEditor::pasteEmbeddedItem(llwchar ext_char)
01267 {
01268 if (mEmbeddedItemList->hasEmbeddedItem(ext_char))
01269 {
01270 return ext_char;
01271 }
01272 LLInventoryItem* item = LLEmbeddedItems::getEmbeddedItem(ext_char);
01273 if (item)
01274 {
01275
01276 llwchar new_wc;
01277 if (mEmbeddedItemList->insertEmbeddedItem( item, &new_wc, true ))
01278 {
01279 return new_wc;
01280 }
01281 }
01282 return LL_UNKNOWN_CHAR;
01283 }
01284
01285 void LLViewerTextEditor::bindEmbeddedChars(LLFontGL* font) const
01286 {
01287 mEmbeddedItemList->bindEmbeddedChars( font );
01288 }
01289
01290 void LLViewerTextEditor::unbindEmbeddedChars(LLFontGL* font) const
01291 {
01292 mEmbeddedItemList->unbindEmbeddedChars( font );
01293 }
01294
01295 BOOL LLViewerTextEditor::getEmbeddedItemToolTipAtPos(S32 pos, LLWString &msg) const
01296 {
01297 if (pos < getLength())
01298 {
01299 LLInventoryItem* item = LLEmbeddedItems::getEmbeddedItem(getWChar(pos));
01300 if( item )
01301 {
01302 msg = utf8str_to_wstring(item->getName());
01303 msg += '\n';
01304 msg += utf8str_to_wstring(item->getDescription());
01305 return TRUE;
01306 }
01307 }
01308 return FALSE;
01309 }
01310
01311
01312 BOOL LLViewerTextEditor::openEmbeddedItemAtPos(S32 pos)
01313 {
01314 if( pos < getLength())
01315 {
01316 LLInventoryItem* item = LLEmbeddedItems::getEmbeddedItem( getWChar(pos) );
01317 if( item )
01318 {
01319 BOOL saved = LLEmbeddedItems::getEmbeddedItemSaved( getWChar(pos) );
01320 if (saved)
01321 {
01322 return openEmbeddedItem(item);
01323 }
01324 else
01325 {
01326 showUnsavedAlertDialog(item);
01327 }
01328 }
01329 }
01330 return FALSE;
01331 }
01332
01333
01334 BOOL LLViewerTextEditor::openEmbeddedItem(LLInventoryItem* item)
01335 {
01336
01337 switch( item->getType() )
01338 {
01339 case LLAssetType::AT_TEXTURE:
01340 openEmbeddedTexture( item );
01341 return TRUE;
01342
01343 case LLAssetType::AT_SOUND:
01344 openEmbeddedSound( item );
01345 return TRUE;
01346
01347 case LLAssetType::AT_NOTECARD:
01348 openEmbeddedNotecard( item );
01349 return TRUE;
01350
01351 case LLAssetType::AT_LANDMARK:
01352 openEmbeddedLandmark( item );
01353 return TRUE;
01354
01355 case LLAssetType::AT_LSL_TEXT:
01356 case LLAssetType::AT_CLOTHING:
01357 case LLAssetType::AT_OBJECT:
01358 case LLAssetType::AT_BODYPART:
01359 case LLAssetType::AT_ANIMATION:
01360 case LLAssetType::AT_GESTURE:
01361 showCopyToInvDialog( item );
01362 return TRUE;
01363 default:
01364 return FALSE;
01365 }
01366
01367 }
01368
01369
01370 void LLViewerTextEditor::openEmbeddedTexture( LLInventoryItem* item )
01371 {
01372
01373
01374
01375
01376
01377 if( !LLPreview::show( item->getAssetUUID() ) )
01378 {
01379
01380 if(item)
01381 {
01382 S32 left, top;
01383 gFloaterView->getNewFloaterPosition(&left, &top);
01384 LLRect rect = gSavedSettings.getRect("PreviewTextureRect");
01385 rect.translate( left - rect.mLeft, top - rect.mTop );
01386
01387 LLPreviewTexture* preview = new LLPreviewTexture("preview texture",
01388 rect,
01389 item->getName(),
01390 item->getAssetUUID(),
01391 TRUE);
01392 preview->setAuxItem( item );
01393 preview->setNotecardInfo(mNotecardInventoryID, mObjectID);
01394 }
01395 }
01396 }
01397
01398 void LLViewerTextEditor::openEmbeddedSound( LLInventoryItem* item )
01399 {
01400
01401 LLVector3d lpos_global = gAgent.getPositionGlobal();
01402 const F32 SOUND_GAIN = 1.0f;
01403 if(gAudiop)
01404 {
01405 F32 volume = gSavedSettings.getBOOL("MuteSounds") ? 0.f : (SOUND_GAIN * gSavedSettings.getF32("AudioLevelSFX"));
01406 gAudiop->triggerSound(item->getAssetUUID(), gAgentID, volume, lpos_global);
01407 }
01408 showCopyToInvDialog( item );
01409 }
01410
01411
01412 void LLViewerTextEditor::openEmbeddedLandmark( LLInventoryItem* item )
01413 {
01414 LLString title =
01415 LLString(" ") + LLLandmarkBridge::prefix() + item->getName();
01416 open_landmark((LLViewerInventoryItem*)item, title, FALSE, item->getUUID(), TRUE);
01417 }
01418
01419 void LLViewerTextEditor::openEmbeddedNotecard( LLInventoryItem* item )
01420 {
01421
01422
01423
01424
01425
01426 copyInventory(item, gInventoryCallbacks.registerCB(mInventoryCallback));
01427
01428
01429
01430
01431
01432
01433
01434
01435 }
01436
01437 void LLViewerTextEditor::showUnsavedAlertDialog( LLInventoryItem* item )
01438 {
01439 LLNotecardCopyInfo *info = new LLNotecardCopyInfo(this, item);
01440 gViewerWindow->alertXml( "ConfirmNotecardSave",
01441 LLViewerTextEditor::onNotecardDialog, (void*)info);
01442 }
01443
01444 void LLViewerTextEditor::onNotecardDialog( S32 option, void* userdata )
01445 {
01446 LLNotecardCopyInfo *info = (LLNotecardCopyInfo *)userdata;
01447 if( option == 0 )
01448 {
01449
01450 LLPointer<LLInventoryItem>* itemptr = new LLPointer<LLInventoryItem>(info->mItem);
01451 LLPreview::save( info->mTextEd->mNotecardInventoryID, itemptr);
01452 }
01453 }
01454
01455
01456
01457 void LLViewerTextEditor::showCopyToInvDialog( LLInventoryItem* item )
01458 {
01459 LLNotecardCopyInfo *info = new LLNotecardCopyInfo(this, item);
01460 gViewerWindow->alertXml( "ConfirmItemCopy",
01461 LLViewerTextEditor::onCopyToInvDialog, (void*)info);
01462 }
01463
01464
01465 void LLViewerTextEditor::onCopyToInvDialog( S32 option, void* userdata )
01466 {
01467 LLNotecardCopyInfo *info = (LLNotecardCopyInfo *)userdata;
01468 if( 0 == option )
01469 {
01470 info->mTextEd->copyInventory(info->mItem);
01471 }
01472 delete info;
01473 }
01474
01475
01476
01477
01478 S32 LLViewerTextEditor::insertEmbeddedItem( S32 pos, LLInventoryItem* item )
01479 {
01480 return execute( new LLTextCmdInsertEmbeddedItem( pos, item ) );
01481 }
01482
01483 bool LLViewerTextEditor::importStream(std::istream& str)
01484 {
01485 LLNotecard nc(LLNotecard::MAX_SIZE);
01486 bool success = nc.importStream(str);
01487 if (success)
01488 {
01489 mEmbeddedItemList->clear();
01490 const std::vector<LLPointer<LLInventoryItem> >& items = nc.getItems();
01491 mEmbeddedItemList->addItems(items);
01492
01493 if (allowsEmbeddedItems())
01494 {
01495 if (nc.getVersion() == 1)
01496 setASCIIEmbeddedText( nc.getText() );
01497 else
01498 setEmbeddedText( nc.getText() );
01499 }
01500 else
01501 {
01502 setText( nc.getText() );
01503 }
01504 }
01505 return success;
01506 }
01507
01508 void LLViewerTextEditor::copyInventory(const LLInventoryItem* item, U32 callback_id)
01509 {
01510 copy_inventory_from_notecard(mObjectID,
01511 mNotecardInventoryID,
01512 item, callback_id);
01513 }
01514
01515 bool LLViewerTextEditor::hasEmbeddedInventory()
01516 {
01517 return ! mEmbeddedItemList->empty();
01518 }
01519
01521
01522 BOOL LLViewerTextEditor::importBuffer( const LLString& buffer )
01523 {
01524 LLMemoryStream str((U8*)buffer.c_str(), buffer.length());
01525 return importStream(str);
01526 }
01527
01528 BOOL LLViewerTextEditor::exportBuffer( LLString& buffer )
01529 {
01530 LLNotecard nc(LLNotecard::MAX_SIZE);
01531
01532
01533 nc.setText(getEmbeddedText());
01534
01535
01536 std::vector<LLPointer<LLInventoryItem> > embedded_items;
01537 mEmbeddedItemList->getEmbeddedItemList(embedded_items);
01538 nc.setItems(embedded_items);
01539
01540 std::stringstream out_stream;
01541 nc.exportStream(out_stream);
01542
01543 buffer = out_stream.str();
01544
01545 return TRUE;
01546 }
01547
01548 LLView* LLViewerTextEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
01549 {
01550 LLString name("text_editor");
01551 node->getAttributeString("name", name);
01552
01553 LLRect rect;
01554 createRect(node, rect, parent, LLRect());
01555
01556 U32 max_text_length = 255;
01557 node->getAttributeU32("max_length", max_text_length);
01558
01559 BOOL allow_embedded_items = FALSE;
01560 node->getAttributeBOOL("embedded_items", allow_embedded_items);
01561
01562 LLFontGL* font = LLView::selectFont(node);
01563
01564
01565 LLString text = node->getTextContents().substr(0, max_text_length - 1);
01566
01567 if (text.size() > max_text_length)
01568 {
01569
01570 text.erase(max_text_length);
01571 }
01572
01573 LLViewerTextEditor* text_editor = new LLViewerTextEditor(name,
01574 rect,
01575 max_text_length,
01576 "",
01577 font,
01578 allow_embedded_items);
01579
01580 BOOL ignore_tabs = text_editor->tabsToNextField();
01581 node->getAttributeBOOL("ignore_tab", ignore_tabs);
01582 text_editor->setTabsToNextField(ignore_tabs);
01583
01584 text_editor->setTextEditorParameters(node);
01585
01586 BOOL hide_scrollbar = FALSE;
01587 node->getAttributeBOOL("hide_scrollbar",hide_scrollbar);
01588 text_editor->setHideScrollbarForShortDocs(hide_scrollbar);
01589
01590 BOOL hide_border = !text_editor->isBorderVisible();
01591 node->getAttributeBOOL("hide_border", hide_border);
01592 text_editor->setBorderVisible(!hide_border);
01593
01594 BOOL parse_html = text_editor->mParseHTML;
01595 node->getAttributeBOOL("allow_html", parse_html);
01596 text_editor->setParseHTML(parse_html);
01597
01598 text_editor->initFromXML(node, parent);
01599
01600
01601 text_editor->appendStyledText(text, FALSE, FALSE);
01602
01603 return text_editor;
01604 }