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

Generated on Thu Jul 1 06:09:34 2010 for Second Life Viewer by  doxygen 1.4.7