llviewertexteditor.cpp

Go to the documentation of this file.
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"  // for landmark prefix string
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" // for gPacificDaylightTime
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         // override
00082         void fire(const LLUUID& inv_item)
00083         {
00084                 if(!mTextEditor)
00085                 {
00086                         // The parent text editor may have vanished by now. 
00087             // In that case just quit.
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                         // See if we can bring an existing preview to the front
00099                         if(!LLPreview::show(item->getUUID(), true))
00100                         {
00101                                 if(!gSavedSettings.getBOOL("ShowNewInventory"))
00102                                 {
00103                                         // There isn't one, so make a new preview
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                                         // Force to be entirely onscreen.
00121                                         gFloaterView->adjustToFitScreen(preview, FALSE);
00122                                 }
00123                         }
00124                 }
00125         }
00126 };
00127 
00129 // LLEmbeddedItems
00130 //
00131 // Embedded items are stored as:
00132 // * A global map of llwchar to LLInventoryItem
00133 // ** This is unique for each item embedded in any notecard
00134 //    to support copy/paste across notecards
00135 // * A per-notecard set of embeded llwchars for easy removal
00136 //   from the global list
00137 // * A per-notecard vector of embedded lwchars for mapping from
00138 //   old style 0x80 + item format notechards
00139 
00140 class LLEmbeddedItems
00141 {
00142 public:
00143         LLEmbeddedItems(const LLViewerTextEditor* editor);
00144         ~LLEmbeddedItems();
00145         void clear();
00146 
00147         // return true if there are no embedded items.
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); // returns TRUE if /this/ editor has an entry for this item
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); // returns item from static list
00170         static BOOL getEmbeddedItemSaved(llwchar ext_char); // returns whether item from static list is saved
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;    // list of used llwchars
00184         std::vector<llwchar> mEmbeddedIndexedChars; // index -> wchar for 0x80 + index format
00185         const LLViewerTextEditor* mEditor;
00186 };
00187 
00188 //statics
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         // Remove entries for this editor from static list
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 // Inserts a new unique entry
00222 BOOL LLEmbeddedItems::insertEmbeddedItem( LLInventoryItem* item, llwchar* ext_char, bool is_new)
00223 {
00224         // Now insert a new one
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 // Removes an entry (all entries are unique)
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 // static
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 // static
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         // Remove chars not actually used
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         // Prune unused items
00329         removeUnusedChars();
00330 
00331         // Copy all used llwchars to mEmbeddedIndexedChars
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                 // Take this opportunity to remove any unused embedded items from this editor
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         // need to make this be a copy (not a * here) because it isn't stable.
00554         // I wish we had passed LLPointers all the way down, but we didn't
00555         LLPointer<LLInventoryItem> mItem;
00556 };
00557 
00558 //----------------------------------------------------------------------------
00559 
00560 //
00561 // Member functions
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         // *TODO: Add right click menus for SLURLs
00578         // Build the right click menu
00579         // make the popup menu available
00580 
00581         //LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_slurl.xml", this);
00582         //if (!menu)
00583         //{
00584         //      menu = new LLMenuGL("");
00585         //}
00586         //menu->setBackgroundColor(gColors.getColor("MenuPopupBgColor"));
00588         //mPopupMenuHandle = menu->getHandle();
00589 }
00590 
00591 LLViewerTextEditor::~LLViewerTextEditor()
00592 {
00593         delete mEmbeddedItemList;
00594         
00595         
00596         // The inventory callback may still be in use by gInventoryCallbackManager...
00597         // so set its reference to this to null.
00598         mInventoryCallback->setEditor(NULL); 
00599 }
00600 
00602 // virtual
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                         // Just use a slop area around the cursor
00647                         // Convert rect local to screen coordinates
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         // Let scrollbar have first dibs
00664         handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL;
00665 
00666         // enable I Agree checkbox if the user scrolled through entire text
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                         // If we're not scrolling (handled by child), then we're selecting
00713                         if (mask & MASK_SHIFT)
00714                         {
00715                                 S32 old_cursor_pos = mCursorPos;
00716                                 setCursorAtLocalPos( x, y, TRUE );
00717 
00718                                 if (hasSelection())
00719                                 {
00720                                         /* Mac-like behavior - extend selection towards the cursor
00721                                         if (mCursorPos < mSelectionStart
00722                                                 && mCursorPos < mSelectionEnd)
00723                                         {
00724                                                 // ...left of selection
00725                                                 mSelectionStart = llmax(mSelectionStart, mSelectionEnd);
00726                                                 mSelectionEnd = mCursorPos;
00727                                         }
00728                                         else if (mCursorPos > mSelectionStart
00729                                                 && mCursorPos > mSelectionEnd)
00730                                         {
00731                                                 // ...right of selection
00732                                                 mSelectionStart = llmin(mSelectionStart, mSelectionEnd);
00733                                                 mSelectionEnd = mCursorPos;
00734                                         }
00735                                         else
00736                                         {
00737                                                 mSelectionEnd = mCursorPos;
00738                                         }
00739                                         */
00740                                         // Windows behavior
00741                                         mSelectionEnd = mCursorPos;
00742                                 }
00743                                 else
00744                                 {
00745                                         mSelectionStart = old_cursor_pos;
00746                                         mSelectionEnd = mCursorPos;
00747                                 }
00748                                 // assume we're starting a drag select
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         // Delay cursor flashing
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                 // leave hover segment active during drag and drop
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                 // Pass to children
00836                 handled = LLView::childrenHandleHover(x, y, mask) != NULL;
00837         }
00838 
00839         if( handled )
00840         {
00841                 // Delay cursor flashing
00842                 resetKeystrokeTimer();
00843         }
00844 
00845         // Opaque
00846         if( !handled && mTakesNonScrollClicks)
00847         {
00848                 // Check to see if we're over an HTML-style link
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                                         //getWindow()->setCursor(UI_CURSOR_ARROW);
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         // let scrollbar have first dibs
00896         handled = LLView::childrenHandleMouseUp(x, y, mask) != NULL;
00897 
00898         // Used to enable I Agree checkbox if the user scrolled through entire text
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                         // Finish selection
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         // Delay cursor flashing
00935         resetKeystrokeTimer();
00936 
00937         if( hasMouseCapture()  )
00938         {
00939                 if (mDragItem)
00940                 {
00941                         // mouse down was on an item
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         // *TODO: Add right click menus for SLURLs
00968 //      if(! handled)
00969 //      {
00970 //              const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y );
00971 //              if( cur_segment )
00972 //              {
00973 //                      if(cur_segment->getStyle()->isLink())
00974 //                      {
00975 //                              handled = TRUE;
00976 //                              mHTML = cur_segment->getStyle()->getLinkHREF();
00977 //                      }
00978 //              }
00979 //      }
00980 //      LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
00981 //      if(handled && menu && mParseHTML && mHTML.length() > 0)
00982 //      {
00983 //              menu->setVisible(TRUE);
00984 //              menu->arrange();
00985 //              menu->updateParent(LLMenuGL::sMenuContainer);
00986 //              LLMenuGL::showPopup(this, menu, x, y);
00987 //              mHTML = "";
00988 //      }
00989 //      else
00990 //      {
00991 //              if(menu && menu->getVisible())
00992 //              {
00993 //                      menu->setVisible(FALSE);
00994 //              }
00995 //      }
00996         return handled;
00997 }
00998 
00999 BOOL LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask)
01000 {
01001         BOOL    handled = FALSE;
01002 
01003         // let scrollbar have first dibs
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                         // Select word the cursor is over
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                         // Select the character the cursor is over
01047                         startSelection();
01048                         mCursorPos++;
01049                         mSelectionEnd = mCursorPos;
01050                 }
01051 
01052                 // We don't want handleMouseUp() to "finish" the selection (and thereby
01053                 // set mSelectionEnd to where the mouse is), so we finish the selection here.
01054                 mIsSelecting = FALSE;  
01055 
01056                 // delay cursor flashing
01057                 resetKeystrokeTimer();
01058 
01059                 handled = TRUE;
01060         }
01061         return handled;
01062 }
01063 
01064 
01065 // Allow calling cards to be dropped onto text fields.  Append the name and
01066 // a carriage return.
01067 // virtual
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                         // Not enabled
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         // New version (Version 2)
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         // Old version (Version 1)
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         // There's only one internal tm buffer.
01251         struct tm* timep;
01252 
01253         // Convert to Pacific, based on server's opinion of whether
01254         // it's daylight savings time there.
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; // already exists in my list
01271         }
01272         LLInventoryItem* item = LLEmbeddedItems::getEmbeddedItem(ext_char);
01273         if (item)
01274         {
01275                 // Add item to my list and return new llwchar associated with it
01276                 llwchar new_wc;
01277                 if (mEmbeddedItemList->insertEmbeddedItem( item, &new_wc, true ))
01278                 {
01279                         return new_wc;
01280                 }
01281         }
01282         return LL_UNKNOWN_CHAR; // item not found or list full
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         // See if we can bring an existing preview to the front
01373         // *NOTE:  Just for embedded Texture , we should use getAssetUUID(), 
01374         // not getUUID(), because LLPreviewTexture pass in AssetUUID into 
01375         // LLPreview constructor ItemUUID parameter.
01376 
01377         if( !LLPreview::show( item->getAssetUUID() ) )
01378         {
01379                 // There isn't one, so make a new preview
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         // Play sound locally
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         //if (saved)
01422         //{
01423                 // An LLInventoryItem needs to be in an inventory to be opened.
01424                 // This will give the item to the viewer's agent.
01425                 // The callback will attempt to open it if its not already opened.
01426         copyInventory(item, gInventoryCallbacks.registerCB(mInventoryCallback));
01427 
01428         //}
01429         //else
01430         //{
01431         //      LLNotecardCopyInfo *info = new LLNotecardCopyInfo(this, item);
01432         //      gViewerWindow->alertXml("ConfirmNotecardSave",          
01433         //                                                      LLViewerTextEditor::onNotecardDialog, (void*)info);
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 // static
01444 void LLViewerTextEditor::onNotecardDialog( S32 option, void* userdata )
01445 {
01446         LLNotecardCopyInfo *info = (LLNotecardCopyInfo *)userdata;
01447         if( option == 0 )
01448         {
01449                 // itemptr is deleted by LLPreview::save
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 // static
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 // Returns change in number of characters in mWText
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                 // Actually set the text
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         // Get the embedded text and update the item list to just be the used items
01533         nc.setText(getEmbeddedText());
01534 
01535         // Now get the used items and copy the list to the notecard
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         // LLString text = node->getValue();
01565         LLString text = node->getTextContents().substr(0, max_text_length - 1);
01566 
01567         if (text.size() > max_text_length)
01568         {
01569                 // Erase everything from max_text_length on.
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         // add text after all parameters have been set
01601         text_editor->appendStyledText(text, FALSE, FALSE);
01602 
01603         return text_editor;
01604 }

Generated on Fri May 16 08:34:17 2008 for SecondLife by  doxygen 1.5.5