llinventorybridge.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include <utility> // for std::pair<>
00035 
00036 #include "llinventoryview.h"
00037 #include "llinventorybridge.h"
00038 
00039 #include "message.h"
00040 
00041 #include "llagent.h"
00042 #include "llcallingcard.h"
00043 #include "llcheckboxctrl.h"             // for radio buttons
00044 #include "llradiogroup.h"
00045 #include "llspinctrl.h"
00046 #include "lltextbox.h"
00047 #include "llui.h"
00048 
00049 #include "llviewercontrol.h"
00050 #include "llfirstuse.h"
00051 #include "llfloateravatarinfo.h"
00052 #include "llfloaterchat.h"
00053 #include "llfloatercustomize.h"
00054 #include "llfloaterproperties.h"
00055 #include "llfloaterworldmap.h"
00056 #include "llfocusmgr.h"
00057 #include "llfolderview.h"
00058 #include "llgesturemgr.h"
00059 #include "lliconctrl.h"
00060 #include "llinventorymodel.h"
00061 #include "llinventoryclipboard.h"
00062 #include "lllineeditor.h"
00063 #include "llmenugl.h"
00064 #include "llpreviewanim.h"
00065 #include "llpreviewgesture.h"
00066 #include "llpreviewlandmark.h"
00067 #include "llpreviewnotecard.h"
00068 #include "llpreviewscript.h"
00069 #include "llpreviewsound.h"
00070 #include "llpreviewtexture.h"
00071 #include "llresmgr.h"
00072 #include "llscrollcontainer.h"
00073 #include "llimview.h"
00074 #include "lltooldraganddrop.h"
00075 #include "llviewerimagelist.h"
00076 #include "llviewerinventory.h"
00077 #include "llviewerobjectlist.h"
00078 #include "llviewerwindow.h"
00079 #include "llwearable.h"
00080 #include "llwearablelist.h"
00081 #include "viewer.h"
00082 #include "llviewermessage.h" 
00083 #include "llviewerregion.h"
00084 #include "lltabcontainer.h"
00085 #include "llvieweruictrlfactory.h"
00086 #include "llselectmgr.h"
00087 #include "llfloateropenobject.h"
00088 
00089 // Helpers
00090 // bug in busy count inc/dec right now, logic is complex... do we really need it?
00091 void inc_busy_count()
00092 {
00093 //      gViewerWindow->getWindow()->incBusyCount();
00094 //  check balance of these calls if this code is changed to ever actually
00095 //  *do* something!
00096 }
00097 void dec_busy_count()
00098 {
00099 //      gViewerWindow->getWindow()->decBusyCount();
00100 //  check balance of these calls if this code is changed to ever actually
00101 //  *do* something!
00102 }
00103 
00104 // Function declarations
00105 struct LLWearableHoldingPattern;
00106 void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append);
00107 void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata);
00108 void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*);
00109 void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append);
00110 void remove_inventory_category_from_avatar(LLInventoryCategory* category);
00111 void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata);
00112 void move_task_inventory_callback(S32 option, void* user_data);
00113 void confirm_replace_attachment_rez(S32 option, void* user_data);
00114 
00115 const char* ICON_NAME[ICON_NAME_COUNT] =
00116 {
00117         "inv_item_texture.tga",
00118         "inv_item_sound.tga",
00119         "inv_item_callingcard_online.tga",
00120         "inv_item_callingcard_offline.tga",
00121         "inv_item_landmark.tga",
00122         "inv_item_landmark_visited.tga",
00123         "inv_item_script.tga",
00124         "inv_item_clothing.tga",
00125         "inv_item_object.tga",
00126         "inv_item_object_multi.tga",
00127         "inv_item_notecard.tga",
00128         "inv_item_bodypart.tga",
00129         "inv_item_snapshot.tga",
00130 
00131         "inv_item_shape.tga",
00132         "inv_item_bodypart.tga",
00133         "inv_item_hair.tga",
00134         "inv_item_eyes.tga",
00135         "inv_item_shirt.tga",
00136         "inv_item_pants.tga",
00137         "inv_item_shoes.tga",
00138         "inv_item_socks.tga",
00139         "inv_item_jacket.tga",
00140         "inv_item_gloves.tga",
00141         "inv_item_undershirt.tga",
00142         "inv_item_underpants.tga",
00143         "inv_item_skirt.tga",
00144 
00145         "inv_item_animation.tga",
00146         "inv_item_gesture.tga",
00147 };
00148 
00149 struct LLWearInfo
00150 {
00151         LLUUID  mCategoryID;
00152         BOOL    mAppend;
00153 };
00154 
00155 BOOL gAddToOutfit = FALSE;
00156 
00157 // +=================================================+
00158 // |        LLInvFVBridge                            |
00159 // +=================================================+
00160 
00161 const LLString& LLInvFVBridge::getName() const
00162 {
00163         LLInventoryObject* obj = getInventoryObject();
00164         if(obj)
00165         {
00166                 return obj->getName();
00167         }
00168         return LLString::null;
00169 }
00170 
00171 const LLString& LLInvFVBridge::getDisplayName() const
00172 {
00173         return getName();
00174 }
00175 
00176 // Folders have full perms
00177 PermissionMask LLInvFVBridge::getPermissionMask() const
00178 {
00179 
00180         return PERM_ALL;
00181 }
00182 
00183 // Folders don't have creation dates.
00184 U32 LLInvFVBridge::getCreationDate() const
00185 {
00186         return 0;
00187 }
00188 
00189 // Can be destoryed (or moved to trash)
00190 BOOL LLInvFVBridge::isItemRemovable()
00191 {
00192         LLInventoryModel* model = mInventoryPanel->getModel();
00193         if(!model) return FALSE;
00194         if(model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID()))
00195         {
00196                 return TRUE;
00197         }
00198         return FALSE;
00199 }
00200 
00201 // Can be moved to another folder
00202 BOOL LLInvFVBridge::isItemMovable()
00203 {
00204         return TRUE;
00205 }
00206 
00207 // *TODO: make sure this does the right thing
00208 void LLInvFVBridge::showProperties()
00209 {
00210         LLShowProps::showProperties(mUUID);
00211 }
00212 
00213 void LLInvFVBridge::removeBatch(LLDynamicArray<LLFolderViewEventListener*>& batch)
00214 {
00215         removeBatchNoCheck(batch);
00216 }
00217 
00218 void LLInvFVBridge::removeBatchNoCheck(LLDynamicArray<LLFolderViewEventListener*>& batch)
00219 {
00220         // this method moves a bunch of items and folders to the trash. As
00221         // per design guidelines for the inventory model, the message is
00222         // built and the accounting is performed first. After all of that,
00223         // we call LLInventoryModel::moveObject() to move everything
00224         // around.
00225         LLInvFVBridge* bridge;
00226         LLInventoryModel* model = mInventoryPanel->getModel();
00227         if(!model) return;
00228         LLMessageSystem* msg = gMessageSystem;
00229         LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
00230         LLViewerInventoryItem* item = NULL;
00231         LLViewerInventoryCategory* cat = NULL;
00232         std::vector<LLUUID> move_ids;
00233         LLInventoryModel::update_map_t update;
00234         bool start_new_message = true;
00235         S32 count = batch.count();
00236         S32 i;
00237         for(i = 0; i < count; ++i)
00238         {
00239                 bridge = (LLInvFVBridge*)(batch.get(i));
00240                 if(!bridge || !bridge->isItemRemovable()) continue;
00241                 item = (LLViewerInventoryItem*)model->getItem(bridge->getUUID());
00242                 if(item)
00243                 {
00244                         if(item->getParentUUID() == trash_id) continue;
00245                         move_ids.push_back(item->getUUID());
00246                         LLPreview::hide(item->getUUID());
00247                         --update[item->getParentUUID()];
00248                         ++update[trash_id];
00249                         if(start_new_message)
00250                         {
00251                                 start_new_message = false;
00252                                 msg->newMessageFast(_PREHASH_MoveInventoryItem);
00253                                 msg->nextBlockFast(_PREHASH_AgentData);
00254                                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00255                                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00256                                 msg->addBOOLFast(_PREHASH_Stamp, TRUE);
00257                         }
00258                         msg->nextBlockFast(_PREHASH_InventoryData);
00259                         msg->addUUIDFast(_PREHASH_ItemID, item->getUUID());
00260                         msg->addUUIDFast(_PREHASH_FolderID, trash_id);
00261                         msg->addString("NewName", NULL);
00262                         if(msg->isSendFullFast(_PREHASH_InventoryData))
00263                         {
00264                                 start_new_message = true;
00265                                 gAgent.sendReliableMessage();
00266                                 gInventory.accountForUpdate(update);
00267                                 update.clear();
00268                         }
00269                 }
00270         }
00271         if(!start_new_message)
00272         {
00273                 start_new_message = true;
00274                 gAgent.sendReliableMessage();
00275                 gInventory.accountForUpdate(update);
00276                 update.clear();
00277         }
00278         for(i = 0; i < count; ++i)
00279         {
00280                 bridge = (LLInvFVBridge*)(batch.get(i));
00281                 if(!bridge || !bridge->isItemRemovable()) continue;
00282                 cat = (LLViewerInventoryCategory*)model->getCategory(bridge->getUUID());
00283                 if(cat)
00284                 {
00285                         if(cat->getParentUUID() == trash_id) continue;
00286                         move_ids.push_back(cat->getUUID());
00287                         --update[cat->getParentUUID()];
00288                         ++update[trash_id];
00289                         if(start_new_message)
00290                         {
00291                                 start_new_message = false;
00292                                 msg->newMessageFast(_PREHASH_MoveInventoryFolder);
00293                                 msg->nextBlockFast(_PREHASH_AgentData);
00294                                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00295                                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00296                                 msg->addBOOL("Stamp", TRUE);
00297                         }
00298                         msg->nextBlockFast(_PREHASH_InventoryData);
00299                         msg->addUUIDFast(_PREHASH_FolderID, cat->getUUID());
00300                         msg->addUUIDFast(_PREHASH_ParentID, trash_id);
00301                         if(msg->isSendFullFast(_PREHASH_InventoryData))
00302                         {
00303                                 start_new_message = true;
00304                                 gAgent.sendReliableMessage();
00305                                 gInventory.accountForUpdate(update);
00306                                 update.clear();
00307                         }
00308                 }
00309         }
00310         if(!start_new_message)
00311         {
00312                 gAgent.sendReliableMessage();
00313                 gInventory.accountForUpdate(update);
00314         }
00315 
00316         // move everything.
00317         std::vector<LLUUID>::iterator it = move_ids.begin();
00318         std::vector<LLUUID>::iterator end = move_ids.end();
00319         for(; it != end; ++it)
00320         {
00321                 gInventory.moveObject((*it), trash_id);
00322         }
00323 
00324         // notify inventory observers.
00325         model->notifyObservers();
00326 }
00327 
00328 BOOL LLInvFVBridge::isClipboardPasteable() const
00329 {
00330         LLInventoryModel* model = mInventoryPanel->getModel();
00331         if(!model) return FALSE;
00332         BOOL is_agent_inventory = model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID());
00333 
00334         if(LLInventoryClipboard::instance().hasContents() && is_agent_inventory)
00335         {
00336                 return TRUE;
00337         }
00338         return FALSE;
00339 }
00340 
00341 void hideContextEntries(LLMenuGL& menu, 
00342                                                                            const std::vector<LLString> &entries_to_show,
00343                                                                            const std::vector<LLString> &disabled_entries)
00344 {
00345         const LLView::child_list_t *list = menu.getChildList();
00346 
00347         LLView::child_list_t::const_iterator itor;
00348         for (itor = list->begin(); itor != list->end(); ++itor)
00349         {
00350                 LLString name = (*itor)->getName();
00351 
00352                 // descend into split menus:
00353                 if ((name == "More") && (WIDGET_TYPE_MENU_ITEM_BRANCH == (*itor)->getWidgetType()))
00354                 {
00355                         hideContextEntries(*((LLMenuItemBranchGL *)(*itor))->getBranch(), entries_to_show, disabled_entries);
00356                 }
00357                 
00358                 
00359                 bool found = false;
00360                 std::vector<LLString>::const_iterator itor2;
00361                 for (itor2 = entries_to_show.begin(); itor2 != entries_to_show.end(); ++itor2)
00362                 {
00363                         if (*itor2 == name)
00364                         {
00365                                 found = true;
00366                         }
00367                 }
00368                 if (!found)
00369                 {
00370                         (*itor)->setVisible(FALSE);
00371                 }
00372                 else
00373                 {
00374                         for (itor2 = disabled_entries.begin(); itor2 != disabled_entries.end(); ++itor2)
00375                         {
00376                                 if (*itor2 == name)
00377                                 {
00378                                         (*itor)->setEnabled(FALSE);
00379                                 }
00380                         }
00381                 }
00382         }
00383 }
00384 
00385 // Helper for commonly-used entries
00386 void LLInvFVBridge::getClipboardEntries(bool show_asset_id, std::vector<LLString> &items, 
00387                 std::vector<LLString> &disabled_items, U32 flags)
00388 {
00389         items.push_back("Rename");
00390         if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0)
00391         {
00392                 disabled_items.push_back("Rename");
00393         }
00394 
00395         if (show_asset_id)
00396         {
00397                 items.push_back("Copy Asset UUID");
00398                 if ( (! ( isItemPermissive() || gAgent.isGodlike() ) ) 
00399                           || (flags & FIRST_SELECTED_ITEM) == 0)
00400                 {
00401                         disabled_items.push_back("Copy Asset UUID");
00402                 }
00403         }
00404 
00405         items.push_back("Copy Separator");
00406 
00407         items.push_back("Copy");
00408         if (!isItemCopyable())
00409         {
00410                 disabled_items.push_back("Copy");
00411         }
00412 
00413         items.push_back("Paste");
00414         if (!isClipboardPasteable() || (flags & FIRST_SELECTED_ITEM) == 0)
00415         {
00416                 disabled_items.push_back("Paste");
00417         }
00418 
00419         items.push_back("Paste Separator");
00420 
00421         items.push_back("Delete");
00422         if (!isItemRemovable())
00423         {
00424                 disabled_items.push_back("Delete");
00425         }
00426 }
00427 
00428 void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
00429 {
00430         lldebugs << "LLInvFVBridge::buildContextMenu()" << llendl;
00431         std::vector<LLString> items;
00432         std::vector<LLString> disabled_items;
00433         if(isInTrash())
00434         {
00435                 items.push_back("Purge Item");
00436                 if (!isItemRemovable())
00437                 {
00438                         disabled_items.push_back("Purge Item");
00439                 }
00440                 items.push_back("Restore Item");
00441         }
00442         else
00443         {
00444                 items.push_back("Open");
00445                 items.push_back("Properties");
00446 
00447                 getClipboardEntries(true, items, disabled_items, flags);
00448         }
00449         hideContextEntries(menu, items, disabled_items);
00450 }
00451 
00452 // *TODO: remove this
00453 BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id)
00454 {
00455         BOOL rv = FALSE;
00456 
00457         LLInventoryObject* obj = getInventoryObject();
00458 
00459         if(obj)
00460         {
00461                 *type = LLAssetType::lookupDragAndDropType(obj->getType());
00462                 if(*type == DAD_NONE)
00463                 {
00464                         return FALSE;
00465                 }
00466                 
00467                 *id = obj->getUUID();
00468                 //object_ids.put(obj->getUUID());
00469 
00470                 if (*type == DAD_CATEGORY)
00471                 {
00472                         gInventory.startBackgroundFetch(obj->getUUID());
00473                 }
00474 
00475                 rv = TRUE;
00476         }
00477 
00478         return rv;
00479 }
00480 
00481 LLInventoryObject* LLInvFVBridge::getInventoryObject() const
00482 {
00483         LLInventoryObject* obj = NULL;
00484         LLInventoryModel* model = mInventoryPanel->getModel();
00485         if(model)
00486         {
00487                 obj = (LLInventoryObject*)model->getObject(mUUID);
00488         }
00489         return obj;
00490 }
00491 
00492 BOOL LLInvFVBridge::isInTrash() const
00493 {
00494         LLInventoryModel* model = mInventoryPanel->getModel();
00495         if(!model) return FALSE;
00496         LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
00497         return model->isObjectDescendentOf(mUUID, trash_id);
00498 }
00499 
00500 BOOL LLInvFVBridge::isAgentInventory() const
00501 {
00502         LLInventoryModel* model = mInventoryPanel->getModel();
00503         if(!model) return FALSE;
00504         if(gAgent.getInventoryRootID() == mUUID) return TRUE;
00505         return model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID());
00506 }
00507 
00508 BOOL LLInvFVBridge::isItemPermissive() const
00509 {
00510         return FALSE;
00511 }
00512 
00513 // static
00514 void LLInvFVBridge::changeItemParent(LLInventoryModel* model,
00515                                                                          LLViewerInventoryItem* item,
00516                                                                          const LLUUID& new_parent,
00517                                                                          BOOL restamp)
00518 {
00519         if(item->getParentUUID() != new_parent)
00520         {
00521                 LLInventoryModel::update_list_t update;
00522                 LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1);
00523                 update.push_back(old_folder);
00524                 LLInventoryModel::LLCategoryUpdate new_folder(new_parent, 1);
00525                 update.push_back(new_folder);
00526                 gInventory.accountForUpdate(update);
00527 
00528                 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
00529                 new_item->setParent(new_parent);
00530                 new_item->updateParentOnServer(restamp);
00531                 model->updateItem(new_item);
00532                 model->notifyObservers();
00533         }
00534 }
00535 
00536 // static
00537 void LLInvFVBridge::changeCategoryParent(LLInventoryModel* model,
00538                                                                                  LLViewerInventoryCategory* cat,
00539                                                                                  const LLUUID& new_parent,
00540                                                                                  BOOL restamp)
00541 {
00542         if(cat->getParentUUID() != new_parent)
00543         {
00544                 LLInventoryModel::update_list_t update;
00545                 LLInventoryModel::LLCategoryUpdate old_folder(cat->getParentUUID(), -1);
00546                 update.push_back(old_folder);
00547                 LLInventoryModel::LLCategoryUpdate new_folder(new_parent, 1);
00548                 update.push_back(new_folder);
00549                 gInventory.accountForUpdate(update);
00550 
00551                 LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
00552                 new_cat->setParent(new_parent);
00553                 new_cat->updateParentOnServer(restamp);
00554                 model->updateCategory(new_cat);
00555                 model->notifyObservers();
00556         }
00557 }
00558 
00559 
00560 const char* safe_inv_type_lookup(LLInventoryType::EType inv_type)
00561 {
00562         const char* rv = LLInventoryType::lookup(inv_type);
00563         if(!rv)
00564         {
00565                 const char* INVALID_TYPE = "<invalid>";
00566                 rv = INVALID_TYPE;
00567         }
00568         return rv;
00569 }
00570 
00571 LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
00572                                            LLInventoryType::EType inv_type,
00573                                            LLInventoryPanel* inventory,
00574                                            const LLUUID& uuid,
00575                                            U32 flags)
00576 {
00577         LLInvFVBridge* new_listener = NULL;
00578         switch(asset_type)
00579         {
00580         case LLAssetType::AT_TEXTURE:
00581                 if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT))
00582                 {
00583                         llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
00584                 }
00585                 new_listener = new LLTextureBridge(inventory, uuid, inv_type);
00586                 break;
00587 
00588         case LLAssetType::AT_SOUND:
00589                 if(!(inv_type == LLInventoryType::IT_SOUND))
00590                 {
00591                         llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
00592                 }
00593                 new_listener = new LLSoundBridge(inventory, uuid);
00594                 break;
00595 
00596         case LLAssetType::AT_LANDMARK:
00597                 if(!(inv_type == LLInventoryType::IT_LANDMARK))
00598                 {
00599                         llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
00600                 }
00601                 new_listener = new LLLandmarkBridge(inventory, uuid, flags);
00602                 break;
00603                 
00604         case LLAssetType::AT_CALLINGCARD:
00605                 if(!(inv_type == LLInventoryType::IT_CALLINGCARD))
00606                 {
00607                         llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
00608                 }
00609                 new_listener = new LLCallingCardBridge(inventory, uuid);
00610                 break;
00611 
00612         case LLAssetType::AT_SCRIPT:
00613                 if(!(inv_type == LLInventoryType::IT_LSL))
00614                 {
00615                         llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
00616                 }
00617                 new_listener = new LLScriptBridge(inventory, uuid);
00618                 break;
00619 
00620         case LLAssetType::AT_OBJECT:
00621                 if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT))
00622                 {
00623                         llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
00624                 }
00625                 new_listener = new LLObjectBridge(inventory, uuid, inv_type, flags);
00626                 break;
00627 
00628         case LLAssetType::AT_NOTECARD:
00629                 if(!(inv_type == LLInventoryType::IT_NOTECARD))
00630                 {
00631                         llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
00632                 }
00633                 new_listener = new LLNotecardBridge(inventory, uuid);
00634                 break;
00635 
00636         case LLAssetType::AT_ANIMATION:
00637                 if(!(inv_type == LLInventoryType::IT_ANIMATION))
00638                 {
00639                         llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
00640                 }
00641                 new_listener = new LLAnimationBridge(inventory, uuid);
00642                 break;
00643 
00644         case LLAssetType::AT_GESTURE:
00645                 if(!(inv_type == LLInventoryType::IT_GESTURE))
00646                 {
00647                         llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
00648                 }
00649                 new_listener = new LLGestureBridge(inventory, uuid);
00650                 break;
00651 
00652         case LLAssetType::AT_LSL_TEXT:
00653                 if(!(inv_type == LLInventoryType::IT_LSL))
00654                 {
00655                         llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
00656                 }
00657                 new_listener = new LLLSLTextBridge(inventory, uuid);
00658                 break;
00659 
00660         case LLAssetType::AT_CLOTHING:
00661         case LLAssetType::AT_BODYPART:
00662                 if(!(inv_type == LLInventoryType::IT_WEARABLE))
00663                 {
00664                         llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
00665                 }
00666                 new_listener = new LLWearableBridge(inventory, uuid, asset_type, inv_type, (EWearableType)flags);
00667                 break;
00668 
00669         case LLAssetType::AT_CATEGORY:
00670         case LLAssetType::AT_ROOT_CATEGORY:
00671                 new_listener = new LLFolderBridge(inventory, uuid);
00672                 break;
00673                 
00674         default:
00675                 llinfos << "Unhandled asset type (llassetstorage.h): "
00676                                 << (S32)asset_type << llendl;
00677                 break;
00678         }
00679 
00680         if (new_listener)
00681         {
00682                 new_listener->mInvType = inv_type;
00683         }
00684 
00685         return new_listener;
00686 }
00687 
00688 // +=================================================+
00689 // |        LLItemBridge                             |
00690 // +=================================================+
00691 
00692 void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
00693 {
00694         if ("open" == action)
00695         {
00696                 openItem();
00697         }
00698         else if ("properties" == action)
00699         {
00700                 showProperties();
00701         }
00702         else if ("purge" == action)
00703         {
00704                 LLInventoryCategory* cat = model->getCategory(mUUID);
00705                 if(cat)
00706                 {
00707                         model->purgeDescendentsOf(mUUID);
00708                 }
00709                 LLInventoryObject* obj = model->getObject(mUUID);
00710                 if(!obj) return;
00711                 obj->removeFromServer();
00712                 LLPreview::hide(mUUID);
00713                 model->deleteObject(mUUID);
00714                 model->notifyObservers();
00715         }
00716         else if ("restore" == action)
00717         {
00718                 restoreItem();
00719         }
00720         else if ("copy_uuid" == action)
00721         {
00722                 // Single item only
00723                 LLInventoryItem* item = model->getItem(mUUID);
00724                 if(!item) return;
00725                 LLUUID asset_id = item->getAssetUUID();
00726                 char buffer[UUID_STR_LENGTH];           /*Flawfinder: ignore*/
00727                 asset_id.toString(buffer);
00728 
00729                 gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(buffer));
00730                 return;
00731         }
00732         else if ("copy" == action)
00733         {
00734                 copyToClipboard();
00735                 return;
00736         }
00737         else if ("paste" == action)
00738         {
00739                 // Single item only
00740                 LLInventoryItem* itemp = model->getItem(mUUID);
00741                 if (!itemp) return;
00742 
00743                 LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID());
00744                 if (!folder_view_itemp) return;
00745 
00746                 folder_view_itemp->getListener()->pasteFromClipboard();
00747                 return;
00748         }
00749 }
00750 
00751 void LLItemBridge::selectItem()
00752 {
00753         LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem();
00754         if(item && !item->isComplete())
00755         {
00756                 item->fetchFromServer();
00757         }
00758 }
00759 
00760 void LLItemBridge::restoreItem()
00761 {
00762         LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem();
00763         if(item)
00764         {
00765                 LLInventoryModel* model = mInventoryPanel->getModel();
00766                 LLUUID new_parent = model->findCategoryUUIDForType(item->getType());
00767                 // do not restamp on restore.
00768                 LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE);
00769         }
00770 }
00771 
00772 LLViewerImage* LLItemBridge::getIcon() const
00773 {
00774         LLString uuid_string = gViewerArt.getString(ICON_NAME[OBJECT_ICON_NAME]);
00775         return gImageList.getImage(LLUUID(uuid_string), MIPMAP_FALSE, TRUE);
00776 }
00777 
00778 PermissionMask LLItemBridge::getPermissionMask() const
00779 {
00780         LLViewerInventoryItem* item = getItem();
00781         PermissionMask perm_mask = 0;
00782         if(item) 
00783         {
00784                 BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
00785                 BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
00786                 BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
00787                                                                                                                         gAgent.getID());
00788 
00789                 if (copy) perm_mask |= PERM_COPY;
00790                 if (mod)  perm_mask |= PERM_MODIFY;
00791                 if (xfer) perm_mask |= PERM_TRANSFER;
00792 
00793         }
00794         return perm_mask;
00795 }
00796         
00797 const LLString& LLItemBridge::getDisplayName() const
00798 {
00799         if(mDisplayName.empty())
00800         {
00801                 buildDisplayName(getItem(), mDisplayName);
00802         }
00803         return mDisplayName;
00804 }
00805 
00806 void LLItemBridge::buildDisplayName(LLInventoryItem* item, LLString& name)
00807 {
00808         if(item) 
00809         {
00810                 name.assign(item->getName());                   
00811         }
00812         else
00813         {
00814                 name.assign(LLString::null);
00815         }
00816 }
00817 
00818 LLString LLItemBridge::getLabelSuffix() const
00819 {
00820         LLString suffix;
00821         LLInventoryItem* item = getItem();
00822         if(item) 
00823         {
00824                 // it's a bit confusing to put nocopy/nomod/etc on calling cards.
00825                 if(LLAssetType::AT_CALLINGCARD != item->getType()
00826                    && item->getPermissions().getOwner() == gAgent.getID())
00827                 {
00828                         BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
00829                         BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID());
00830                         BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER,
00831                                                                                                                                 gAgent.getID());
00832                         const char* EMPTY = "";
00833                         const char* NO_COPY = " (no copy)";
00834                         const char* NO_MOD = " (no modify)";
00835                         const char* NO_XFER = " (no transfer)";
00836                         const char* scopy;
00837                         if(copy) scopy = EMPTY;
00838                         else scopy = NO_COPY;
00839                         const char* smod;
00840                         if(mod) smod = EMPTY;
00841                         else smod = NO_MOD;
00842                         const char* sxfer;
00843                         if(xfer) sxfer = EMPTY;
00844                         else sxfer = NO_XFER;
00845                         char buffer[MAX_STRING];                /*Flawfinder: ignore*/
00846                         snprintf(                                               /* Flawfinder: ignore */
00847                                 buffer,
00848                                 MAX_STRING,
00849                                 "%s%s%s",
00850                                 scopy,
00851                                 smod,
00852                                 sxfer);
00853                         suffix.assign(buffer);
00854                 }
00855         }
00856         return suffix;
00857 }
00858 
00859 U32 LLItemBridge::getCreationDate() const
00860 {
00861         LLViewerInventoryItem* item = getItem();
00862         if (item)
00863         {
00864                 return item->getCreationDate();
00865         }
00866         return 0;
00867 }
00868 
00869 
00870 BOOL LLItemBridge::isItemRenameable() const
00871 {
00872         LLViewerInventoryItem* item = getItem();
00873         if(item)
00874         {
00875                 return (item->getPermissions().allowModifyBy(gAgent.getID()));
00876         }
00877         return FALSE;
00878 }
00879 
00880 BOOL LLItemBridge::renameItem(const LLString& new_name)
00881 {
00882         if(!isItemRenameable()) return FALSE;
00883         LLPreview::rename(mUUID, getPrefix() + new_name);
00884         LLInventoryModel* model = mInventoryPanel->getModel();
00885         if(!model) return FALSE;
00886         LLViewerInventoryItem* item = getItem();
00887         if(item && (item->getName() != new_name))
00888         {
00889                 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
00890                 new_item->rename(new_name);
00891                 buildDisplayName(new_item, mDisplayName);
00892                 new_item->updateServer(FALSE);
00893                 model->updateItem(new_item);
00894                 model->notifyObservers();
00895         }
00896         // return FALSE because we either notified observers (& therefore
00897         // rebuilt) or we didn't update.
00898         return FALSE;
00899 }
00900 
00901 
00902 BOOL LLItemBridge::removeItem()
00903 {
00904         if(!isItemRemovable())
00905         {
00906                 return FALSE;
00907         }
00908         // move it to the trash
00909         LLPreview::hide(mUUID, TRUE);
00910         LLInventoryModel* model = mInventoryPanel->getModel();
00911         if(!model) return FALSE;
00912         LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
00913         LLViewerInventoryItem* item = getItem();
00914 
00915         // if item is not already in trash
00916         if(item && !model->isObjectDescendentOf(mUUID, trash_id))
00917         {
00918                 // move to trash, and restamp
00919                 LLInvFVBridge::changeItemParent(model, item, trash_id, TRUE);
00920                 // delete was successful
00921                 return TRUE;
00922         }
00923         else
00924         {
00925                 // tried to delete already item in trash (should purge?)
00926                 return FALSE;
00927         }
00928 }
00929 
00930 BOOL LLItemBridge::isItemCopyable() const
00931 {
00932         LLViewerInventoryItem* item = getItem();
00933         if (item)
00934         {
00935                 return (item->getPermissions().allowCopyBy(gAgent.getID()));
00936         }
00937         return FALSE;
00938 }
00939 BOOL LLItemBridge::copyToClipboard() const
00940 {
00941         if(isItemCopyable())
00942         {
00943                 LLInventoryClipboard::instance().add(mUUID);
00944                 return TRUE;
00945         }
00946         return FALSE;
00947 }
00948 
00949 LLViewerInventoryItem* LLItemBridge::getItem() const
00950 {
00951         LLViewerInventoryItem* item = NULL;
00952         LLInventoryModel* model = mInventoryPanel->getModel();
00953         if(model)
00954         {
00955                 item = (LLViewerInventoryItem*)model->getItem(mUUID);
00956         }
00957         return item;
00958 }
00959 
00960 BOOL LLItemBridge::isItemPermissive() const
00961 {
00962         LLViewerInventoryItem* item = getItem();
00963         if(item)
00964         {
00965                 U32 mask = item->getPermissions().getMaskBase();
00966                 if((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)
00967                 {
00968                         return TRUE;
00969                 }
00970         }
00971         return FALSE;
00972 }
00973 
00974 // +=================================================+
00975 // |        LLFolderBridge                           |
00976 // +=================================================+
00977 
00978 LLFolderBridge* LLFolderBridge::sSelf=NULL;
00979 
00980 // Can be moved to another folder
00981 BOOL LLFolderBridge::isItemMovable()
00982 {
00983         LLInventoryObject* obj = getInventoryObject();
00984         if(obj)
00985         {
00986                 return (LLAssetType::AT_NONE == ((LLInventoryCategory*)obj)->getPreferredType());
00987         }
00988         return FALSE;
00989 }
00990 
00991 void LLFolderBridge::selectItem()
00992 {
00993 }
00994 
00995 
00996 // Can be destroyed (or moved to trash)
00997 BOOL LLFolderBridge::isItemRemovable()
00998 {
00999         LLInventoryModel* model = mInventoryPanel->getModel();
01000         if(!model) 
01001         {
01002                 return FALSE;
01003         }
01004 
01005         if(!model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID()))
01006         {
01007                 return FALSE;
01008         }
01009 
01010         LLVOAvatar* avatar = gAgent.getAvatarObject();
01011         if( !avatar )
01012         {
01013                 return FALSE;
01014         }
01015 
01016         LLInventoryCategory* category = model->getCategory(mUUID);
01017         if( !category )
01018         {
01019                 return FALSE;
01020         }
01021 
01022         if( LLAssetType::AT_NONE != category->getPreferredType() )
01023         {
01024                 return FALSE;
01025         }
01026 
01027         LLInventoryModel::cat_array_t   descendent_categories;
01028         LLInventoryModel::item_array_t  descendent_items;
01029         gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE );
01030 
01031         S32 i;
01032         for( i = 0; i < descendent_categories.count(); i++ )
01033         {
01034                 LLInventoryCategory* category = descendent_categories[i];
01035                 if( LLAssetType::AT_NONE != category->getPreferredType() )
01036                 {
01037                         return FALSE;
01038                 }
01039         }
01040 
01041         for( i = 0; i < descendent_items.count(); i++ )
01042         {
01043                 LLInventoryItem* item = descendent_items[i];
01044                 if( (item->getType() == LLAssetType::AT_CLOTHING) ||
01045                         (item->getType() == LLAssetType::AT_BODYPART) )
01046                 {
01047                         if( gAgent.isWearingItem( item->getUUID() ) )
01048                         {
01049                                 return FALSE;
01050                         }
01051                 }
01052                 else
01053                 if( item->getType() == LLAssetType::AT_OBJECT )
01054                 {
01055                         if( avatar->isWearingAttachment( item->getUUID() ) )
01056                         {
01057                                 return FALSE;
01058                         }
01059                 }
01060         }
01061 
01062         return TRUE;
01063 }
01064 
01065 BOOL LLFolderBridge::isUpToDate() const
01066 {
01067         LLInventoryModel* model = mInventoryPanel->getModel();
01068         if(!model) return FALSE;
01069         LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
01070         if( !category )
01071         {
01072                 return FALSE;
01073         }
01074 
01075         return category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN;
01076 }
01077 
01078 BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
01079                                                                                         BOOL drop)
01080 {
01081         // This should never happen, but if an inventory item is incorrectly parented, 
01082         // the UI will get confused and pass in a NULL.
01083         if(!inv_cat) return FALSE;
01084 
01085         LLInventoryModel* model = mInventoryPanel->getModel();
01086         if(!model) return FALSE;
01087 
01088         LLVOAvatar* avatar = gAgent.getAvatarObject();
01089         if(!avatar) return FALSE;
01090 
01091         // cannot drag into library
01092         if(!isAgentInventory())
01093         {
01094                 return FALSE;
01095         }
01096 
01097         // check to make sure source is agent inventory, and is represented there.
01098         LLToolDragAndDrop::ESource source = gToolDragAndDrop->getSource();
01099         BOOL is_agent_inventory = (model->getCategory(inv_cat->getUUID()) != NULL)
01100                 && (LLToolDragAndDrop::SOURCE_AGENT == source);
01101 
01102         BOOL accept = FALSE;
01103         S32 i;
01104         LLInventoryModel::cat_array_t   descendent_categories;
01105         LLInventoryModel::item_array_t  descendent_items;
01106         if(is_agent_inventory)
01107         {
01108                 const LLUUID& cat_id = inv_cat->getUUID();
01109 
01110                 // Is the destination the trash?
01111                 LLUUID trash_id;
01112                 trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
01113                 BOOL move_is_into_trash = (mUUID == trash_id)
01114                                 || model->isObjectDescendentOf(mUUID, trash_id);
01115                 BOOL is_movable = (LLAssetType::AT_NONE == inv_cat->getPreferredType());
01116                 if( is_movable )
01117                 {
01118                         gInventory.collectDescendents( cat_id, descendent_categories, descendent_items, FALSE );
01119 
01120                         for( i = 0; i < descendent_categories.count(); i++ )
01121                         {
01122                                 LLInventoryCategory* category = descendent_categories[i];
01123                                 if( LLAssetType::AT_NONE != category->getPreferredType() )
01124                                 {
01125                                         // ...can't move "special folders" like Textures
01126                                         is_movable = FALSE;
01127                                         break;
01128                                 }
01129                         }
01130                         
01131                         if( is_movable )
01132                         {
01133                                 if( move_is_into_trash )
01134                                 {
01135                                         for( i = 0; i < descendent_items.count(); i++ )
01136                                         {
01137                                                 LLInventoryItem* item = descendent_items[i];
01138                                                 if( (item->getType() == LLAssetType::AT_CLOTHING) ||
01139                                                         (item->getType() == LLAssetType::AT_BODYPART) )
01140                                                 {
01141                                                         if( gAgent.isWearingItem( item->getUUID() ) )
01142                                                         {
01143                                                                 is_movable = FALSE;  // It's generally movable, but not into the trash!
01144                                                                 break;
01145                                                         }
01146                                                 }
01147                                                 else
01148                                                 if( item->getType() == LLAssetType::AT_OBJECT )
01149                                                 {
01150                                                         if( avatar->isWearingAttachment( item->getUUID() ) )
01151                                                         {
01152                                                                 is_movable = FALSE;  // It's generally movable, but not into the trash!
01153                                                                 break;
01154                                                         }
01155                                                 }
01156                                         }
01157                                 }
01158                         }
01159                 }
01160 
01161                 
01162                 accept =        is_movable
01163                                         && (mUUID != cat_id)                                                            // Can't move a folder into itself
01164                                         && (mUUID != inv_cat->getParentUUID())                          // Avoid moves that would change nothing
01165                                         && !(model->isObjectDescendentOf(mUUID, cat_id));       // Avoid circularity
01166                 if(accept && drop)
01167                 {
01168                         // Look for any gestures and deactivate them
01169                         if (move_is_into_trash)
01170                         {
01171                                 for (i = 0; i < descendent_items.count(); i++)
01172                                 {
01173                                         LLInventoryItem* item = descendent_items[i];
01174                                         if (item->getType() == LLAssetType::AT_GESTURE
01175                                                 && gGestureManager.isGestureActive(item->getUUID()))
01176                                         {
01177                                                 gGestureManager.deactivateGesture(item->getUUID());
01178                                         }
01179                                 }
01180                         }
01181 
01182                         // Reparent the folder and restamp children if it's moving
01183                         // into trash.
01184                         LLInvFVBridge::changeCategoryParent(
01185                                 model,
01186                                 (LLViewerInventoryCategory*)inv_cat,
01187                                 mUUID,
01188                                 move_is_into_trash);
01189                 }
01190         }
01191         else if(LLToolDragAndDrop::SOURCE_WORLD == source)
01192         {
01193                 // content category has same ID as object itself
01194                 LLUUID object_id = inv_cat->getUUID();
01195                 LLUUID category_id = mUUID;
01196                 accept = move_inv_category_world_to_agent(object_id, category_id, drop);
01197         }
01198         return accept;
01199 }
01200 
01201 void warn_move_inventory(LLViewerObject* object, LLMoveInv* move_inv)
01202 {
01203         const char* dialog = NULL;
01204         if (object->flagScripted())
01205         {
01206                 dialog = "MoveInventoryFromScriptedObject";
01207         }
01208         else
01209         {
01210                 dialog = "MoveInventoryFromObject";
01211         }
01212         gViewerWindow->alertXml(dialog, move_task_inventory_callback, move_inv);
01213 }
01214 
01215 // Move/copy all inventory items from the Contents folder of an in-world
01216 // object to the agent's inventory, inside a given category.
01217 BOOL move_inv_category_world_to_agent(const LLUUID& object_id, 
01218                                                                           const LLUUID& category_id,
01219                                                                           BOOL drop,
01220                                                                           void (*callback)(S32, void*),
01221                                                                           void* user_data)
01222 {
01223         // Make sure the object exists. If we allowed dragging from
01224         // anonymous objects, it would be possible to bypass
01225         // permissions.
01226         // content category has same ID as object itself
01227         LLViewerObject* object = gObjectList.findObject(object_id);
01228         if(!object)
01229         {
01230                 llinfos << "Object not found for drop." << llendl;
01231                 return FALSE;
01232         }
01233 
01234         // this folder is coming from an object, as there is only one folder in an object, the root,
01235         // we need to collect the entire contents and handle them as a group
01236         InventoryObjectList inventory_objects;
01237         object->getInventoryContents(inventory_objects);
01238 
01239         if (inventory_objects.empty())
01240         {
01241                 llinfos << "Object contents not found for drop." << llendl;
01242                 return FALSE;
01243         }
01244         
01245         BOOL accept = TRUE;
01246         BOOL is_move = FALSE;
01247 
01248         // coming from a task. Need to figure out if the person can
01249         // move/copy this item.
01250         InventoryObjectList::iterator it = inventory_objects.begin();
01251         InventoryObjectList::iterator end = inventory_objects.end();
01252         for ( ; it != end; ++it)
01253         {
01254                 // coming from a task. Need to figure out if the person can
01255                 // move/copy this item.
01256                 LLPermissions perm(((LLInventoryItem*)((LLInventoryObject*)(*it)))->getPermissions());
01257                 if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID())
01258                         && perm.allowTransferTo(gAgent.getID())))
01259 //                      || gAgent.isGodlike())
01260                 {
01261                         accept = TRUE;
01262                 }
01263                 else if(object->permYouOwner())
01264                 {
01265                         // If the object cannot be copied, but the object the
01266                         // inventory is owned by the agent, then the item can be
01267                         // moved from the task to agent inventory.
01268                         is_move = TRUE;
01269                         accept = TRUE;
01270                 }
01271                 else
01272                 {
01273                         accept = FALSE;
01274                         break;
01275                 }
01276         }
01277 
01278         if(drop && accept)
01279         {
01280                 it = inventory_objects.begin();
01281                 InventoryObjectList::iterator first_it = inventory_objects.begin();
01282                 LLMoveInv* move_inv = new LLMoveInv;
01283                 move_inv->mObjectID = object_id;
01284                 move_inv->mCategoryID = category_id;
01285                 move_inv->mCallback = callback;
01286                 move_inv->mUserData = user_data;
01287 
01288                 for ( ; it != end; ++it)
01289                 {
01290                         two_uuids_t two(category_id, (*it)->getUUID());
01291                         move_inv->mMoveList.push_back(two);
01292                 }
01293 
01294                 if(is_move)
01295                 {
01296                         // Callback called from within here.
01297                         warn_move_inventory(object, move_inv);
01298                 }
01299                 else
01300                 {
01301                         move_task_inventory_callback(0, (void*)(move_inv));
01302                 }
01303         }
01304         return accept;
01305 }
01306 
01307 class LLFindWearables : public LLInventoryCollectFunctor
01308 {
01309 public:
01310         LLFindWearables() {}
01311         virtual ~LLFindWearables() {}
01312         virtual bool operator()(LLInventoryCategory* cat,
01313                                                         LLInventoryItem* item);
01314 };
01315 
01316 bool LLFindWearables::operator()(LLInventoryCategory* cat,
01317                                                                  LLInventoryItem* item)
01318 {
01319         if(item)
01320         {
01321                 if((item->getType() == LLAssetType::AT_CLOTHING)
01322                    || (item->getType() == LLAssetType::AT_BODYPART))
01323                 {
01324                         return TRUE;
01325                 }
01326         }
01327         return FALSE;
01328 }
01329 
01330 //Used by LLFolderBridge as callback for directory recursion.
01331 class LLRightClickInventoryFetchObserver : public LLInventoryFetchObserver
01332 {
01333 public:
01334         LLRightClickInventoryFetchObserver()  {};
01335         LLRightClickInventoryFetchObserver(const LLUUID& cat_id, bool copy_items) :
01336                 mCatID(cat_id),
01337                 mCopyItems(copy_items)
01338                 { };
01339         virtual void done()
01340         {
01341                 // we've downloaded all the items, so repaint the dialog
01342                 LLFolderBridge::staticFolderOptionsMenu();
01343 
01344                 gInventory.removeObserver(this);
01345                 delete this;
01346         }
01347         
01348 
01349 protected:
01350         LLUUID mCatID;
01351         bool mCopyItems;
01352 
01353 };
01354 
01355 //Used by LLFolderBridge as callback for directory recursion.
01356 class LLRightClickInventoryFetchDescendentsObserver : public LLInventoryFetchDescendentsObserver
01357 {
01358 public:
01359         LLRightClickInventoryFetchDescendentsObserver(bool copy_items) : mCopyItems(copy_items) {}
01360         ~LLRightClickInventoryFetchDescendentsObserver() {}
01361         virtual void done();
01362 protected:
01363         bool mCopyItems;
01364 };
01365 
01366 void LLRightClickInventoryFetchDescendentsObserver::done()
01367 {
01368         // Avoid passing a NULL-ref as mCompleteFolders.front() down to
01369         // gInventory.collectDescendents()
01370         if( mCompleteFolders.empty() )
01371         {
01372                 llwarns << "LLRightClickInventoryFetchDescendentsObserver::done with empty mCompleteFolders" << llendl;
01373                 dec_busy_count();
01374                 gInventory.removeObserver(this);
01375                 delete this;
01376                 return;
01377         }
01378 
01379         // What we do here is get the complete information on the items in
01380         // the library, and set up an observer that will wait for that to
01381         // happen.
01382         LLInventoryModel::cat_array_t cat_array;
01383         LLInventoryModel::item_array_t item_array;
01384         gInventory.collectDescendents(mCompleteFolders.front(),
01385                                                                   cat_array,
01386                                                                   item_array,
01387                                                                   LLInventoryModel::EXCLUDE_TRASH);
01388         S32 count = item_array.count();
01389 #if 0 // HACK/TODO: Why?
01390         // This early causes a giant menu to get produced, and doesn't seem to be needed.
01391         if(!count)
01392         {
01393                 llwarns << "Nothing fetched in category " << mCompleteFolders.front()
01394                                 << llendl;
01395                 dec_busy_count();
01396                 gInventory.removeObserver(this);
01397                 delete this;
01398                 return;
01399         }
01400 #endif
01401 
01402         LLRightClickInventoryFetchObserver* outfit;
01403         outfit = new LLRightClickInventoryFetchObserver(mCompleteFolders.front(), mCopyItems);
01404         LLInventoryFetchObserver::item_ref_t ids;
01405         for(S32 i = 0; i < count; ++i)
01406         {
01407                 ids.push_back(item_array.get(i)->getUUID());
01408         }
01409 
01410         // clean up, and remove this as an observer since the call to the
01411         // outfit could notify observers and throw us into an infinite
01412         // loop.
01413         dec_busy_count();
01414         gInventory.removeObserver(this);
01415         delete this;
01416 
01417         // increment busy count and either tell the inventory to check &
01418         // call done, or add this object to the inventory for observation.
01419         inc_busy_count();
01420 
01421         // do the fetch
01422         outfit->fetchItems(ids);
01423         outfit->done();                         //Not interested in waiting and this will be right 99% of the time.
01424 //Uncomment the following code for laggy Inventory UI.
01425 /*      if(outfit->isEverythingComplete())
01426         {
01427                 // everything is already here - call done.
01428                 outfit->done();
01429         }
01430         else
01431         {
01432                 // it's all on it's way - add an observer, and the inventory
01433                 // will call done for us when everything is here.
01434                 gInventory.addObserver(outfit);
01435         }*/
01436 }
01437 
01438 
01439 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01440 // Class LLInventoryWearObserver
01441 //
01442 // Observer for "copy and wear" operation to support knowing 
01443 // when the all of the contents have been added to inventory.
01444 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01445 class LLInventoryCopyAndWearObserver : public LLInventoryObserver
01446 {
01447 public:
01448         LLInventoryCopyAndWearObserver(const LLUUID& cat_id, int count) :mCatID(cat_id), mContentsCount(count), mFolderAdded(FALSE) {}
01449         virtual ~LLInventoryCopyAndWearObserver() {}
01450         virtual void changed(U32 mask);
01451 
01452 protected:
01453         LLUUID mCatID;
01454         int    mContentsCount;
01455         BOOL   mFolderAdded;
01456 };
01457 
01458 
01459 
01460 void LLInventoryCopyAndWearObserver::changed(U32 mask)
01461 {
01462         if((mask & (LLInventoryObserver::ADD)) != 0)
01463         {
01464                 if (!mFolderAdded) 
01465                 {
01466                         const std::set<LLUUID>& changed_items = gInventory.getChangedIDs();
01467 
01468                         std::set<LLUUID>::const_iterator id_it = changed_items.begin();
01469                         std::set<LLUUID>::const_iterator id_end = changed_items.end();
01470                         for (;id_it != id_end; ++id_it)
01471                         {
01472                                 if ((*id_it) == mCatID) 
01473                                 {
01474                                         mFolderAdded = TRUE;
01475                                         break;
01476                                 }
01477                         }
01478                 }
01479 
01480                 if (mFolderAdded) 
01481                 {
01482                         LLViewerInventoryCategory* category = gInventory.getCategory(mCatID);
01483 
01484                         if (NULL == category)
01485                         {
01486                                 llwarns << "gInventory.getCategory(" << mCatID
01487                                         << ") was NULL" << llendl;
01488                         }
01489                         else
01490                         {
01491                                 if (category->getDescendentCount() ==
01492                                     mContentsCount)
01493                                 {
01494                                         gInventory.removeObserver(this);
01495                                         wear_inventory_category(category, FALSE, TRUE);
01496                                         delete this;
01497                                 }
01498                         }               
01499                 }
01500 
01501         }
01502 }
01503 
01504 
01505 
01506 void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
01507 {
01508         if ("open" == action)
01509         {
01510                 openItem();
01511         }
01512         else if ("paste" == action)
01513         {
01514                 pasteFromClipboard();
01515         }
01516         else if ("properties" == action)
01517         {
01518                 showProperties();
01519         }
01520         else if ("replaceoutfit" == action)
01521         {
01522                 modifyOutfit(FALSE);
01523         }
01524         else if ("addtooutfit" == action)
01525         {
01526                 modifyOutfit(TRUE);
01527         }
01528         else if ("removefromoutfit" == action)
01529         {
01530                 LLInventoryModel* model = mInventoryPanel->getModel();
01531                 if(!model) return;
01532                 LLViewerInventoryCategory* cat = getCategory();
01533                 if(!cat) return;
01534                 
01535                 remove_inventory_category_from_avatar ( cat );
01536         }       
01537         else if ("purge" == action)
01538         {               
01539                 LLViewerInventoryCategory* cat;
01540                 cat = (LLViewerInventoryCategory*)getCategory();
01541 
01542                 if(cat)
01543                 {
01544                         model->purgeDescendentsOf(mUUID);
01545                 }
01546                 LLInventoryObject* obj = model->getObject(mUUID);
01547                 if(!obj) return;
01548                 obj->removeFromServer();
01549                 model->deleteObject(mUUID);
01550                 model->notifyObservers();
01551         }
01552         else if ("restore" == action)
01553         {
01554                 restoreItem();
01555         }
01556 }
01557 
01558 void LLFolderBridge::openItem()
01559 {
01560         lldebugs << "LLFolderBridge::openItem()" << llendl;
01561         LLInventoryModel* model = mInventoryPanel->getModel();
01562         if(!model) return;
01563         model->fetchDescendentsOf(mUUID);
01564 }
01565 
01566 BOOL LLFolderBridge::isItemRenameable() const
01567 {
01568         LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)getCategory();
01569         if(cat && (cat->getPreferredType() == LLAssetType::AT_NONE)
01570            && (cat->getOwnerID() == gAgent.getID()))
01571         {
01572                 return TRUE;
01573         }
01574         return FALSE;
01575 }
01576 
01577 void LLFolderBridge::restoreItem()
01578 {
01579         LLViewerInventoryCategory* cat;
01580         cat = (LLViewerInventoryCategory*)getCategory();
01581         if(cat)
01582         {
01583                 LLInventoryModel* model = mInventoryPanel->getModel();
01584                 LLUUID new_parent = model->findCategoryUUIDForType(cat->getType());
01585                 // do not restamp children on restore
01586                 LLInvFVBridge::changeCategoryParent(model, cat, new_parent, FALSE);
01587         }
01588 }
01589 
01590 // Icons for folders are based on the preferred type
01591 LLViewerImage* LLFolderBridge::getIcon() const
01592 {
01593         const char* control = NULL;
01594         LLAssetType::EType preferred_type = LLAssetType::AT_NONE;
01595         LLViewerInventoryCategory* cat = getCategory();
01596         if(cat)
01597         {
01598                 preferred_type = cat->getPreferredType();
01599         }
01600         switch(preferred_type)
01601         {
01602         case LLAssetType::AT_TEXTURE:
01603                 control = "inv_folder_texture.tga";
01604                 break;
01605         case LLAssetType::AT_SOUND:
01606                 control = "inv_folder_sound.tga";
01607                 break;
01608         case LLAssetType::AT_CALLINGCARD:
01609                 control = "inv_folder_callingcard.tga";
01610                 break;
01611         case LLAssetType::AT_LANDMARK:
01612                 control = "inv_folder_landmark.tga";
01613                 break;
01614         case LLAssetType::AT_SCRIPT:
01615         case LLAssetType::AT_LSL_TEXT:
01616                 control = "inv_folder_script.tga";
01617                 break;
01618         case LLAssetType::AT_OBJECT:
01619                 control = "inv_folder_object.tga";
01620                 break;
01621         case LLAssetType::AT_NOTECARD:
01622                 control = "inv_folder_notecard.tga";
01623                 break;
01624         case LLAssetType::AT_CATEGORY:
01625                 control = "inv_folder_plain_closed.tga";
01626                 break;
01627         case LLAssetType::AT_CLOTHING:
01628                 control = "inv_folder_clothing.tga";
01629                 break;
01630         case LLAssetType::AT_BODYPART:
01631                 control = "inv_folder_bodypart.tga";
01632                 break;
01633         case LLAssetType::AT_TRASH:
01634                 control = "inv_folder_trash.tga";
01635                 break;
01636         case LLAssetType::AT_SNAPSHOT_CATEGORY:
01637                 control = "inv_folder_snapshot.tga";
01638                 break;
01639         case LLAssetType::AT_LOST_AND_FOUND:
01640                 control = "inv_folder_lostandfound.tga";
01641                 break;
01642         case LLAssetType::AT_ANIMATION:
01643                 control = "inv_folder_animation.tga";
01644                 break;
01645         case LLAssetType::AT_GESTURE:
01646                 control = "inv_folder_gesture.tga";
01647                 break;
01648         default:
01649                 control = "inv_folder_plain_closed.tga";
01650                 break;
01651         }
01652         LLString uuid_string = gViewerArt.getString(control);
01653         return gImageList.getImage(LLUUID(uuid_string), MIPMAP_FALSE, TRUE);
01654 }
01655 
01656 BOOL LLFolderBridge::renameItem(const LLString& new_name)
01657 {
01658         if(!isItemRenameable()) return FALSE;
01659         LLInventoryModel* model = mInventoryPanel->getModel();
01660         if(!model) return FALSE;
01661         LLViewerInventoryCategory* cat = getCategory();
01662         if(cat && (cat->getName() != new_name))
01663         {
01664                 LLPointer<LLViewerInventoryCategory> new_cat = new LLViewerInventoryCategory(cat);
01665                 new_cat->rename(new_name);
01666                 new_cat->updateServer(FALSE);
01667                 model->updateCategory(new_cat);
01668                 model->notifyObservers();
01669         }
01670         // return FALSE because we either notified observers (& therefore
01671         // rebuilt) or we didn't update.
01672         return FALSE;
01673 }
01674 
01675 BOOL LLFolderBridge::removeItem()
01676 {
01677         if(!isItemRemovable())
01678         {
01679                 return FALSE;
01680         }
01681         // move it to the trash
01682         LLPreview::hide(mUUID);
01683         LLInventoryModel* model = mInventoryPanel->getModel();
01684         if(!model) return FALSE;
01685 
01686         LLUUID trash_id;
01687         trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
01688 
01689         // Look for any gestures and deactivate them
01690         LLInventoryModel::cat_array_t   descendent_categories;
01691         LLInventoryModel::item_array_t  descendent_items;
01692         gInventory.collectDescendents( mUUID, descendent_categories, descendent_items, FALSE );
01693 
01694         S32 i;
01695         for (i = 0; i < descendent_items.count(); i++)
01696         {
01697                 LLInventoryItem* item = descendent_items[i];
01698                 if (item->getType() == LLAssetType::AT_GESTURE
01699                         && gGestureManager.isGestureActive(item->getUUID()))
01700                 {
01701                         gGestureManager.deactivateGesture(item->getUUID());
01702                 }
01703         }
01704 
01705         // go ahead and do the normal remove if no 'last calling
01706         // cards' are being removed.
01707         LLViewerInventoryCategory* cat = getCategory();
01708         if(cat)
01709         {
01710                 LLInvFVBridge::changeCategoryParent(model, cat, trash_id, TRUE);
01711         }
01712 
01713         return TRUE;
01714 }
01715 
01716 BOOL LLFolderBridge::isClipboardPasteable() const
01717 {
01718         if(LLInventoryClipboard::instance().hasContents() && isAgentInventory())
01719         {
01720                 return TRUE;
01721         }
01722         return FALSE;
01723 }
01724 
01725 void LLFolderBridge::pasteFromClipboard()
01726 {
01727         LLInventoryModel* model = mInventoryPanel->getModel();
01728         if(model && isClipboardPasteable())
01729         {
01730                 LLInventoryItem* item = NULL;
01731                 LLDynamicArray<LLUUID> objects;
01732                 LLInventoryClipboard::instance().retrieve(objects);
01733                 S32 count = objects.count();
01734                 LLUUID parent_id(mUUID);
01735                 for(S32 i = 0; i < count; i++)
01736                 {
01737                         item = model->getItem(objects.get(i));
01738                         if (item)
01739                         {
01740                                 copy_inventory_item(
01741                                         gAgent.getID(),
01742                                         item->getPermissions().getOwner(),
01743                                         item->getUUID(),
01744                                         parent_id,
01745                                         std::string(),
01746                                         LLPointer<LLInventoryCallback>(NULL));
01747                         }
01748                 }
01749         }
01750 }
01751 
01752 void LLFolderBridge::staticFolderOptionsMenu()
01753 {
01754         if (!sSelf) return;
01755         sSelf->folderOptionsMenu();
01756 }
01757 
01758 void LLFolderBridge::folderOptionsMenu()
01759 {
01760         std::vector<LLString> disabled_items;
01761 
01762         LLInventoryModel* model = mInventoryPanel->getModel();
01763         if(!model) return;
01764         
01765         // calling card related functionality for folders.
01766 
01767         LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
01768         if (mCallingCards || checkFolderForContentsOfType(model, is_callingcard))
01769         {
01770                 mItems.push_back("Calling Card Separator");
01771                 mItems.push_back("Conference Chat Folder");
01772                 mItems.push_back("IM All Contacts In Folder");
01773         }
01774         
01775         // wearables related functionality for folders.
01776         //is_wearable
01777         LLFindWearables is_wearable;
01778         LLIsType is_object( LLAssetType::AT_OBJECT );
01779         LLIsType is_gesture( LLAssetType::AT_GESTURE );
01780 
01781         if (mWearables ||
01782                 checkFolderForContentsOfType(model, is_wearable)  ||
01783                 checkFolderForContentsOfType(model, is_object) ||
01784                 checkFolderForContentsOfType(model, is_gesture) )
01785         {
01786                 mItems.push_back("Folder Wearables Separator");
01787 
01788                 // Only enable add/replace outfit for non-default folders.
01789                 const LLInventoryCategory* category = model->getCategory(mUUID);
01790                 if (!category || (LLAssetType::AT_NONE == category->getPreferredType()))
01791                 {
01792                         mItems.push_back("Add To Outfit");
01793                         mItems.push_back("Replace Outfit");
01794                 }
01795                 mItems.push_back("Take Off Items");
01796         }
01797         hideContextEntries(*mMenu, mItems, disabled_items);
01798 }
01799 
01800 BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type)
01801 {
01802         LLInventoryModel::cat_array_t cat_array;
01803         LLInventoryModel::item_array_t item_array;
01804         model->collectDescendentsIf(mUUID,
01805                                                                 cat_array,
01806                                                                 item_array,
01807                                                                 LLInventoryModel::EXCLUDE_TRASH,
01808                                                                 is_type);
01809         return ((item_array.count() > 0) ? TRUE : FALSE );
01810 }
01811 
01812 // Flags unused
01813 void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
01814 {
01815         lldebugs << "LLFolderBridge::buildContextMenu()" << llendl;
01816 //      std::vector<LLString> disabled_items;
01817         LLInventoryModel* model = mInventoryPanel->getModel();
01818         if(!model) return;
01819         LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
01820         LLUUID lost_and_found_id = model->findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND);
01821 
01822         if (lost_and_found_id == mUUID)
01823           {
01824                 // This is the lost+found folder.
01825                 mItems.push_back("Empty Lost And Found");
01826           }
01827 
01828         if(trash_id == mUUID)
01829         {
01830                 // This is the trash.
01831                 mItems.push_back("Empty Trash");
01832         }
01833         else if(model->isObjectDescendentOf(mUUID, trash_id))
01834         {
01835                 // This is a folder in the trash.
01836                 mItems.clear(); // clear any items that used to exist
01837                 mItems.push_back("Purge Item");
01838                 if (!isItemRemovable())
01839                 {
01840                         mDisabledItems.push_back("Purge Item");
01841                 }
01842 
01843                 mItems.push_back("Restore Item");
01844         }
01845         else if(isAgentInventory()) // do not allow creating in library
01846         {
01847                         // only mature accounts can create undershirts/underwear
01848                         /*if (!gAgent.isTeen())
01849                         {
01850                                 sub_menu->append(new LLMenuItemCallGL("New Undershirt",
01851                                                                                                         &createNewUndershirt,
01852                                                                                                         NULL,
01853                                                                                                         (void*)this));
01854                                 sub_menu->append(new LLMenuItemCallGL("New Underpants",
01855                                                                                                         &createNewUnderpants,
01856                                                                                                         NULL,
01857                                                                                                         (void*)this));
01858                         }*/
01859 
01860 /*              BOOL contains_calling_cards = FALSE;
01861                 LLInventoryModel::cat_array_t cat_array;
01862                 LLInventoryModel::item_array_t item_array;
01863 
01864                 LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
01865                 model->collectDescendentsIf(mUUID,
01866                                                                         cat_array,
01867                                                                         item_array,
01868                                                                         LLInventoryModel::EXCLUDE_TRASH,
01869                                                                         is_callingcard);
01870                 if(item_array.count() > 0) contains_calling_cards = TRUE;
01871 */
01872                 mItems.push_back("New Folder");
01873                 mItems.push_back("New Script");
01874                 mItems.push_back("New Note");
01875                 mItems.push_back("New Gesture");
01876                 mItems.push_back("New Clothes");
01877                 mItems.push_back("New Body Parts");
01878 
01879                 getClipboardEntries(false, mItems, mDisabledItems, flags);
01880 
01881                 //Added by spatters to force inventory pull on right-click to display folder options correctly. 07-17-06
01882                 mCallingCards = mWearables = FALSE;
01883 
01884                 LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD);
01885                 if (checkFolderForContentsOfType(model, is_callingcard))
01886                 {
01887                         mCallingCards=TRUE;
01888                 }
01889                 
01890                 LLFindWearables is_wearable;
01891                 LLIsType is_object( LLAssetType::AT_OBJECT );
01892                 LLIsType is_gesture( LLAssetType::AT_GESTURE );
01893 
01894                 if (checkFolderForContentsOfType(model, is_wearable)  ||
01895                         checkFolderForContentsOfType(model, is_object) ||
01896                         checkFolderForContentsOfType(model, is_gesture) )
01897                 {
01898                         mWearables=TRUE;
01899                 }
01900                 
01901                 mMenu = &menu;
01902                 sSelf = this;
01903                 LLRightClickInventoryFetchDescendentsObserver* fetch = new LLRightClickInventoryFetchDescendentsObserver(FALSE);
01904 
01905                 LLInventoryFetchDescendentsObserver::folder_ref_t folders;
01906                 LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID);
01907                 folders.push_back(category->getUUID());
01908                 fetch->fetchDescendents(folders);
01909                 inc_busy_count();
01910                 if(fetch->isEverythingComplete())
01911                 {
01912                         // everything is already here - call done.
01913                         fetch->done();
01914                 }
01915                 else
01916                 {
01917                         // it's all on it's way - add an observer, and the inventory
01918                         // will call done for us when everything is here.
01919                         gInventory.addObserver(fetch);
01920                 }
01921         }
01922         else
01923         {
01924                 mItems.push_back("--no options--");
01925                 mDisabledItems.push_back("--no options--");
01926         }
01927         hideContextEntries(menu, mItems, mDisabledItems);
01928 }
01929 
01930 BOOL LLFolderBridge::hasChildren() const
01931 {
01932         LLInventoryModel* model = mInventoryPanel->getModel();
01933         if(!model) return FALSE;
01934         LLInventoryModel::EHasChildren has_children;
01935         has_children = gInventory.categoryHasChildren(mUUID);
01936         return has_children != LLInventoryModel::CHILDREN_NO;
01937 }
01938 
01939 BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
01940                                                                 EDragAndDropType cargo_type,
01941                                                                 void* cargo_data)
01942 {
01943         //llinfos << "LLFolderBridge::dragOrDrop()" << llendl;
01944         BOOL accept = FALSE;
01945         switch(cargo_type)
01946         {
01947         case DAD_TEXTURE:
01948         case DAD_SOUND:
01949         case DAD_CALLINGCARD:
01950         case DAD_LANDMARK:
01951         case DAD_SCRIPT:
01952         case DAD_OBJECT:
01953         case DAD_NOTECARD:
01954         case DAD_CLOTHING:
01955         case DAD_BODYPART:
01956         case DAD_ANIMATION:
01957         case DAD_GESTURE:
01958                 accept = dragItemIntoFolder((LLInventoryItem*)cargo_data,
01959                                                                         drop);
01960                 break;
01961         case DAD_CATEGORY:
01962                 accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data,
01963                                                                                 drop);
01964                 break;
01965         default:
01966                 break;
01967         }
01968         return accept;
01969 }
01970 
01971 LLViewerInventoryCategory* LLFolderBridge::getCategory() const
01972 {
01973         LLViewerInventoryCategory* cat = NULL;
01974         LLInventoryModel* model = mInventoryPanel->getModel();
01975         if(model)
01976         {
01977                 cat = (LLViewerInventoryCategory*)model->getCategory(mUUID);
01978         }
01979         return cat;
01980 }
01981 
01982 
01983 // static
01984 void LLFolderBridge::pasteClipboard(void* user_data)
01985 {
01986         LLFolderBridge* self = (LLFolderBridge*)user_data;
01987         if(self) self->pasteFromClipboard();
01988 }
01989 
01990 void LLFolderBridge::createNewCategory(void* user_data)
01991 {
01992         LLFolderBridge* bridge = (LLFolderBridge*)user_data;
01993         if(!bridge) return;
01994         LLInventoryPanel* panel = bridge->mInventoryPanel;
01995         LLInventoryModel* model = panel->getModel();
01996         if(!model) return;
01997         LLUUID id;
01998         id = model->createNewCategory(bridge->getUUID(),
01999                                                                   LLAssetType::AT_NONE,
02000                                                                   NULL);
02001         model->notifyObservers();
02002 
02003         // At this point, the bridge has probably been deleted, but the
02004         // view is still there.
02005         panel->setSelection(id, TAKE_FOCUS_YES);
02006 }
02007 
02008 void LLFolderBridge::createNewShirt(void* user_data)
02009 {
02010         LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHIRT);
02011 }
02012 
02013 void LLFolderBridge::createNewPants(void* user_data)
02014 {
02015         LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_PANTS);
02016 }
02017 
02018 void LLFolderBridge::createNewShoes(void* user_data)
02019 {
02020         LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHOES);
02021 }
02022 
02023 void LLFolderBridge::createNewSocks(void* user_data)
02024 {
02025         LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SOCKS);
02026 }
02027 
02028 void LLFolderBridge::createNewJacket(void* user_data)
02029 {
02030         LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_JACKET);
02031 }
02032 
02033 void LLFolderBridge::createNewSkirt(void* user_data)
02034 {
02035         LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIRT);
02036 }
02037 
02038 void LLFolderBridge::createNewGloves(void* user_data)
02039 {
02040         LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_GLOVES);
02041 }
02042 
02043 void LLFolderBridge::createNewUndershirt(void* user_data)
02044 {
02045         LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERSHIRT);
02046 }
02047 
02048 void LLFolderBridge::createNewUnderpants(void* user_data)
02049 {
02050         LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_UNDERPANTS);
02051 }
02052 
02053 void LLFolderBridge::createNewShape(void* user_data)
02054 {
02055         LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SHAPE);
02056 }
02057 
02058 void LLFolderBridge::createNewSkin(void* user_data)
02059 {
02060         LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_SKIN);
02061 }
02062 
02063 void LLFolderBridge::createNewHair(void* user_data)
02064 {
02065         LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_HAIR);
02066 }
02067 
02068 void LLFolderBridge::createNewEyes(void* user_data)
02069 {
02070         LLFolderBridge::createWearable((LLFolderBridge*)user_data, WT_EYES);
02071 }
02072 
02073 // static
02074 void LLFolderBridge::createWearable(LLFolderBridge* bridge, EWearableType type)
02075 {
02076         if(!bridge) return;
02077         LLUUID parent_id = bridge->getUUID();
02078         createWearable(parent_id, type);
02079 }
02080 
02081 // Separate function so can be called by global menu as well as right-click
02082 // menu.
02083 // static
02084 void LLFolderBridge::createWearable(LLUUID parent_id, EWearableType type)
02085 {
02086         LLWearable* wearable = gWearableList.createNewWearable(type);
02087         LLAssetType::EType asset_type = wearable->getAssetType();
02088         LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE;
02089         create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
02090                 parent_id, wearable->getTransactionID(), wearable->getName(),
02091                 wearable->getDescription(), asset_type, inv_type, wearable->getType(),
02092                 wearable->getPermissions().getMaskNextOwner(),
02093                 LLPointer<LLInventoryCallback>(NULL));
02094 }
02095 
02096 void LLFolderBridge::modifyOutfit(BOOL append)
02097 {
02098         LLInventoryModel* model = mInventoryPanel->getModel();
02099         if(!model) return;
02100         LLViewerInventoryCategory* cat = getCategory();
02101         if(!cat) return;
02102         
02103         wear_inventory_category_on_avatar( cat, append );
02104 }
02105 
02106 // helper stuff
02107 void move_task_inventory_callback(S32 option, void* user_data)
02108 {
02109         LLMoveInv* move_inv = (LLMoveInv*)user_data;
02110         LLFloaterOpenObject::LLCatAndWear* cat_and_wear = (LLFloaterOpenObject::LLCatAndWear* )move_inv->mUserData;
02111         LLViewerObject* object = gObjectList.findObject(move_inv->mObjectID);
02112         
02113         if(option == 0 && object)
02114         {
02115                 if (cat_and_wear && cat_and_wear->mWear)
02116                 {
02117                         InventoryObjectList inventory_objects;
02118                         object->getInventoryContents(inventory_objects);
02119                         int contents_count = inventory_objects.size()-1; //subtract one for containing folder
02120 
02121                         LLInventoryCopyAndWearObserver* inventoryObserver = new LLInventoryCopyAndWearObserver(cat_and_wear->mCatID, contents_count);
02122                         gInventory.addObserver(inventoryObserver);
02123                 }
02124 
02125                 two_uuids_list_t::iterator move_it;
02126                 for (move_it = move_inv->mMoveList.begin(); 
02127                         move_it != move_inv->mMoveList.end(); 
02128                         ++move_it)
02129                 {
02130                         object->moveInventory(move_it->first, move_it->second);
02131                 }
02132 
02133                 // update the UI.
02134                 dialog_refresh_all();
02135         }
02136 
02137         if (move_inv->mCallback)
02138         {
02139                 move_inv->mCallback(option, move_inv->mUserData);
02140         }
02141 
02142         delete move_inv;
02143 }
02144 
02145 BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
02146                                                                                 BOOL drop)
02147 {
02148         LLInventoryModel* model = mInventoryPanel->getModel();
02149         if(!model) return FALSE;
02150 
02151         // cannot drag into library
02152         if(!isAgentInventory())
02153         {
02154                 return FALSE;
02155         }
02156 
02157         LLVOAvatar* avatar = gAgent.getAvatarObject();
02158         if(!avatar) return FALSE;
02159 
02160         LLToolDragAndDrop::ESource source = gToolDragAndDrop->getSource();
02161         BOOL accept = FALSE;
02162         LLViewerObject* object = NULL;
02163         if(LLToolDragAndDrop::SOURCE_AGENT == source)
02164         {
02165 
02166                 BOOL is_movable = TRUE;
02167                 switch( inv_item->getType() )
02168                 {
02169                 case LLAssetType::AT_ROOT_CATEGORY:
02170                         is_movable = FALSE;
02171                         break;
02172 
02173                 case LLAssetType::AT_CATEGORY:
02174                         is_movable = ( LLAssetType::AT_NONE == ((LLInventoryCategory*)inv_item)->getPreferredType() );
02175                         break;
02176                 default:
02177                         break;
02178                 }
02179 
02180                 LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH);
02181                 BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id);
02182                 if(is_movable && move_is_into_trash)
02183                 {
02184                         switch(inv_item->getType())
02185                         {
02186                         case LLAssetType::AT_CLOTHING:
02187                         case LLAssetType::AT_BODYPART:
02188                                 is_movable = !gAgent.isWearingItem(inv_item->getUUID());
02189                                 break;
02190 
02191                         case LLAssetType::AT_OBJECT:
02192                                 is_movable = !avatar->isWearingAttachment(inv_item->getUUID());
02193                                 break;
02194                         default:
02195                                 break;
02196                         }
02197                 }
02198  
02199                 accept = is_movable && (mUUID != inv_item->getParentUUID());
02200                 if(accept && drop)
02201                 {
02202                         if (inv_item->getType() == LLAssetType::AT_GESTURE
02203                                 && gGestureManager.isGestureActive(inv_item->getUUID()))
02204                         {
02205                                 gGestureManager.deactivateGesture(inv_item->getUUID());
02206                         }
02207                         // If an item is being dragged between windows, unselect
02208                         // everything in the active window so that we don't follow
02209                         // the selection to its new location (which is very
02210                         // annoying).
02211                         if (LLInventoryView::getActiveInventory())
02212                         {
02213                                 LLInventoryPanel* active_panel = LLInventoryView::getActiveInventory()->getPanel();
02214                                 if (active_panel && (mInventoryPanel != active_panel))
02215                                 {
02216                                         active_panel->unSelectAll();
02217                                 }
02218                         }
02219 
02220                         // restamp if the move is into the trash.
02221                         LLInvFVBridge::changeItemParent(
02222                                 model,
02223                                 (LLViewerInventoryItem*)inv_item,
02224                                 mUUID,
02225                                 move_is_into_trash);
02226                 }
02227         }
02228         else if(LLToolDragAndDrop::SOURCE_WORLD == source)
02229         {
02230                 // Make sure the object exists. If we allowed dragging from
02231                 // anonymous objects, it would be possible to bypass
02232                 // permissions.
02233                 object = gObjectList.findObject(inv_item->getParentUUID());
02234                 if(!object)
02235                 {
02236                         llinfos << "Object not found for drop." << llendl;
02237                         return FALSE;
02238                 }
02239 
02240                 // coming from a task. Need to figure out if the person can
02241                 // move/copy this item.
02242                 LLPermissions perm(inv_item->getPermissions());
02243                 BOOL is_move = FALSE;
02244                 if((perm.allowCopyBy(gAgent.getID(), gAgent.getGroupID())
02245                         && perm.allowTransferTo(gAgent.getID())))
02246 //                 || gAgent.isGodlike())
02247                         
02248                 {
02249                         accept = TRUE;
02250                 }
02251                 else if(object->permYouOwner())
02252                 {
02253                         // If the object cannot be copied, but the object the
02254                         // inventory is owned by the agent, then the item can be
02255                         // moved from the task to agent inventory.
02256                         is_move = TRUE;
02257                         accept = TRUE;
02258                 }
02259                 if(drop && accept)
02260                 {
02261                         LLMoveInv* move_inv = new LLMoveInv;
02262                         move_inv->mObjectID = inv_item->getParentUUID();
02263                         two_uuids_t item_pair(mUUID, inv_item->getUUID());
02264                         move_inv->mMoveList.push_back(item_pair);
02265                         move_inv->mCallback = NULL;
02266                         move_inv->mUserData = NULL;
02267                         if(is_move)
02268                         {
02269                                 warn_move_inventory(object, move_inv);
02270                         }
02271                         else
02272                         {
02273                                 move_task_inventory_callback(0, (void*)(move_inv));
02274                         }
02275                 }
02276                 
02277         }
02278         else if(LLToolDragAndDrop::SOURCE_NOTECARD == source)
02279         {
02280                 accept = TRUE;
02281                 if(drop)
02282                 {
02283                         copy_inventory_from_notecard(gToolDragAndDrop->getObjectID(),
02284                                 gToolDragAndDrop->getSourceID(), inv_item);
02285                 }
02286         }
02287         else if(LLToolDragAndDrop::SOURCE_LIBRARY == source)
02288         {
02289                 LLViewerInventoryItem* item = (LLViewerInventoryItem*)inv_item;
02290                 if(item && item->isComplete())
02291                 {
02292                         accept = TRUE;
02293                         if(drop)
02294                         {
02295                                 copy_inventory_item(
02296                                         gAgent.getID(),
02297                                         inv_item->getPermissions().getOwner(),
02298                                         inv_item->getUUID(),
02299                                         mUUID,
02300                                         std::string(),
02301                                         LLPointer<LLInventoryCallback>(NULL));
02302                         }
02303                 }
02304         }
02305         else
02306         {
02307                 llwarns << "unhandled drag source" << llendl;
02308         }
02309         return accept;
02310 }
02311 
02312 // +=================================================+
02313 // |        LLScriptBridge (DEPRECTED)               |
02314 // +=================================================+
02315 
02316 LLViewerImage* LLScriptBridge::getIcon() const
02317 {
02318         return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE);
02319 }
02320 
02321 // +=================================================+
02322 // |        LLTextureBridge                          |
02323 // +=================================================+
02324 
02325 LLString LLTextureBridge::sPrefix("Texture: ");
02326 
02327 
02328 LLViewerImage* LLTextureBridge::getIcon() const
02329 {
02330         return get_item_icon(LLAssetType::AT_TEXTURE, mInvType, 0, FALSE);
02331 }
02332         
02333 void open_texture(const LLUUID& item_id, 
02334                                    const LLString& title,
02335                                    BOOL show_keep_discard,
02336                                    const LLUUID& source_id,
02337                                    BOOL take_focus)
02338 {
02339         // See if we can bring an exiting preview to the front
02340         if( !LLPreview::show( item_id, take_focus ) )
02341         {
02342                 // There isn't one, so make a new preview
02343                 S32 left, top;
02344                 gFloaterView->getNewFloaterPosition(&left, &top);
02345                 LLRect rect = gSavedSettings.getRect("PreviewTextureRect");
02346                 rect.translate( left - rect.mLeft, top - rect.mTop );
02347 
02348                 LLPreviewTexture* preview;
02349                 preview = new LLPreviewTexture("preview texture",
02350                                                                                   rect,
02351                                                                                   title,
02352                                                                                   item_id,
02353                                                                                   LLUUID::null,
02354                                                                                   show_keep_discard);
02355                 preview->setSourceID(source_id);
02356                 if(take_focus) preview->setFocus(TRUE);
02357 
02358                 gFloaterView->adjustToFitScreen(preview, FALSE);
02359         }
02360 }
02361 
02362 void LLTextureBridge::openItem()
02363 {
02364         LLViewerInventoryItem* item = getItem();
02365         if(item)
02366         {
02367                 open_texture(mUUID, getPrefix() + item->getName(), FALSE);
02368         }
02369 }
02370 
02371 // +=================================================+
02372 // |        LLSoundBridge                            |
02373 // +=================================================+
02374 
02375 LLString LLSoundBridge::sPrefix("Sound: ");
02376 
02377 
02378 LLViewerImage* LLSoundBridge::getIcon() const
02379 {
02380         return get_item_icon(LLAssetType::AT_SOUND, LLInventoryType::IT_SOUND, 0, FALSE);
02381 }
02382 
02383 void LLSoundBridge::openItem()
02384 {
02385 // Changed this back to the way it USED to work:
02386 // only open the preview dialog through the contextual right-click menu
02387 // double-click just plays the sound
02388 
02389         LLViewerInventoryItem* item = getItem();
02390         if(item)
02391         {
02392                 openSoundPreview((void*)this);
02393                 //send_uuid_sound_trigger(item->getAssetUUID(), 1.0);
02394         }
02395 
02396 //      if(!LLPreview::show(mUUID))
02397 //      {
02398 //              S32 left, top;
02399 //              gFloaterView->getNewFloaterPosition(&left, &top);
02400 //              LLRect rect = gSavedSettings.getRect("PreviewSoundRect");
02401 //              rect.translate(left - rect.mLeft, top - rect.mTop);
02402 //                      new LLPreviewSound("preview sound",
02403 //                                                         rect,
02404 //                                                         getPrefix() + getName(),
02405 //                                                         mUUID));
02406 //      }
02407 }
02408 
02409 void LLSoundBridge::previewItem()
02410 {
02411         LLViewerInventoryItem* item = getItem();
02412         if(item)
02413         {
02414                 send_sound_trigger(item->getAssetUUID(), 1.0);
02415         }
02416 }
02417 
02418 void LLSoundBridge::openSoundPreview(void* which)
02419 {
02420         LLSoundBridge *me = (LLSoundBridge *)which;
02421         if(!LLPreview::show(me->mUUID))
02422         {
02423                 S32 left, top;
02424                 gFloaterView->getNewFloaterPosition(&left, &top);
02425                 LLRect rect = gSavedSettings.getRect("PreviewSoundRect");
02426                 rect.translate(left - rect.mLeft, top - rect.mTop);
02427                 LLPreviewSound* preview = new LLPreviewSound("preview sound",
02428                                                                                    rect,
02429                                                                                    me->getPrefix() + me->getName(),
02430                                                                                    me->mUUID);
02431                 preview->setFocus(TRUE);
02432                 // Keep entirely onscreen.
02433                 gFloaterView->adjustToFitScreen(preview, FALSE);
02434         }
02435 }
02436 
02437 void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
02438 {
02439         lldebugs << "LLTextureBridge::buildContextMenu()" << llendl;
02440         std::vector<LLString> items;
02441         std::vector<LLString> disabled_items;
02442 
02443         if(isInTrash())
02444         {
02445                 items.push_back("Purge Item");
02446                 if (!isItemRemovable())
02447                 {
02448                         disabled_items.push_back("Purge Item");
02449                 }
02450 
02451                 items.push_back("Restore Item");
02452         }
02453         else
02454         {
02455                 items.push_back("Sound Open");
02456                 items.push_back("Properties");
02457 
02458                 getClipboardEntries(true, items, disabled_items, flags);
02459         }
02460 
02461         items.push_back("Sound Separator");
02462         items.push_back("Sound Play");
02463 
02464         hideContextEntries(menu, items, disabled_items);
02465 }
02466 
02467 // +=================================================+
02468 // |        LLLandmarkBridge                         |
02469 // +=================================================+
02470 
02471 LLString LLLandmarkBridge::sPrefix("Landmark:  ");
02472 
02473 LLViewerImage* LLLandmarkBridge::getIcon() const
02474 {
02475         return get_item_icon(LLAssetType::AT_LANDMARK, LLInventoryType::IT_LANDMARK, mVisited, FALSE);
02476 }
02477 
02478 void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
02479 {
02480         std::vector<LLString> items;
02481         std::vector<LLString> disabled_items;
02482 
02483         lldebugs << "LLLandmarkBridge::buildContextMenu()" << llendl;
02484         if(isInTrash())
02485         {
02486                 items.push_back("Purge Item");
02487                 if (!isItemRemovable())
02488                 {
02489                         disabled_items.push_back("Purge Item");
02490                 }
02491 
02492                 items.push_back("Restore Item");
02493         }
02494         else
02495         {
02496                 items.push_back("Landmark Open");
02497                 items.push_back("Properties");
02498 
02499                 getClipboardEntries(true, items, disabled_items, flags);
02500         }
02501 
02502         items.push_back("Landmark Separator");
02503         items.push_back("Teleport To Landmark");
02504 
02505         hideContextEntries(menu, items, disabled_items);
02506 
02507 }
02508 
02509 // virtual
02510 void LLLandmarkBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
02511 {
02512         if ("teleport" == action)
02513         {
02514                 LLViewerInventoryItem* item = getItem();
02515                 if(item)
02516                 {
02517                         gAgent.teleportViaLandmark(item->getAssetUUID());
02518 
02519                         // we now automatically track the landmark you're teleporting to
02520                         // because you'll probably arrive at a telehub instead
02521                         if( gFloaterWorldMap )
02522                         {
02523                                 gFloaterWorldMap->trackLandmark( item->getAssetUUID() );
02524                         }
02525                 }
02526         }
02527         if ("about" == action)
02528         {
02529                 LLViewerInventoryItem* item = getItem();
02530                 if(item)
02531                 {
02532                         open_landmark(item, LLString("  ") + getPrefix() + item->getName(), FALSE);
02533                 }
02534         }
02535         else LLItemBridge::performAction(folder, model, action);
02536 }
02537 
02538 void open_landmark(LLViewerInventoryItem* inv_item,
02539                                    const LLString& title,
02540                                    BOOL show_keep_discard,
02541                                    const LLUUID& source_id,
02542                                    BOOL take_focus)
02543 {
02544         // See if we can bring an exiting preview to the front
02545         if( !LLPreview::show( inv_item->getUUID(), take_focus ) )
02546         {
02547                 // There isn't one, so make a new preview
02548                 S32 left, top;
02549                 gFloaterView->getNewFloaterPosition(&left, &top);
02550                 LLRect rect = gSavedSettings.getRect("PreviewLandmarkRect");
02551                 rect.translate( left - rect.mLeft, top - rect.mTop );
02552 
02553                 LLPreviewLandmark* preview = new LLPreviewLandmark(title,
02554                                                                   rect,
02555                                                                   title,
02556                                                                   inv_item->getUUID(),
02557                                                                   show_keep_discard,
02558                                                                   inv_item);
02559                 preview->setSourceID(source_id);
02560                 if(take_focus) preview->setFocus(TRUE);
02561                 // keep onscreen
02562                 gFloaterView->adjustToFitScreen(preview, FALSE);
02563         }
02564 }
02565 
02566 static void open_landmark_callback(S32 option, void* data)
02567 {
02568         LLUUID* asset_idp = (LLUUID*)data;
02569         if (option == 0)
02570         {
02571                 // HACK: This is to demonstrate teleport on double click for landmarks
02572                 gAgent.teleportViaLandmark( *asset_idp );
02573 
02574                 // we now automatically track the landmark you're teleporting to
02575                 // because you'll probably arrive at a telehub instead
02576                 if( gFloaterWorldMap )
02577                 {
02578                         gFloaterWorldMap->trackLandmark( *asset_idp );
02579                 }
02580         }
02581         delete asset_idp;
02582 }
02583 
02584 void LLLandmarkBridge::openItem()
02585 {
02586         LLViewerInventoryItem* item = getItem();
02587         if( item )
02588         {
02589                 // Opening (double-clicking) a landmark immediately teleports,
02590                 // but warns you the first time.
02591                 // open_landmark(item, LLString("  ") + getPrefix() + item->getName(), FALSE);
02592                 LLUUID* asset_idp = new LLUUID(item->getAssetUUID());
02593                 LLAlertDialog::showXml("TeleportFromLandmark",
02594                         open_landmark_callback, (void*)asset_idp);
02595         }
02596 }
02597 
02598 
02599 // +=================================================+
02600 // |        LLCallingCardObserver                    |
02601 // +=================================================+
02602 void LLCallingCardObserver::changed(U32 mask)
02603 {
02604         mBridgep->refreshFolderViewItem();
02605 }
02606 
02607 // +=================================================+
02608 // |        LLCallingCardBridge                      |
02609 // +=================================================+
02610 
02611 LLString LLCallingCardBridge::sPrefix("Calling Card: ");
02612 
02613 LLCallingCardBridge::LLCallingCardBridge( LLInventoryPanel* inventory, const LLUUID& uuid ) :
02614         LLItemBridge(inventory, uuid)
02615 {
02616         mObserver = new LLCallingCardObserver(this);
02617         LLAvatarTracker::instance().addObserver(mObserver);
02618 }
02619 
02620 LLCallingCardBridge::~LLCallingCardBridge()
02621 {
02622         LLAvatarTracker::instance().removeObserver(mObserver);
02623         delete mObserver;
02624 }
02625 
02626 void LLCallingCardBridge::refreshFolderViewItem()
02627 {
02628         LLFolderViewItem* itemp = mInventoryPanel->getRootFolder()->getItemByID(mUUID);
02629         if (itemp)
02630         {
02631                 itemp->refresh();
02632         }
02633 }
02634 
02635 // virtual
02636 void LLCallingCardBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
02637 {
02638         if ("begin_im" == action)
02639         {
02640                 LLViewerInventoryItem *item = getItem();
02641                 if (item && (item->getCreatorUUID() != gAgent.getID()) &&
02642                         (!item->getCreatorUUID().isNull()))
02643                 {
02644                         gIMMgr->setFloaterOpen(TRUE);
02645                         gIMMgr->addSession(item->getName(), IM_NOTHING_SPECIAL, item->getCreatorUUID());
02646                 }
02647         }
02648         else if ("lure" == action)
02649         {
02650                 LLViewerInventoryItem *item = getItem();
02651                 if (item && (item->getCreatorUUID() != gAgent.getID()) &&
02652                         (!item->getCreatorUUID().isNull()))
02653                 {
02654                         handle_lure(item->getCreatorUUID());
02655                 }
02656         }
02657         else LLItemBridge::performAction(folder, model, action);
02658 }
02659 
02660 LLViewerImage* LLCallingCardBridge::getIcon() const
02661 {
02662         BOOL online = FALSE;
02663         LLViewerInventoryItem* item = getItem();
02664         if(item)
02665         {
02666                 online = LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID());
02667         }
02668         return get_item_icon(LLAssetType::AT_CALLINGCARD, LLInventoryType::IT_CALLINGCARD, online, FALSE);
02669 }
02670 
02671 LLString LLCallingCardBridge::getLabelSuffix() const
02672 {
02673         LLViewerInventoryItem* item = getItem();
02674         if( item && LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()) )
02675         {
02676                 return LLItemBridge::getLabelSuffix() + " (online)";
02677         }
02678         else
02679         {
02680                 return LLItemBridge::getLabelSuffix();
02681         }
02682 }
02683 
02684 void LLCallingCardBridge::openItem()
02685 {
02686         LLViewerInventoryItem* item = getItem();
02687         if(item && !item->getCreatorUUID().isNull())
02688         {
02689                 BOOL online;
02690                 online = LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID());
02691                 LLFloaterAvatarInfo::showFromFriend(item->getCreatorUUID(), online);
02692         }
02693 }
02694 
02695 void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
02696 {
02697         lldebugs << "LLCallingCardBridge::buildContextMenu()" << llendl;
02698         std::vector<LLString> items;
02699         std::vector<LLString> disabled_items;
02700 
02701         if(isInTrash())
02702         {
02703                 items.push_back("Purge Item");
02704                 if (!isItemRemovable())
02705                 {
02706                         disabled_items.push_back("Purge Item");
02707                 }
02708 
02709                 items.push_back("Restore Item");
02710         }
02711         else
02712         {
02713                 items.push_back("Open");
02714                 items.push_back("Properties");
02715 
02716                 getClipboardEntries(true, items, disabled_items, flags);
02717 
02718                 LLInventoryItem* item = getItem();
02719                 BOOL good_card = (item
02720                                                   && (LLUUID::null != item->getCreatorUUID())
02721                                                   && (item->getCreatorUUID() != gAgent.getID()));
02722                 BOOL user_online = (LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()));
02723                 items.push_back("Send Instant Message");
02724                 items.push_back("Offer Teleport...");
02725                 items.push_back("Conference Chat");
02726 
02727                 if (!good_card)
02728                 {
02729                         disabled_items.push_back("Send Instant Message");
02730                 }
02731                 if (!good_card || !user_online)
02732                 {
02733                         disabled_items.push_back("Offer Teleport...");
02734                         disabled_items.push_back("Conference Chat");
02735                 }
02736         }
02737         hideContextEntries(menu, items, disabled_items);
02738 }
02739 
02740 BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop,
02741                                                                          EDragAndDropType cargo_type,
02742                                                                          void* cargo_data)
02743 {
02744         LLViewerInventoryItem* item = getItem();
02745         BOOL rv = FALSE;
02746         if(item)
02747         {
02748                 // check the type
02749                 switch(cargo_type)
02750                 {
02751                 case DAD_TEXTURE:
02752                 case DAD_SOUND:
02753                 case DAD_LANDMARK:
02754                 case DAD_SCRIPT:
02755                 case DAD_CLOTHING:
02756                 case DAD_OBJECT:
02757                 case DAD_NOTECARD:
02758                 case DAD_BODYPART:
02759                 case DAD_ANIMATION:
02760                 case DAD_GESTURE:
02761                         {
02762                                 LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
02763                                 const LLPermissions& perm = inv_item->getPermissions();
02764                                 if(gInventory.getItem(inv_item->getUUID())
02765                                    && perm.allowOperationBy(PERM_TRANSFER, gAgent.getID()))
02766                                 {
02767                                         rv = TRUE;
02768                                         if(drop)
02769                                         {
02770                                                 LLToolDragAndDrop::giveInventory(item->getCreatorUUID(),
02771                                                                                                                  (LLInventoryItem*)cargo_data);
02772                                         }
02773                                 }
02774                                 else
02775                                 {
02776                                         // It's not in the user's inventory (it's probably in
02777                                         // an object's contents), so disallow dragging it here.
02778                                         // You can't give something you don't yet have.
02779                                         rv = FALSE;
02780                                 }
02781                                 break;
02782                         }
02783                 case DAD_CATEGORY:
02784                         {
02785                                 LLInventoryCategory* inv_cat = (LLInventoryCategory*)cargo_data;
02786                                 if( gInventory.getCategory( inv_cat->getUUID() ) )
02787                                 {
02788                                         rv = TRUE;
02789                                         if(drop)
02790                                         {
02791                                                 LLToolDragAndDrop::giveInventoryCategory(
02792                                                         item->getCreatorUUID(),
02793                                                         inv_cat);
02794                                         }
02795                                 }
02796                                 else
02797                                 {
02798                                         // It's not in the user's inventory (it's probably in
02799                                         // an object's contents), so disallow dragging it here.
02800                                         // You can't give something you don't yet have.
02801                                         rv = FALSE;
02802                                 }
02803                                 break;
02804                         }
02805                 default:
02806                         break;
02807                 }
02808         }
02809         return rv;
02810 }
02811 
02812 // +=================================================+
02813 // |        LLNotecardBridge                         |
02814 // +=================================================+
02815 
02816 LLString LLNotecardBridge::sPrefix("Note: ");
02817 
02818 
02819 LLViewerImage* LLNotecardBridge::getIcon() const
02820 {
02821         return get_item_icon(LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, 0, FALSE);
02822 }
02823 
02824 void open_notecard(LLViewerInventoryItem* inv_item,
02825                                    const LLString& title,
02826                                    const LLUUID& object_id,
02827                                    BOOL show_keep_discard,
02828                                    const LLUUID& source_id,
02829                                    BOOL take_focus)
02830 {
02831         // See if we can bring an existing preview to the front
02832         if(!LLPreview::show(inv_item->getUUID(), take_focus))
02833         {
02834                 // There isn't one, so make a new preview
02835                 S32 left, top;
02836                 gFloaterView->getNewFloaterPosition(&left, &top);
02837                 LLRect rect = gSavedSettings.getRect("NotecardEditorRect");
02838                 rect.translate(left - rect.mLeft, top - rect.mTop);
02839                 LLPreviewNotecard* preview;
02840                 preview = new LLPreviewNotecard("preview notecard", rect, title,
02841                                                 inv_item->getUUID(), object_id, inv_item->getAssetUUID(),
02842                                                 show_keep_discard, inv_item);
02843                 preview->setSourceID(source_id);
02844                 if(take_focus) preview->setFocus(TRUE);
02845                 // Force to be entirely onscreen.
02846                 gFloaterView->adjustToFitScreen(preview, FALSE);
02847 
02848                 //if (source_id.notNull())
02849                 //{
02850                 //      // look for existing tabbed view for content from same source
02851                 //      LLPreview* existing_preview = LLPreview::getPreviewForSource(source_id);
02852                 //      if (existing_preview)
02853                 //      {
02854                 //              // found existing preview from this source
02855                 //              // is it already hosted in a multi-preview window?
02856                 //              LLMultiPreview* preview_hostp = (LLMultiPreview*)existing_preview->getHost();
02857                 //              if (!preview_hostp)
02858                 //              {
02859                 //                      // create new multipreview if it doesn't exist
02860                 //                      LLMultiPreview* preview_hostp = new LLMultiPreview(existing_preview->getRect());
02861                 //                      preview_hostp->addFloater(existing_preview);
02862                 //              }
02863                 //              // add this preview to existing host
02864                 //              preview_hostp->addFloater(preview);
02865                 //      }
02866                 //}
02867         }
02868 }
02869 
02870 
02871 void LLNotecardBridge::openItem()
02872 {
02873         LLViewerInventoryItem* item = getItem();
02874         if (item)
02875         {
02876                 open_notecard(item, getPrefix() + item->getName(), LLUUID::null, FALSE);
02877         }
02878 }
02879 
02880 
02881 // +=================================================+
02882 // |        LLGestureBridge                          |
02883 // +=================================================+
02884 
02885 LLString LLGestureBridge::sPrefix("Gesture: ");
02886 
02887 LLViewerImage* LLGestureBridge::getIcon() const
02888 {
02889         return get_item_icon(LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, 0, FALSE);
02890 }
02891 
02892 LLFontGL::StyleFlags LLGestureBridge::getLabelStyle() const
02893 {
02894         if( gGestureManager.isGestureActive(mUUID) )
02895         {
02896                 return LLFontGL::BOLD;
02897         }
02898         else
02899         {
02900                 return LLFontGL::NORMAL;
02901         }
02902 }
02903 
02904 LLString LLGestureBridge::getLabelSuffix() const
02905 {
02906         if( gGestureManager.isGestureActive(mUUID) )
02907         {
02908                 return LLItemBridge::getLabelSuffix() + " (active)";
02909         }
02910         else
02911         {
02912                 return LLItemBridge::getLabelSuffix();
02913         }
02914 }
02915 
02916 // virtual
02917 void LLGestureBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
02918 {
02919         if ("activate" == action)
02920         {
02921                 gGestureManager.activateGesture(mUUID);
02922 
02923                 LLViewerInventoryItem* item = gInventory.getItem(mUUID);
02924                 if (!item) return;
02925 
02926                 // Since we just changed the suffix to indicate (active)
02927                 // the server doesn't need to know, just the viewer.
02928                 gInventory.updateItem(item);
02929                 gInventory.notifyObservers();
02930         }
02931         else if ("deactivate" == action)
02932         {
02933                 gGestureManager.deactivateGesture(mUUID);
02934 
02935                 LLViewerInventoryItem* item = gInventory.getItem(mUUID);
02936                 if (!item) return;
02937 
02938                 // Since we just changed the suffix to indicate (active)
02939                 // the server doesn't need to know, just the viewer.
02940                 gInventory.updateItem(item);
02941                 gInventory.notifyObservers();
02942         }
02943         else LLItemBridge::performAction(folder, model, action);
02944 }
02945 
02946 void LLGestureBridge::openItem()
02947 {
02948         LLViewerInventoryItem* item = getItem();
02949         if (!item) return;
02950 
02951         // See if we can bring an existing preview to the front
02952         if(!LLPreview::show(mUUID))
02953         {
02954                 LLUUID item_id = mUUID;
02955                 LLString title = getPrefix() + item->getName();
02956                 LLUUID object_id = LLUUID::null;
02957 
02958                 // TODO: save the rectangle
02959                 LLPreviewGesture* preview = LLPreviewGesture::show(title, item_id, object_id);
02960                 preview->setFocus(TRUE);
02961 
02962                 // Force to be entirely onscreen.
02963                 gFloaterView->adjustToFitScreen(preview, FALSE);
02964         }
02965 }
02966 
02967 BOOL LLGestureBridge::removeItem()
02968 {
02969         // Force close the preview window, if it exists
02970         gGestureManager.deactivateGesture(mUUID);
02971         return LLItemBridge::removeItem();
02972 }
02973 
02974 void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
02975 {
02976         lldebugs << "LLGestureBridge::buildContextMenu()" << llendl;
02977         std::vector<LLString> items;
02978         std::vector<LLString> disabled_items;
02979         if(isInTrash())
02980         {
02981                 items.push_back("Purge Item");
02982                 if (!isItemRemovable())
02983                 {
02984                         disabled_items.push_back("Purge Item");
02985                 }
02986 
02987                 items.push_back("Restore Item");
02988         }
02989         else
02990         {
02991                 items.push_back("Open");
02992                 items.push_back("Properties");
02993 
02994                 getClipboardEntries(true, items, disabled_items, flags);
02995 
02996                 items.push_back("Gesture Separator");
02997                 items.push_back("Activate");
02998                 items.push_back("Deactivate");
02999 
03000                 /*menu.append(new LLMenuItemCallGL("Activate",
03001                                                                                  handleActivateGesture,
03002                                                                                  enableActivateGesture,
03003                                                                                  (void*)this));
03004                 menu.append(new LLMenuItemCallGL("Deactivate",
03005                                                                                  handleDeactivateGesture,
03006                                                                                  enableDeactivateGesture,
03007                                                                                  (void*)this));*/
03008         }
03009         hideContextEntries(menu, items, disabled_items);
03010 }
03011 
03012 // +=================================================+
03013 // |        LLAnimationBridge                        |
03014 // +=================================================+
03015 
03016 LLString LLAnimationBridge::sPrefix("Animation: ");
03017 
03018 
03019 LLViewerImage* LLAnimationBridge::getIcon() const
03020 {
03021         return get_item_icon(LLAssetType::AT_ANIMATION, LLInventoryType::IT_ANIMATION, 0, FALSE);
03022 }
03023 
03024 void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
03025 {
03026         std::vector<LLString> items;
03027         std::vector<LLString> disabled_items;
03028 
03029         lldebugs << "LLAnimationBridge::buildContextMenu()" << llendl;
03030         if(isInTrash())
03031         {
03032                 items.push_back("Purge Item");
03033                 if (!isItemRemovable())
03034                 {
03035                         disabled_items.push_back("Purge Item");
03036                 }
03037 
03038                 items.push_back("Restore Item");
03039         }
03040         else
03041         {
03042                 items.push_back("Animation Open");
03043                 items.push_back("Properties");
03044 
03045                 getClipboardEntries(true, items, disabled_items, flags);
03046         }
03047 
03048         items.push_back("Animation Separator");
03049         items.push_back("Animation Play");
03050         items.push_back("Animation Audition");
03051 
03052         hideContextEntries(menu, items, disabled_items);
03053 
03054 }
03055 
03056 // virtual
03057 void LLAnimationBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
03058 {
03059         S32 activate = 0;
03060 
03061         if ((action == "playworld") || (action == "playlocal"))
03062         {
03063         
03064                 if ("playworld" == action) activate = 1;
03065                 if ("playlocal" == action) activate = 2;
03066 
03067                 // See if we can bring an existing preview to the front
03068                 if( !LLPreview::show( mUUID ) )
03069                 {
03070                         // There isn't one, so make a new preview
03071                         LLViewerInventoryItem* item = getItem();
03072                         if( item )
03073                         {
03074                                 S32 left, top;
03075                                 gFloaterView->getNewFloaterPosition(&left, &top);
03076                                 LLRect rect = gSavedSettings.getRect("PreviewAnimRect");
03077                                 rect.translate( left - rect.mLeft, top - rect.mTop );
03078                                 LLPreviewAnim* preview = new LLPreviewAnim("preview anim",
03079                                                                                 rect,
03080                                                                                 getPrefix() + item->getName(),
03081                                                                                 mUUID,
03082                                                                                 activate);
03083                                 // Force to be entirely onscreen.
03084                                 gFloaterView->adjustToFitScreen(preview, FALSE);
03085                         }
03086                 }
03087         }
03088         else
03089         {
03090                 LLItemBridge::performAction(folder, model, action);
03091         }
03092 }
03093 
03094 void LLAnimationBridge::openItem()
03095 {
03096         // See if we can bring an existing preview to the front
03097         if( !LLPreview::show( mUUID ) )
03098         {
03099                 // There isn't one, so make a new preview
03100                 LLViewerInventoryItem* item = getItem();
03101                 if( item )
03102                 {
03103                         S32 left, top;
03104                         gFloaterView->getNewFloaterPosition(&left, &top);
03105                         LLRect rect = gSavedSettings.getRect("PreviewAnimRect");
03106                         rect.translate( left - rect.mLeft, top - rect.mTop );
03107                         LLPreviewAnim* preview = new LLPreviewAnim("preview anim",
03108                                                                         rect,
03109                                                                         getPrefix() + item->getName(),
03110                                                                         mUUID,
03111                                                                         0);
03112                         preview->setFocus(TRUE);
03113                         // Force to be entirely onscreen.
03114                         gFloaterView->adjustToFitScreen(preview, FALSE);
03115                 }
03116         }
03117 }
03118 
03119 // +=================================================+
03120 // |        LLObjectBridge                           |
03121 // +=================================================+
03122 
03123 // static
03124 LLString LLObjectBridge::sPrefix("Object: ");
03125 
03126 // static
03127 LLUUID LLObjectBridge::sContextMenuItemID;
03128 
03129 BOOL LLObjectBridge::isItemRemovable()
03130 {
03131         LLVOAvatar* avatar = gAgent.getAvatarObject();
03132         if(!avatar) return FALSE;
03133         if(avatar->isWearingAttachment(mUUID)) return FALSE;
03134         return LLInvFVBridge::isItemRemovable();
03135 }
03136 
03137 LLViewerImage* LLObjectBridge::getIcon() const
03138 {
03139         return get_item_icon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject );
03140 }
03141 
03142 void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment);
03143 
03144 // virtual
03145 void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
03146 {
03147         if ("attach" == action)
03148         {
03149                 LLUUID object_id = mUUID;
03150                 LLViewerInventoryItem* item;
03151                 item = (LLViewerInventoryItem*)gInventory.getItem(object_id);
03152                 if(item && gInventory.isObjectDescendentOf(object_id, gAgent.getInventoryRootID()))
03153                 {
03154                         rez_attachment(item, NULL);
03155                 }
03156                 else if(item && item->isComplete())
03157                 {
03158                         // must be in library. copy it to our inventory and put it on.
03159                         LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(0);
03160                         copy_inventory_item(
03161                                 gAgent.getID(),
03162                                 item->getPermissions().getOwner(),
03163                                 item->getUUID(),
03164                                 LLUUID::null,
03165                                 std::string(),
03166                                 cb);
03167                 }
03168                 gFocusMgr.setKeyboardFocus(NULL, NULL);
03169         }
03170         else if ("detach" == action)
03171         {
03172                 LLInventoryItem* item = gInventory.getItem(mUUID);
03173                 if( item )
03174                 {
03175                         gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv);
03176                         gMessageSystem->nextBlockFast(_PREHASH_ObjectData );
03177                         gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
03178                         gMessageSystem->addUUIDFast(_PREHASH_ItemID, item->getUUID() );
03179 
03180                         gMessageSystem->sendReliable( gAgent.getRegion()->getHost() );
03181                 }
03182                 // this object might have been selected, so let the selection manager know it's gone now
03183                 LLViewerObject *found_obj =
03184                         gObjectList.findObject(item->getUUID());
03185                 if (found_obj)
03186                 {
03187                         gSelectMgr->remove(found_obj);
03188                 }
03189                 else
03190                 {
03191                         llwarns << "object not found - ignoring" << llendl;
03192                 }
03193         }
03194         else LLItemBridge::performAction(folder, model, action);
03195 }
03196 
03197 void LLObjectBridge::openItem()
03198 {
03199         /* Disabled -- this preview isn't useful. JC */
03200         // CP: actually, this code is required - made changes to match LLAnimationBridge::openItem() idiom
03201         // The properties preview is useful, converting to show object properties. - DaveP
03202         LLShowProps::showProperties(mUUID);
03203 }
03204 
03205 LLFontGL::StyleFlags LLObjectBridge::getLabelStyle() const
03206 { 
03207         LLVOAvatar* avatar = gAgent.getAvatarObject();
03208         if( avatar && avatar->isWearingAttachment( mUUID ) )
03209         {
03210                 return LLFontGL::BOLD;
03211         }
03212         else
03213         {
03214                 return LLFontGL::NORMAL;
03215         }
03216 }
03217 
03218 LLString LLObjectBridge::getLabelSuffix() const
03219 {
03220         LLVOAvatar* avatar = gAgent.getAvatarObject();
03221         if( avatar && avatar->isWearingAttachment( mUUID ) )
03222         {
03223                 LLString attachment_point_name = avatar->getAttachedPointName(mUUID);
03224                 LLString::toLower(attachment_point_name);
03225                 return LLItemBridge::getLabelSuffix() + LLString(" (worn on ") + attachment_point_name + LLString(")");
03226         }
03227         else
03228         {
03229                 return LLItemBridge::getLabelSuffix();
03230         }
03231 }
03232 
03233 void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment)
03234 {
03235         LLAttachmentRezAction* rez_action = new LLAttachmentRezAction;
03236         rez_action->mItemID = item->getUUID();
03237         rez_action->mAttachPt = gAgent.getAvatarObject()->mAttachmentPoints.reverseLookup(attachment);
03238 
03239         if (attachment && attachment->getObject())
03240         {
03241                 gViewerWindow->alertXml("ReplaceAttachment", confirm_replace_attachment_rez, (void*)rez_action);
03242         }
03243         else
03244         {
03245                 confirm_replace_attachment_rez(0/*YES*/, (void*)rez_action);
03246         }
03247 }
03248 
03249 void confirm_replace_attachment_rez(S32 option, void* user_data)
03250 {
03251         LLAttachmentRezAction* rez_action = (LLAttachmentRezAction*)user_data;
03252         if (option == 0/*YES*/)
03253         {
03254                 if (rez_action)
03255                 {
03256                         LLViewerInventoryItem* itemp = gInventory.getItem(rez_action->mItemID);
03257                         
03258                         if (itemp)
03259                         {
03260                                 LLMessageSystem* msg = gMessageSystem;
03261                                 msg->newMessageFast(_PREHASH_RezSingleAttachmentFromInv);
03262                                 msg->nextBlockFast(_PREHASH_AgentData);
03263                                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
03264                                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
03265                                 msg->nextBlockFast(_PREHASH_ObjectData);
03266                                 msg->addUUIDFast(_PREHASH_ItemID, itemp->getUUID());
03267                                 msg->addUUIDFast(_PREHASH_OwnerID, itemp->getPermissions().getOwner());
03268                                 msg->addU8Fast(_PREHASH_AttachmentPt, rez_action->mAttachPt);
03269                                 pack_permissions_slam(msg, itemp->getFlags(), itemp->getPermissions());
03270                                 msg->addStringFast(_PREHASH_Name, itemp->getName());
03271                                 msg->addStringFast(_PREHASH_Description, itemp->getDescription());
03272                                 msg->sendReliable(gAgent.getRegion()->getHost());
03273                         }
03274                 }
03275         }
03276         delete rez_action;
03277 }
03278 
03279 void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
03280 {
03281         std::vector<LLString> items;
03282         std::vector<LLString> disabled_items;
03283         if(isInTrash())
03284         {
03285                 items.push_back("Purge Item");
03286                 if (!isItemRemovable())
03287                 {
03288                         disabled_items.push_back("Purge Item");
03289                 }
03290 
03291                 items.push_back("Restore Item");
03292         }
03293         else
03294         {
03295                 items.push_back("Properties");
03296 
03297                 getClipboardEntries(true, items, disabled_items, flags);
03298 
03299                 LLObjectBridge::sContextMenuItemID = mUUID;
03300 
03301                 LLInventoryItem* item = getItem();
03302                 if(item)
03303                 {
03304                         LLVOAvatar *avatarp = gAgent.getAvatarObject();
03305                         if( !avatarp )
03306                         {
03307                                 return;
03308                         }
03309                         
03310                         if( avatarp->isWearingAttachment( mUUID ) )
03311                         {
03312                                 items.push_back("Detach From Yourself");
03313                         }
03314                         else
03315                         if( !isInTrash() )
03316                         {
03317                                 items.push_back("Attach Separator");
03318                                 items.push_back("Object Wear");
03319                                 items.push_back("Attach To");
03320                                 items.push_back("Attach To HUD");
03321 
03322                                 LLMenuGL* attach_menu = menu.getChildMenuByName("Attach To", TRUE);
03323                                 LLMenuGL* attach_hud_menu = menu.getChildMenuByName("Attach To HUD", TRUE);
03324                                 LLVOAvatar *avatarp = gAgent.getAvatarObject();
03325                                 if (attach_menu && (attach_menu->getChildCount() == 0) &&
03326                                         attach_hud_menu && (attach_hud_menu->getChildCount() == 0) &&
03327                                         avatarp)
03328                                 {
03329                                         for (LLViewerJointAttachment* attachment = avatarp->mAttachmentPoints.getFirstData(); 
03330                                                 attachment;
03331                                                 attachment = gAgent.getAvatarObject()->mAttachmentPoints.getNextData())
03332                                         {
03333                                                 LLMenuItemCallGL *new_item;
03334                                                 if (attachment->getIsHUDAttachment())
03335                                                 {
03336                                                         attach_hud_menu->append(new_item = new LLMenuItemCallGL(attachment->getName(), 
03337                                                                 NULL, //&LLObjectBridge::attachToAvatar, 
03338                                                                 NULL, &attach_label, (void*)attachment));
03339                                                 }
03340                                                 else
03341                                                 {
03342                                                         attach_menu->append(new_item = new LLMenuItemCallGL(attachment->getName(), 
03343                                                                 NULL, //&LLObjectBridge::attachToAvatar,
03344                                                                 NULL, &attach_label, (void*)attachment));
03345                                                 }
03346 
03347                                                 LLSimpleListener* callback = mInventoryPanel->getListenerByName("Inventory.AttachObject");
03348 
03349                                                 if (callback)
03350                                                 {
03351                                                         new_item->addListener(callback, "on_click", LLSD(attachment->getName()));
03352                                                 }
03353                                         }
03354                                 }
03355                         }
03356                 }
03357         }
03358         hideContextEntries(menu, items, disabled_items);
03359 }
03360 
03361 BOOL LLObjectBridge::renameItem(const LLString& new_name)
03362 {
03363         if(!isItemRenameable()) return FALSE;
03364         LLPreview::rename(mUUID, getPrefix() + new_name);
03365         LLInventoryModel* model = mInventoryPanel->getModel();
03366         if(!model) return FALSE;
03367         LLViewerInventoryItem* item = getItem();
03368         if(item && (item->getName() != new_name))
03369         {
03370                 LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
03371                 new_item->rename(new_name);
03372                 buildDisplayName(new_item, mDisplayName);
03373                 new_item->updateServer(FALSE);
03374                 model->updateItem(new_item);
03375                 model->notifyObservers();
03376 
03377                 LLVOAvatar* avatar = gAgent.getAvatarObject();
03378                 if( avatar )
03379                 {
03380                         LLViewerObject* obj = avatar->getWornAttachment( item->getUUID() );
03381                         if( obj )
03382                         {
03383                                 gSelectMgr->deselectAll();
03384                                 gSelectMgr->addAsIndividual( obj, SELECT_ALL_TES, FALSE );
03385                                 gSelectMgr->selectionSetObjectName( new_name );
03386                                 gSelectMgr->deselectAll();
03387                         }
03388                 }
03389         }
03390         // return FALSE because we either notified observers (& therefore
03391         // rebuilt) or we didn't update.
03392         return FALSE;
03393 }
03394 
03395 // +=================================================+
03396 // |        LLLSLTextBridge                          |
03397 // +=================================================+
03398 
03399 LLString LLLSLTextBridge::sPrefix("Script: ");
03400 
03401 LLViewerImage* LLLSLTextBridge::getIcon() const
03402 {
03403         return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE);
03404 }
03405 
03406 void LLLSLTextBridge::openItem()
03407 {
03408         // See if we can bring an exiting preview to the front
03409         if(!LLPreview::show(mUUID))
03410         {
03411                 LLViewerInventoryItem* item = getItem();
03412                 if (item)
03413                 {
03414                         // There isn't one, so make a new preview
03415                         S32 left, top;
03416                         gFloaterView->getNewFloaterPosition(&left, &top);
03417                         LLRect rect = gSavedSettings.getRect("PreviewScriptRect");
03418                         rect.translate(left - rect.mLeft, top - rect.mTop);
03419                         
03420                         LLPreviewLSL* preview = new LLPreviewLSL("preview lsl text",
03421                                                                                          rect,
03422                                                                                          getPrefix() + item->getName(),
03423                                                                                          mUUID);
03424                         preview->setFocus(TRUE);
03425                         // keep onscreen
03426                         gFloaterView->adjustToFitScreen(preview, FALSE);
03427                 }
03428         }
03429 }
03430 
03431 // +=================================================+
03432 // |        LLWearableBridge                         |
03433 // +=================================================+
03434 
03435 // *NOTE: hack to get from avatar inventory to avatar
03436 void wear_inventory_item_on_avatar( LLInventoryItem* item )
03437 {
03438         if(item)
03439         {
03440                 lldebugs << "wear_inventory_item_on_avatar( " << item->getName()
03441                                  << " )" << llendl;
03442                         
03443                 gWearableList.getAsset(item->getAssetUUID(),
03444                                                            item->getName(),
03445                                                            item->getType(),
03446                                                            LLWearableBridge::onWearOnAvatarArrived,
03447                                                            new LLUUID(item->getUUID()));
03448         }
03449 }
03450 
03451 struct LLFoundData
03452 {
03453         LLFoundData(const LLUUID& item_id,
03454                                 const LLUUID& asset_id,
03455                                 const LLString& name,
03456                                 LLAssetType::EType asset_type) :
03457                 mItemID(item_id),
03458                 mAssetID(asset_id),
03459                 mName(name),
03460                 mAssetType(asset_type),
03461                 mWearable( NULL ) {}
03462         
03463         LLUUID mItemID;
03464         LLUUID mAssetID;
03465         LLString mName;
03466         LLAssetType::EType mAssetType;
03467         LLWearable* mWearable;
03468 };
03469 
03470 struct LLWearableHoldingPattern
03471 {
03472         LLWearableHoldingPattern() : mResolved(0) {}
03473         ~LLWearableHoldingPattern() { mFoundList.deleteAllData(); }
03474         LLDoubleLinkedList<LLFoundData> mFoundList;
03475         S32 mResolved;
03476 };
03477 
03478 
03479 class LLOutfitObserver : public LLInventoryFetchObserver
03480 {
03481 public:
03482         LLOutfitObserver(const LLUUID& cat_id, bool copy_items, bool append) :
03483                 mCatID(cat_id),
03484                 mCopyItems(copy_items),
03485                 mAppend(append)
03486         {}
03487         ~LLOutfitObserver() {}
03488         virtual void done(); //public
03489 
03490 protected:
03491         LLUUID mCatID;
03492         bool mCopyItems;
03493         bool mAppend;
03494 };
03495 
03496 class LLWearInventoryCategoryCallback : public LLInventoryCallback
03497 {
03498 public:
03499         LLWearInventoryCategoryCallback(const LLUUID& cat_id, bool append)
03500         {
03501                 mCatID = cat_id;
03502                 mAppend = append;
03503         }
03504         void fire(const LLUUID& item_id)
03505         {
03506                 /*
03507                  * Do nothing.  We only care about the destructor
03508                  *
03509                  * The reason for this is that this callback is used in a hack where the
03510                  * same callback is given to dozens of items, and the destructor is called
03511                  * after the last item has fired the event and dereferenced it -- if all
03512                  * the events actually fire!
03513                  */
03514         }
03515 
03516 protected:
03517         ~LLWearInventoryCategoryCallback()
03518         {
03519                 // Is the destructor called by ordinary dereference, or because the app's shutting down?
03520                 // If the inventory callback manager goes away, we're shutting down, no longer want the callback.
03521                 if( LLInventoryCallbackManager::is_instantiated() )
03522                 {
03523                         wear_inventory_category_on_avatar(gInventory.getCategory(mCatID), mAppend);
03524                 }
03525                 else
03526                 {
03527                         llwarns << "Dropping unhandled LLWearInventoryCategoryCallback" << llendl;
03528                 }
03529         }
03530 
03531 private:
03532         LLUUID mCatID;
03533         bool mAppend;
03534 };
03535 
03536 void LLOutfitObserver::done()
03537 {
03538         // We now have an outfit ready to be copied to agent inventory. Do
03539         // it, and wear that outfit normally.
03540         if(mCopyItems)
03541         {
03542                 LLInventoryCategory* cat = gInventory.getCategory(mCatID);
03543                 LLString name;
03544                 if(!cat)
03545                 {
03546                         // should never happen.
03547                         name = "New Outfit";
03548                 }
03549                 else
03550                 {
03551                         name = cat->getName();
03552                 }
03553                 LLViewerInventoryItem* item = NULL;
03554                 item_ref_t::iterator it = mComplete.begin();
03555                 item_ref_t::iterator end = mComplete.end();
03556                 LLUUID pid;
03557                 for(; it < end; ++it)
03558                 {
03559                         item = (LLViewerInventoryItem*)gInventory.getItem(*it);
03560                         if(item)
03561                         {
03562                                 if(LLInventoryType::IT_GESTURE == item->getInventoryType())
03563                                 {
03564                                         pid = gInventory.findCategoryUUIDForType(LLAssetType::AT_GESTURE);
03565                                 }
03566                                 else
03567                                 {
03568                                         pid = gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING);
03569                                 }
03570                                 break;
03571                         }
03572                 }
03573                 if(pid.isNull())
03574                 {
03575                         pid = gAgent.getInventoryRootID();
03576                 }
03577                 
03578                 LLUUID cat_id = gInventory.createNewCategory(
03579                         pid,
03580                         LLAssetType::AT_NONE,
03581                         name);
03582                 mCatID = cat_id;
03583                 LLPointer<LLInventoryCallback> cb = new LLWearInventoryCategoryCallback(mCatID, mAppend);
03584                 it = mComplete.begin();
03585                 for(; it < end; ++it)
03586                 {
03587                         item = (LLViewerInventoryItem*)gInventory.getItem(*it);
03588                         if(item)
03589                         {
03590                                 copy_inventory_item(
03591                                         gAgent.getID(),
03592                                         item->getPermissions().getOwner(),
03593                                         item->getUUID(),
03594                                         cat_id,
03595                                         std::string(),
03596                                         cb);
03597                         }
03598                 }
03599         }
03600         else
03601         {
03602                 // Wear the inventory category.
03603                 wear_inventory_category_on_avatar(gInventory.getCategory(mCatID), mAppend);
03604         }
03605 }
03606 
03607 class LLOutfitFetch : public LLInventoryFetchDescendentsObserver
03608 {
03609 public:
03610         LLOutfitFetch(bool copy_items, bool append) : mCopyItems(copy_items), mAppend(append) {}
03611         ~LLOutfitFetch() {}
03612         virtual void done();
03613 protected:
03614         bool mCopyItems;
03615         bool mAppend;
03616 };
03617 
03618 void LLOutfitFetch::done()
03619 {
03620         // What we do here is get the complete information on the items in
03621         // the library, and set up an observer that will wait for that to
03622         // happen.
03623         LLInventoryModel::cat_array_t cat_array;
03624         LLInventoryModel::item_array_t item_array;
03625         gInventory.collectDescendents(mCompleteFolders.front(),
03626                                                                   cat_array,
03627                                                                   item_array,
03628                                                                   LLInventoryModel::EXCLUDE_TRASH);
03629         S32 count = item_array.count();
03630         if(!count)
03631         {
03632                 llwarns << "Nothing fetched in category " << mCompleteFolders.front()
03633                                 << llendl;
03634                 dec_busy_count();
03635                 gInventory.removeObserver(this);
03636                 delete this;
03637                 return;
03638         }
03639 
03640         LLOutfitObserver* outfit;
03641         outfit = new LLOutfitObserver(mCompleteFolders.front(), mCopyItems, mAppend);
03642         LLInventoryFetchObserver::item_ref_t ids;
03643         for(S32 i = 0; i < count; ++i)
03644         {
03645                 ids.push_back(item_array.get(i)->getUUID());
03646         }
03647 
03648         // clean up, and remove this as an observer since the call to the
03649         // outfit could notify observers and throw us into an infinite
03650         // loop.
03651         dec_busy_count();
03652         gInventory.removeObserver(this);
03653         delete this;
03654 
03655         // increment busy count and either tell the inventory to check &
03656         // call done, or add this object to the inventory for observation.
03657         inc_busy_count();
03658 
03659         // do the fetch
03660         outfit->fetchItems(ids);
03661         if(outfit->isEverythingComplete())
03662         {
03663                 // everything is already here - call done.
03664                 outfit->done();
03665         }
03666         else
03667         {
03668                 // it's all on it's way - add an observer, and the inventory
03669                 // will call done for us when everything is here.
03670                 gInventory.addObserver(outfit);
03671         }
03672 }
03673 
03674 void wear_outfit_by_name(const char* name)
03675 {
03676         llinfos << "Wearing category " << name << llendl;
03677         inc_busy_count();
03678 
03679         LLInventoryModel::cat_array_t cat_array;
03680         LLInventoryModel::item_array_t item_array;
03681         LLNameCategoryCollector has_name(name);
03682         gInventory.collectDescendentsIf(gAgent.getInventoryRootID(),
03683                                                                         cat_array,
03684                                                                         item_array,
03685                                                                         LLInventoryModel::EXCLUDE_TRASH,
03686                                                                         has_name);
03687         bool copy_items = false;
03688         LLInventoryCategory* cat = NULL;
03689         if (cat_array.count() > 0)
03690         {
03691                 // Just wear the first one that matches
03692                 cat = cat_array.get(0);
03693         }
03694         else
03695         {
03696                 gInventory.collectDescendentsIf(LLUUID::null,
03697                                                                                 cat_array,
03698                                                                                 item_array,
03699                                                                                 LLInventoryModel::EXCLUDE_TRASH,
03700                                                                                 has_name);
03701                 if(cat_array.count() > 0)
03702                 {
03703                         cat = cat_array.get(0);
03704                         copy_items = true;
03705                 }
03706         }
03707 
03708         if(cat)
03709         {
03710                 wear_inventory_category(cat, copy_items, false);
03711         }
03712         else
03713         {
03714                 llwarns << "Couldn't find outfit " <<name<< " in wear_outfit_by_name()"
03715                                 << llendl;
03716         }
03717 
03718         dec_busy_count();
03719 }
03720 
03721 void wear_inventory_category(LLInventoryCategory* category, bool copy, bool append)
03722 {
03723         if(!category) return;
03724 
03725         lldebugs << "wear_inventory_category( " << category->getName()
03726                          << " )" << llendl;
03727         // What we do here is get the complete information on the items in
03728         // the inventory, and set up an observer that will wait for that to
03729         // happen.
03730         LLOutfitFetch* outfit;
03731         outfit = new LLOutfitFetch(copy, append);
03732         LLInventoryFetchDescendentsObserver::folder_ref_t folders;
03733         folders.push_back(category->getUUID());
03734         outfit->fetchDescendents(folders);
03735         inc_busy_count();
03736         if(outfit->isEverythingComplete())
03737         {
03738                 // everything is already here - call done.
03739                 outfit->done();
03740         }
03741         else
03742         {
03743                 // it's all on it's way - add an observer, and the inventory
03744                 // will call done for us when everything is here.
03745                 gInventory.addObserver(outfit);
03746         }
03747 }
03748 
03749 // *NOTE: hack to get from avatar inventory to avatar
03750 void wear_inventory_category_on_avatar( LLInventoryCategory* category, BOOL append )
03751 {
03752         // Avoid unintentionally overwriting old wearables.  We have to do
03753         // this up front to avoid having to deal with the case of multiple
03754         // wearables being dirty.
03755         if(!category) return;
03756         lldebugs << "wear_inventory_category_on_avatar( " << category->getName()
03757                          << " )" << llendl;
03758                                 
03759         LLWearInfo* userdata = new LLWearInfo;
03760         userdata->mAppend = append;
03761         userdata->mCategoryID = category->getUUID();
03762 
03763         if( gFloaterCustomize )
03764         {
03765                 gFloaterCustomize->askToSaveAllIfDirty(
03766                         wear_inventory_category_on_avatar_step2,
03767                         userdata);
03768         }
03769         else
03770         {
03771                 wear_inventory_category_on_avatar_step2(
03772                         TRUE,
03773                         userdata );
03774         }
03775 }
03776 
03777 
03778 void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata )
03779 {
03780         LLWearInfo* wear_info = (LLWearInfo*)userdata;
03781         if (!wear_info) return;
03782 
03783         // Find all the wearables that are in the category's subtree.   
03784         lldebugs << "wear_inventory_category_on_avatar_step2()" << llendl;
03785         if(proceed)
03786         {
03787                 LLInventoryModel::cat_array_t cat_array;
03788                 LLInventoryModel::item_array_t item_array;
03789                 LLFindWearables is_wearable;
03790                 gInventory.collectDescendentsIf(wear_info->mCategoryID,
03791                                                                                 cat_array,
03792                                                                                 item_array,
03793                                                                                 LLInventoryModel::EXCLUDE_TRASH,
03794                                                                                 is_wearable);
03795                 S32 i;
03796                 S32 wearable_count = item_array.count();
03797 
03798                 LLInventoryModel::cat_array_t   obj_cat_array;
03799                 LLInventoryModel::item_array_t  obj_item_array;
03800                 LLIsType is_object( LLAssetType::AT_OBJECT );
03801                 gInventory.collectDescendentsIf(wear_info->mCategoryID,
03802                                                                                 obj_cat_array,
03803                                                                                 obj_item_array,
03804                                                                                 LLInventoryModel::EXCLUDE_TRASH,
03805                                                                                 is_object);
03806                 S32 obj_count = obj_item_array.count();
03807 
03808                 // Find all gestures in this folder
03809                 LLInventoryModel::cat_array_t   gest_cat_array;
03810                 LLInventoryModel::item_array_t  gest_item_array;
03811                 LLIsType is_gesture( LLAssetType::AT_GESTURE );
03812                 gInventory.collectDescendentsIf(wear_info->mCategoryID,
03813                                                                                 gest_cat_array,
03814                                                                                 gest_item_array,
03815                                                                                 LLInventoryModel::EXCLUDE_TRASH,
03816                                                                                 is_gesture);
03817                 S32 gest_count = gest_item_array.count();
03818 
03819                 if( !wearable_count && !obj_count && !gest_count)
03820                 {
03821                         gViewerWindow->alertXml("CouldNotPutOnOutfit");
03822                         delete wear_info;
03823                         return;
03824                 }
03825 
03826                 // Processes that take time should show the busy cursor
03827                 if (wearable_count > 0 || obj_count > 0)
03828                 {
03829                         inc_busy_count();
03830                 }
03831 
03832                 // Activate all gestures in this folder
03833                 if (gest_count > 0)
03834                 {
03835                         llinfos << "Activating " << gest_count << " gestures" << llendl;
03836 
03837                         gGestureManager.activateGestures(gest_item_array);
03838 
03839                         // Update the inventory item labels to reflect the fact
03840                         // they are active.
03841                         LLViewerInventoryCategory* catp = gInventory.getCategory(wear_info->mCategoryID);
03842                         if (catp)
03843                         {
03844                                 gInventory.updateCategory(catp);
03845                                 gInventory.notifyObservers();
03846                         }
03847                 }
03848 
03849                 if(wearable_count > 0)
03850                 {
03851                         // Note: can't do normal iteration, because if all the
03852                         // wearables can be resolved immediately, then the
03853                         // callback will be called (and this object deleted)
03854                         // before the final getNextData().
03855                         LLWearableHoldingPattern* holder = new LLWearableHoldingPattern;
03856                         LLFoundData* found;
03857                         LLDynamicArray<LLFoundData*> found_container;
03858                         for(i = 0; i  < wearable_count; ++i)
03859                         {
03860                                 found = new LLFoundData(item_array.get(i)->getUUID(),
03861                                                                                 item_array.get(i)->getAssetUUID(),
03862                                                                                 item_array.get(i)->getName(),
03863                                                                                 item_array.get(i)->getType());
03864                                 holder->mFoundList.addData(found);
03865                                 found_container.put(found);
03866                         }
03867                         for(i = 0; i < wearable_count; ++i)
03868                         {
03869                                 gAddToOutfit = wear_info->mAppend;
03870 
03871                                 found = found_container.get(i);
03872                                 gWearableList.getAsset(found->mAssetID,
03873                                                                                 found->mName,
03874                                                                            found->mAssetType,
03875                                                                            wear_inventory_category_on_avatar_loop,
03876                                                                            (void*)holder);
03877                         }
03878                 }
03879 
03880 
03881                 //If not appending and the folder doesn't contain only gestures, take off all attachments.
03882                 if (!wear_info->mAppend 
03883                         && !(wearable_count == 0 && obj_count == 0 && gest_count > 0) )
03884                 {
03885                         LLAgent::userRemoveAllAttachments(NULL);
03886                 }
03887 
03888                 if( obj_count > 0 )
03889                 {
03890                         // We've found some attachements.  Add these.
03891 
03892                         LLVOAvatar* avatar = gAgent.getAvatarObject();
03893                         if( avatar )
03894                         {
03895                                 // Build a compound message to send all the objects that need to be rezzed.
03896 
03897                                 // Limit number of packets to send
03898                                 const S32 MAX_PACKETS_TO_SEND = 10;
03899                                 const S32 OBJECTS_PER_PACKET = 4;
03900                                 const S32 MAX_OBJECTS_TO_SEND = MAX_PACKETS_TO_SEND * OBJECTS_PER_PACKET;
03901                                 if( obj_count > MAX_OBJECTS_TO_SEND )
03902                                 {
03903                                         obj_count = MAX_OBJECTS_TO_SEND;
03904                                 }
03905                                 
03906                                 // Create an id to keep the parts of the compound message together
03907                                 LLUUID compound_msg_id;
03908                                 compound_msg_id.generate();
03909                                 LLMessageSystem* msg = gMessageSystem;
03910 
03911                                 for(i = 0; i < obj_count; ++i)
03912                                 {
03913                                         if( 0 == (i % OBJECTS_PER_PACKET) )
03914                                         {
03915                                                 // Start a new message chunk
03916                                                 msg->newMessageFast(_PREHASH_RezMultipleAttachmentsFromInv);
03917                                                 msg->nextBlockFast(_PREHASH_AgentData);
03918                                                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
03919                                                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
03920                                                 msg->nextBlockFast(_PREHASH_HeaderData);
03921                                                 msg->addUUIDFast(_PREHASH_CompoundMsgID, compound_msg_id );
03922                                                 msg->addU8Fast(_PREHASH_TotalObjects, obj_count );
03923                                                 msg->addBOOLFast(_PREHASH_FirstDetachAll, !wear_info->mAppend );
03924                                         }
03925 
03926                                         LLInventoryItem* item = obj_item_array.get(i);
03927                                         msg->nextBlockFast(_PREHASH_ObjectData );
03928                                         msg->addUUIDFast(_PREHASH_ItemID, item->getUUID() );
03929                                         msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
03930                                         msg->addU8Fast(_PREHASH_AttachmentPt, 0 );      // Wear at the previous or default attachment point
03931                                         pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
03932                                         msg->addStringFast(_PREHASH_Name, item->getName());
03933                                         msg->addStringFast(_PREHASH_Description, item->getDescription());
03934 
03935                                         if( (i+1 == obj_count) || ((OBJECTS_PER_PACKET-1) == (i % OBJECTS_PER_PACKET)) )
03936                                         {
03937                                                 // End of message chunk
03938                                                 msg->sendReliable( gAgent.getRegion()->getHost() );
03939                                         }
03940                                 }
03941                         }
03942                 }
03943         }
03944         delete wear_info;
03945         wear_info = NULL;
03946 }
03947 
03948 void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void* data)
03949 {
03950         LLWearableHoldingPattern* holder = (LLWearableHoldingPattern*)data;
03951         BOOL append= gAddToOutfit;
03952         
03953         if(wearable)
03954         {
03955                 for(LLFoundData* data = holder->mFoundList.getFirstData();
03956                         data;
03957                         data = holder->mFoundList.getNextData() )
03958                 {
03959                         if(wearable->getID() == data->mAssetID)
03960                         {
03961                                 data->mWearable = wearable;
03962                                 break;
03963                         }
03964                 }
03965         }
03966         holder->mResolved += 1;
03967         if(holder->mResolved >= holder->mFoundList.getLength())
03968         {
03969                 wear_inventory_category_on_avatar_step3(holder, append);
03970         }
03971 }
03972 
03973 void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append)
03974 {
03975         lldebugs << "wear_inventory_category_on_avatar_step3()" << llendl;
03976         LLInventoryItem::item_array_t items;
03977         LLDynamicArray< LLWearable* > wearables;
03978 
03979         // For each wearable type, find the first instance in the category
03980         // that we recursed through.
03981         for( S32 i = 0; i < WT_COUNT; i++ )
03982         {
03983                 for(LLFoundData* data = holder->mFoundList.getFirstData();
03984                         data;
03985                         data = holder->mFoundList.getNextData())
03986                 {
03987                         LLWearable* wearable = data->mWearable;
03988                         if( wearable && ((S32)wearable->getType() == i) )
03989                         {
03990                                 LLViewerInventoryItem* item;
03991                                 item = (LLViewerInventoryItem*)gInventory.getItem(data->mItemID);
03992                                 if( item && (item->getAssetUUID() == wearable->getID()) )
03993                                 {
03994                                 //RN: after discussing with Brashears, I disabled this code
03995                                 //Metadata should reside in the item, not the asset
03996                                 //And this code does not handle failed asset uploads properly
03997 //                                      if(!wearable->isMatchedToInventoryItem(item ))
03998 //                                      {
03999 //                                              wearable = gWearableList.createWearableMatchedToInventoryItem( wearable, item );
04000 //                                              // Now that we have an asset that matches the
04001 //                                              // item, update the item to point to the new
04002 //                                              // asset.
04003 //                                              item->setAssetUUID(wearable->getID());
04004 //                                              item->updateAssetOnServer();
04005 //                                      }
04006                                         items.put(item);
04007                                         wearables.put(wearable);
04008                                 }
04009                                 break;
04010                         }
04011                 }
04012         }
04013 
04014         if(wearables.count() > 0)
04015         {
04016                 gAgent.setWearableOutfit(items, wearables, !append);
04017                 gInventory.notifyObservers();
04018         }
04019 
04020         delete holder;
04021 
04022         dec_busy_count();
04023 }
04024 
04025 void remove_inventory_category_from_avatar( LLInventoryCategory* category )
04026 {
04027         if(!category) return;
04028         lldebugs << "remove_inventory_category_from_avatar( " << category->getName()
04029                          << " )" << llendl;
04030                          
04031         
04032         LLUUID* uuid    = new LLUUID(category->getUUID());
04033 
04034         if( gFloaterCustomize )
04035         {
04036                 gFloaterCustomize->askToSaveAllIfDirty(
04037                         remove_inventory_category_from_avatar_step2,
04038                         uuid);
04039         }
04040         else
04041         {
04042                 remove_inventory_category_from_avatar_step2(
04043                         TRUE,
04044                         uuid );
04045         }
04046 }
04047 
04048 
04049 void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata)
04050 {
04051 
04052         // Find all the wearables that are in the category's subtree.
04053         LLUUID* category_id = (LLUUID *)userdata;
04054         
04055         lldebugs << "remove_inventory_category_from_avatar_step2()" << llendl;
04056         if(proceed)
04057         {
04058                 LLInventoryModel::cat_array_t cat_array;
04059                 LLInventoryModel::item_array_t item_array;
04060                 LLFindWearables is_wearable;
04061                 gInventory.collectDescendentsIf(*category_id,
04062                                                                                 cat_array,
04063                                                                                 item_array,
04064                                                                                 LLInventoryModel::EXCLUDE_TRASH,
04065                                                                                 is_wearable);
04066                 S32 i;
04067                 S32 wearable_count = item_array.count();
04068 
04069                 LLInventoryModel::cat_array_t   obj_cat_array;
04070                 LLInventoryModel::item_array_t  obj_item_array;
04071                 LLIsType is_object( LLAssetType::AT_OBJECT );
04072                 gInventory.collectDescendentsIf(*category_id,
04073                                                                                 obj_cat_array,
04074                                                                                 obj_item_array,
04075                                                                                 LLInventoryModel::EXCLUDE_TRASH,
04076                                                                                 is_object);
04077                 S32 obj_count = obj_item_array.count();
04078 
04079                 // Find all gestures in this folder
04080                 LLInventoryModel::cat_array_t   gest_cat_array;
04081                 LLInventoryModel::item_array_t  gest_item_array;
04082                 LLIsType is_gesture( LLAssetType::AT_GESTURE );
04083                 gInventory.collectDescendentsIf(*category_id,
04084                                                                                 gest_cat_array,
04085                                                                                 gest_item_array,
04086                                                                                 LLInventoryModel::EXCLUDE_TRASH,
04087                                                                                 is_gesture);
04088                 S32 gest_count = gest_item_array.count();
04089 
04090                 if (wearable_count > 0) //Loop through wearables.  If worn, remove.
04091                 {
04092                         for(i = 0; i  < wearable_count; ++i)
04093                         {
04094                                 if( gAgent.isWearingItem (item_array.get(i)->getUUID()) )
04095                                 {
04096                                         gWearableList.getAsset(item_array.get(i)->getAssetUUID(),
04097                                                                         item_array.get(i)->getName(),
04098                                                                    item_array.get(i)->getType(),
04099                                                                     LLWearableBridge::onRemoveFromAvatarArrived,
04100                                                                    new LLUUID(item_array.get(i)->getUUID()));
04101 
04102                                 }
04103                         }
04104                 }
04105                 
04106                 
04107                 if (obj_count > 0)
04108                 {
04109                         for(i = 0; i  < obj_count; ++i)
04110                         {
04111                                 gMessageSystem->newMessageFast(_PREHASH_DetachAttachmentIntoInv);
04112                                 gMessageSystem->nextBlockFast(_PREHASH_ObjectData );
04113                                 gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
04114                                 gMessageSystem->addUUIDFast(_PREHASH_ItemID, obj_item_array.get(i)->getUUID() );
04115 
04116                                 gMessageSystem->sendReliable( gAgent.getRegion()->getHost() );
04117 
04118                                 // this object might have been selected, so let the selection manager know it's gone now
04119                                 LLViewerObject *found_obj = gObjectList.findObject( obj_item_array.get(i)->getUUID());
04120                                 if (found_obj)
04121                                 {
04122                                         gSelectMgr->remove(found_obj);
04123                                 }
04124                                 else
04125                                 {
04126                                         llwarns << "object not found, ignoring" << llendl;
04127                                 }
04128                         }
04129                 }
04130 
04131                 if (gest_count > 0)
04132                 {
04133                         for(i = 0; i  < gest_count; ++i)
04134                         {
04135                                 if ( gGestureManager.isGestureActive( gest_item_array.get(i)->getUUID()) )
04136                                 {
04137                                         gGestureManager.deactivateGesture( gest_item_array.get(i)->getUUID() );
04138                                         gInventory.updateItem( gest_item_array.get(i) );
04139                                         gInventory.notifyObservers();
04140                                 }
04141 
04142                         }
04143                 }
04144         }
04145         delete category_id;
04146         category_id = NULL;
04147 }
04148 
04149 BOOL LLWearableBridge::renameItem(const LLString& new_name)
04150 {
04151         if( gAgent.isWearingItem( mUUID ) )
04152         {
04153                 gAgent.setWearableName( mUUID, new_name );
04154         }
04155         return LLItemBridge::renameItem(new_name);
04156 }
04157 
04158 BOOL LLWearableBridge::isItemRemovable()
04159 {
04160         if(gAgent.isWearingItem(mUUID)) return FALSE;
04161         return LLInvFVBridge::isItemRemovable();
04162 }
04163 
04164 LLFontGL::StyleFlags LLWearableBridge::getLabelStyle() const
04165 { 
04166         if( gAgent.isWearingItem( mUUID ) )
04167         {
04168                 // llinfos << "BOLD" << llendl;
04169                 return LLFontGL::BOLD;
04170         }
04171         else
04172         {
04173                 return LLFontGL::NORMAL;
04174         }
04175 }
04176 
04177 LLString LLWearableBridge::getLabelSuffix() const
04178 {
04179         if( gAgent.isWearingItem( mUUID ) )
04180         {
04181                 return LLItemBridge::getLabelSuffix() + " (worn)";
04182         }
04183         else
04184         {
04185                 return LLItemBridge::getLabelSuffix();
04186         }
04187 }
04188 
04189 LLViewerImage* LLWearableBridge::getIcon() const
04190 {
04191         return get_item_icon(mAssetType, mInvType, mWearableType, FALSE);
04192 }
04193 
04194 // virtual
04195 void LLWearableBridge::performAction(LLFolderView* folder, LLInventoryModel* model, LLString action)
04196 {
04197         if ("wear" == action)
04198         {
04199                 wearOnAvatar();
04200         }
04201         else if ("edit" == action)
04202         {
04203                 editOnAvatar();
04204                 return;
04205         }
04206         else if ("take_off" == action)
04207         {
04208                 if(gAgent.isWearingItem(mUUID))
04209                 {
04210                         LLViewerInventoryItem* item = getItem();
04211                         if (item)
04212                         {
04213                                 gWearableList.getAsset(item->getAssetUUID(),
04214                                                                                 item->getName(),
04215                                                                         item->getType(),
04216                                                                         LLWearableBridge::onRemoveFromAvatarArrived,
04217                                                                         new LLUUID(mUUID));
04218                         }
04219                 }
04220         }
04221         else LLItemBridge::performAction(folder, model, action);
04222 }
04223 
04224 void LLWearableBridge::openItem()
04225 {
04226         if( isInTrash() )
04227         {
04228                 gViewerWindow->alertXml("CannotWearTrash");
04229         }
04230         else if(isAgentInventory())
04231         {
04232                 if( !gAgent.isWearingItem( mUUID ) )
04233                 {
04234                         wearOnAvatar();
04235                 }
04236         }
04237         else
04238         {
04239                 // must be in the inventory library. copy it to our inventory
04240                 // and put it on right away.
04241                 LLViewerInventoryItem* item = getItem();
04242                 if(item && item->isComplete())
04243                 {
04244                         LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback();
04245                         copy_inventory_item(
04246                                 gAgent.getID(),
04247                                 item->getPermissions().getOwner(),
04248                                 item->getUUID(),
04249                                 LLUUID::null,
04250                                 std::string(),
04251                                 cb);
04252                 }
04253                 else if(item)
04254                 {
04255                         // *TODO: We should fetch the item details, and then do
04256                         // the operation above.
04257                         gViewerWindow->alertXml("CannotWearInfoNotComplete");
04258                 }
04259         }
04260 }
04261 
04262 void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
04263 {
04264         lldebugs << "LLWearableBridge::buildContextMenu()" << llendl;
04265         std::vector<LLString> items;
04266         std::vector<LLString> disabled_items;
04267         if(isInTrash())
04268         {
04269                 items.push_back("Purge Item");
04270                 if (!isItemRemovable())
04271                 {
04272                         disabled_items.push_back("Purge Item");
04273                 }
04274 
04275                 items.push_back("Restore Item");
04276         }
04277         else
04278         {       // FWIW, it looks like SUPPRESS_OPEN_ITEM is not set anywhere
04279                 BOOL no_open = ((flags & SUPPRESS_OPEN_ITEM) == SUPPRESS_OPEN_ITEM);
04280 
04281                 // If we have clothing, don't add "Open" as it's the same action as "Wear"   SL-18976
04282                 LLViewerInventoryItem* item = getItem();
04283                 if( !no_open && item )
04284                 {
04285                         no_open = (item->getType() == LLAssetType::AT_CLOTHING) ||
04286                                           (item->getType() == LLAssetType::AT_BODYPART);
04287                 }
04288                 if (!no_open)
04289                 {
04290                         items.push_back("Open");
04291                 }
04292 
04293                 items.push_back("Properties");
04294 
04295                 getClipboardEntries(true, items, disabled_items, flags);
04296 
04297                 items.push_back("Wearable Separator");
04298                 items.push_back("Wearable Wear");
04299                 items.push_back("Wearable Edit");
04300                 if ((flags & FIRST_SELECTED_ITEM) == 0)
04301                 {
04302                         disabled_items.push_back("Wearable Edit");
04303                 }
04304                 /*menu.appendSeparator();
04305                 menu.append(new LLMenuItemCallGL("Wear",
04306                                                                                  LLWearableBridge::onWearOnAvatar,
04307                                                                                  LLWearableBridge::canWearOnAvatar,
04308                                                                                  (void*)this));
04309                 menu.append(new LLMenuItemCallGL("Edit",
04310                                                                                  LLWearableBridge::onEditOnAvatar,
04311                                                                                  LLWearableBridge::canEditOnAvatar,
04312                                                                                  (void*)this));*/
04313 
04314                 if( item && (item->getType() == LLAssetType::AT_CLOTHING) )
04315                 {
04316                         items.push_back("Take Off");
04317                         /*menu.append(new LLMenuItemCallGL("Take Off",
04318                                                                                          LLWearableBridge::onRemoveFromAvatar,
04319                                                                                          LLWearableBridge::canRemoveFromAvatar,
04320                                                                                          (void*)this));*/
04321                 }
04322         }
04323         hideContextEntries(menu, items, disabled_items);
04324 }
04325 
04326 // Called from menus
04327 // static
04328 BOOL LLWearableBridge::canWearOnAvatar(void* user_data)
04329 {
04330         LLWearableBridge* self = (LLWearableBridge*)user_data;
04331         if(!self) return FALSE;
04332         if(!self->isAgentInventory())
04333         {
04334                 LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem();
04335                 if(!item || !item->isComplete()) return FALSE;
04336         }
04337         return (!gAgent.isWearingItem(self->mUUID));
04338 }
04339 
04340 // Called from menus
04341 // static
04342 void LLWearableBridge::onWearOnAvatar(void* user_data)
04343 {
04344         LLWearableBridge* self = (LLWearableBridge*)user_data;
04345         if(!self) return;
04346         self->wearOnAvatar();
04347 }
04348 
04349 void LLWearableBridge::wearOnAvatar()
04350 {
04351         // Don't wear anything until initial wearables are loaded, can
04352         // destroy clothing items.
04353         if (!gAgent.areWearablesLoaded()) 
04354         {
04355                 gViewerWindow->alertXml("CanNotChangeAppearanceUntilLoaded");
04356                 return;
04357         }
04358 
04359         LLViewerInventoryItem* item = getItem();
04360         if(item)
04361         {
04362                 if(!isAgentInventory())
04363                 {
04364                         LLPointer<LLInventoryCallback> cb = new WearOnAvatarCallback();
04365                         copy_inventory_item(
04366                                 gAgent.getID(),
04367                                 item->getPermissions().getOwner(),
04368                                 item->getUUID(),
04369                                 LLUUID::null,
04370                                 std::string(),
04371                                 cb);
04372                 }
04373                 else
04374                 {
04375                         wear_inventory_item_on_avatar(item);
04376                 }
04377         }
04378 }
04379 
04380 // static
04381 void LLWearableBridge::onWearOnAvatarArrived( LLWearable* wearable, void* userdata )
04382 {
04383         LLUUID* item_id = (LLUUID*) userdata;
04384         if(wearable)
04385         {
04386                 LLViewerInventoryItem* item = NULL;
04387                 item = (LLViewerInventoryItem*)gInventory.getItem(*item_id);
04388                 if(item)
04389                 {
04390                         if(item->getAssetUUID() == wearable->getID())
04391                         {
04392                                 //RN: after discussing with Brashears, I disabled this code
04393                                 //Metadata should reside in the item, not the asset
04394                                 //And this code does not handle failed asset uploads properly
04395 
04396 //                              if(!wearable->isMatchedToInventoryItem(item))
04397 //                              {
04398 //                                      LLWearable* new_wearable = gWearableList.createWearableMatchedToInventoryItem( wearable, item );
04399 //
04400 //                                      // Now that we have an asset that matches the
04401 //                                      // item, update the item to point to the new
04402 //                                      // asset.
04403 //                                      item->setAssetUUID(new_wearable->getID());
04404 //                                      item->updateAssetOnServer();
04405 //                                      wearable = new_wearable;
04406 //                              }
04407                                 gAgent.setWearable(item, wearable);
04408                                 gInventory.notifyObservers();
04409                                 //self->getFolderItem()->refreshFromRoot();
04410                         }
04411                         else
04412                         {
04413                                 llinfos << "By the time wearable asset arrived, its inv item already pointed to a different asset." << llendl;
04414                         }
04415                 }
04416         }
04417         delete item_id;
04418 }
04419 
04420 // static
04421 BOOL LLWearableBridge::canEditOnAvatar(void* user_data)
04422 {
04423         LLWearableBridge* self = (LLWearableBridge*)user_data;
04424         if(!self) return FALSE;
04425 
04426         return (gAgent.isWearingItem(self->mUUID));
04427 }
04428 
04429 // static 
04430 void LLWearableBridge::onEditOnAvatar(void* user_data)
04431 {
04432         LLWearableBridge* self = (LLWearableBridge*)user_data;
04433         if(self)
04434         {
04435                 self->editOnAvatar();
04436         }
04437 }
04438 
04439 void LLWearableBridge::editOnAvatar()
04440 {
04441         LLWearable* wearable = gAgent.getWearableFromWearableItem(mUUID);
04442         if( wearable )
04443         {
04444                 // Set the tab to the right wearable.
04445                 LLFloaterCustomize::setCurrentWearableType( wearable->getType() );
04446 
04447                 if( CAMERA_MODE_CUSTOMIZE_AVATAR != gAgent.getCameraMode() )
04448                 {
04449                         // Start Avatar Customization
04450                         gAgent.changeCameraToCustomizeAvatar();
04451                 }
04452         }
04453 }
04454 
04455 // static
04456 BOOL LLWearableBridge::canRemoveFromAvatar(void* user_data)
04457 {
04458         LLWearableBridge* self = (LLWearableBridge*)user_data;
04459         if( self && (LLAssetType::AT_BODYPART != self->mAssetType) )
04460         {
04461                 return gAgent.isWearingItem( self->mUUID );
04462         }
04463         return FALSE;
04464 }
04465 
04466 // static 
04467 void LLWearableBridge::onRemoveFromAvatar(void* user_data)
04468 {
04469         LLWearableBridge* self = (LLWearableBridge*)user_data;
04470         if(!self) return;
04471         if(gAgent.isWearingItem(self->mUUID))
04472         {
04473                 LLViewerInventoryItem* item = self->getItem();
04474                 if (item)
04475                 {
04476                         gWearableList.getAsset(item->getAssetUUID(),
04477                                                                         item->getName(),
04478                                                                    item->getType(),
04479                                                                    onRemoveFromAvatarArrived,
04480                                                                    new LLUUID(self->mUUID));
04481                 }
04482         }
04483 }
04484 
04485 // static
04486 void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable,
04487                                                                                                  void* userdata)
04488 {
04489         LLUUID* item_id = (LLUUID*) userdata;
04490         if(wearable)
04491         {
04492                 if( gAgent.isWearingItem( *item_id ) )
04493                 {
04494                         EWearableType type = wearable->getType();
04495         
04496                         if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR ) ) //&&
04498                         {
04499                                 gAgent.removeWearable( type );
04500                         }
04501                 }
04502         }
04503         delete item_id;
04504 }

Generated on Thu Jul 1 06:08:45 2010 for Second Life Viewer by  doxygen 1.4.7