diff options
-rw-r--r-- | indra/llcommon/llassettype.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llagentwearables.cpp | 258 | ||||
-rw-r--r-- | indra/newview/llagentwearables.h | 40 | ||||
-rw-r--r-- | indra/newview/llfloaterinventory.cpp | 5 | ||||
-rw-r--r-- | indra/newview/llfolderviewitem.cpp | 8 | ||||
-rw-r--r-- | indra/newview/llinventorybridge.cpp | 109 | ||||
-rw-r--r-- | indra/newview/llinventorybridge.h | 3 | ||||
-rw-r--r-- | indra/newview/llinventoryfilter.cpp | 10 | ||||
-rw-r--r-- | indra/newview/llinventorymodel.cpp | 57 | ||||
-rw-r--r-- | indra/newview/llviewerinventory.cpp | 5 | ||||
-rw-r--r-- | indra/newview/llvoavatarself.cpp | 13 | ||||
-rw-r--r-- | indra/newview/llvoavatarself.h | 1 | ||||
-rw-r--r-- | indra/newview/skins/default/textures/textures.xml | 2 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_customize.xml | 10 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/floater_inventory.xml | 16 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/menu_inventory.xml | 32 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml | 8 | ||||
-rw-r--r-- | indra/newview/skins/default/xui/en/strings.xml | 1 |
18 files changed, 336 insertions, 246 deletions
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 835cdbca04..e595cc1f8b 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -101,7 +101,7 @@ LLAssetDictionary::LLAssetDictionary() addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", "Uncompressed Images", DAD_NONE, FALSE, TRUE)); addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", "Uncompressed Images", DAD_NONE, FALSE, TRUE)); addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", "Animations", DAD_ANIMATION, FALSE, TRUE)); - addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", "Gestures", DAD_GESTURE, FALSE, TRUE)); + addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", "Gestures", DAD_GESTURE, TRUE, TRUE)); addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", "New Folder", DAD_NONE, FALSE, TRUE)); addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "favorite", "favorite", DAD_NONE, FALSE, TRUE)); @@ -116,7 +116,7 @@ LLAssetDictionary::LLAssetDictionary() } addEntry(LLAssetType::AT_CURRENT_OUTFIT, new AssetEntry("CURRENT", "current", "current outfit", "Current Outfit", DAD_CATEGORY, FALSE, TRUE)); - addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", "Outfit", DAD_CATEGORY, TRUE, FALSE)); + addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", "New Outfit", DAD_CATEGORY, TRUE, FALSE)); addEntry(LLAssetType::AT_MY_OUTFITS, new AssetEntry("MY_OUTFITS", "my_otfts", "my outfits", "My Outfits", DAD_CATEGORY, FALSE, TRUE)); addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, "New Folder", DAD_NONE, FALSE, FALSE)); diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp index 4834b31bc7..1b496d44cd 100644 --- a/indra/newview/llagentwearables.cpp +++ b/indra/newview/llagentwearables.cpp @@ -44,12 +44,42 @@ #include "llvoavatarself.h" #include "llwearable.h" #include "llwearablelist.h" +#include "llgesturemgr.h" #include <boost/scoped_ptr.hpp> -// For viewer2.0 internal demo, don't use current outfit folder contents at all during initial startup. Will reenable -// this once we're sure this works completely. -// #define USE_CURRENT_OUTFIT_FOLDER +#define USE_CURRENT_OUTFIT_FOLDER + +//-------------------------------------------------------------------- +// Classes for fetching initial wearables data +//-------------------------------------------------------------------- +// Outfit folder fetching callback structure. +class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver +{ +public: + LLInitialWearablesFetch() {} + ~LLInitialWearablesFetch() {} + virtual void done(); + + struct InitialWearableData + { + EWearableType mType; + U32 mIndex; + LLUUID mItemID; + LLUUID mAssetID; + InitialWearableData(EWearableType type, U32 index, LLUUID itemID, LLUUID assetID) : + mType(type), mIndex(index), mItemID(itemID), mAssetID(assetID) { } + }; + + typedef std::vector<InitialWearableData> initial_wearable_data_vec_t; + initial_wearable_data_vec_t mCOFInitialWearables; // Wearables from the Current Outfit Folder + initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg + +protected: + void processInitialWearables(); +}; + + LLAgentWearables gAgentWearables; @@ -668,6 +698,9 @@ BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id, BOOL include_linked_ // MULTI-WEARABLE: update for multiple // static +// ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume +// that viewers have a Current Outfit Folder and won't need this message, and thus +// we can remove/ignore this whole function. void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data) { // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates @@ -696,7 +729,7 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs // Get the UUID of the current outfit folder (will be created if it doesn't exist) LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); - LLOutfitFolderFetch* outfit = new LLOutfitFolderFetch(); + LLInitialWearablesFetch* outfit = new LLInitialWearablesFetch(); //lldebugs << "processAgentInitialWearablesUpdate()" << llendl; // Add wearables @@ -733,8 +766,8 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs // MULTI-WEARABLE: TODO: update once messages change. Currently use results to populate the zeroth element. // Store initial wearables data until we know whether we have the current outfit folder or need to use the data. - InitialWearableData * temp_wearable_data = new InitialWearableData(type, 0, item_id, asset_id); // MULTI-WEARABLE: update - outfit->mAgentInitialWearables.push_back(temp_wearable_data); + LLInitialWearablesFetch::InitialWearableData wearable_data(type, 0, item_id, asset_id); // MULTI-WEARABLE: update + outfit->mAgentInitialWearables.push_back(wearable_data); } @@ -761,52 +794,11 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs } } -// static -void LLAgentWearables::fetchInitialWearables(initial_wearable_data_vec_t & current_outfit_links, initial_wearable_data_vec_t & message_wearables) -{ -#ifdef USE_CURRENT_OUTFIT_FOLDER - if (!current_outfit_links.empty()) - { - for (U8 i = 0; i < current_outfit_links.size(); ++i) - { - // Fetch the wearables in the current outfit folder - LLWearableList::instance().getAsset(current_outfit_links[i]->mAssetID, - LLStringUtil::null, - LLWearableDictionary::getAssetType(current_outfit_links[i]->mType), - onInitialWearableAssetArrived, (void*)(current_outfit_links[i])); - } - } - else -#endif - if (!message_wearables.empty()) // We have an empty current outfit folder, use the message data instead. - { - LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); - for (U8 i = 0; i < message_wearables.size(); ++i) - { - // Populate the current outfit folder with links to the wearables passed in the message -#ifdef USE_CURRENT_OUTFIT_FOLDER - std::string link_name = "WearableLink"; - link_inventory_item(gAgent.getID(), message_wearables[i]->mItemID, current_outfit_id, link_name, - LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL)); -#endif - // Fetch the wearables - LLWearableList::instance().getAsset(message_wearables[i]->mAssetID, - LLStringUtil::null, - LLWearableDictionary::getAssetType(message_wearables[i]->mType), - onInitialWearableAssetArrived, (void*)(message_wearables[i])); - } - } - else - { - LL_WARNS("Wearables") << "No current outfit folder iterms found and no initial wearables fallback message received." << LL_ENDL; - } -} - // A single wearable that the avatar was wearing on start-up has arrived from the database. // static void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void* userdata) { - boost::scoped_ptr<InitialWearableData> wear_data((InitialWearableData*)userdata); + boost::scoped_ptr<LLInitialWearablesFetch::InitialWearableData> wear_data((LLInitialWearablesFetch::InitialWearableData*)userdata); const EWearableType type = wear_data->mType; const U32 index = wear_data->mIndex; @@ -999,6 +991,18 @@ void LLAgentWearables::createStandardWearablesAllDone() mAvatarObject->onFirstTEMessageReceived(); } +void LLAgentWearables::getAllWearablesArray(LLDynamicArray<S32>& wearables) +{ + for( S32 i = 0; i < WT_COUNT; ++i ) + { + // MULTI-WEARABLE: Properly handle multiwearables later. + if (getWearable( (EWearableType) i, 0 ) != NULL) + { + wearables.push_back(i); + } + } +} + // Note: wearables_to_include should be a list of EWearableType types // attachments_to_include should be a list of attachment points void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name, @@ -1134,16 +1138,31 @@ void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name, } } +LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name) +{ + if (mAvatarObject.isNull()) + { + return LLUUID::null; + } + + LLDynamicArray<S32> wearables_to_include; + getAllWearablesArray(wearables_to_include); + + LLDynamicArray<S32> attachments_to_include; + mAvatarObject->getAllAttachmentsArray(attachments_to_include); + + return makeNewOutfitLinks(new_folder_name, wearables_to_include, attachments_to_include); +} + // Note: wearables_to_include should be a list of EWearableType types // attachments_to_include should be a list of attachment points -void LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name, - const LLDynamicArray<S32>& wearables_to_include, - const LLDynamicArray<S32>& attachments_to_include, - BOOL rename_clothing) +LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name, + const LLDynamicArray<S32>& wearables_to_include, + const LLDynamicArray<S32>& attachments_to_include) { if (mAvatarObject.isNull()) { - return; + return LLUUID::null; } // First, make a folder in the Clothes directory. @@ -1172,22 +1191,13 @@ void LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name, LLWearable* old_wearable = getWearable((EWearableType)type,j); if (old_wearable) { - std::string new_name; - if (rename_clothing) - { - new_name = new_folder_name; - new_name.append(" "); - new_name.append(old_wearable->getTypeLabel()); - LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN); - } - LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((EWearableType) type, j)); if (!item) continue; LLPointer<LLInventoryCallback> cb = NULL; link_inventory_item(gAgent.getID(), item->getUUID(), folder_id, - new_name, + item->getName(), LLAssetType::AT_LINK, cb); } @@ -1223,6 +1233,32 @@ void LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name, cb); } } + + /////////////////// + // Gestures + + /* Disabling this for now, otherwise this adds all your default gestures and all previous + active gestures. Need to rethink the intended behavior. + for (LLGestureManager::item_map_t::iterator iter = LLGestureManager::instance().mActive.begin(); + iter != LLGestureManager::instance().mActive.end(); + ++iter) + { + const LLUUID &gesture_id = (*iter).first; + LLViewerInventoryItem* item = gInventory.getItem(gesture_id); + if (item) + { + LLPointer<LLInventoryCallback> cb = NULL; + link_inventory_item(gAgent.getID(), + item->getUUID(), + folder_id, + item->getName(), + LLAssetType::AT_LINK, + cb); + } + } + */ + + return folder_id; } void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index) @@ -1774,11 +1810,10 @@ void LLAgentWearables::updateServer() gAgent.sendAgentSetAppearance(); } -void LLAgentWearables::LLOutfitFolderFetch::done() +void LLInitialWearablesFetch::done() { - // What we do here is get the complete information on the items in - // the library, and set up an observer that will wait for that to - // happen. + // Get the complete information on the items in the library, + // and set up an observer that will wait for that to happen. LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; gInventory.collectDescendents(mCompleteFolders.front(), @@ -1786,43 +1821,70 @@ void LLAgentWearables::LLOutfitFolderFetch::done() item_array, LLInventoryModel::EXCLUDE_TRASH); S32 count = item_array.count(); - LLAgentWearables::initial_wearable_data_vec_t current_outfit_links; - current_outfit_links.reserve(count); + mCOFInitialWearables.reserve(count); - for(S32 i = 0; i < count; ++i) - { - // A bit of a hack since wearables database doesn't contain asset types... - // Perform indirection in case this assetID is in fact a link. This only works - // because of the assumption that all assetIDs and itemIDs are unique (i.e. - // no assetID is also used as an itemID elsewhere); therefore if the assetID - // exists as an itemID in the user's inventory, then this must be a link. - const LLInventoryItem *linked_item = gInventory.getItem(item_array.get(i)->getUUID()); - LLAssetType::EType asset_type = (LLAssetType::EType) 0; - if (linked_item) + for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + const LLViewerInventoryItem *item = (*iter).get(); + // We're only concerned with linked items in the COF. Ignore + // any non-link items or links to folders. + if (item->getActualType() != LLAssetType::AT_LINK) { - asset_type = linked_item->getType(); - LLInventoryItem * base_item = gInventory.getItem(linked_item->getLinkedUUID()); - if (base_item) - { - EWearableType type = (EWearableType) (base_item->getFlags() & LLInventoryItem::II_FLAGS_WEARABLES_MASK); - // MULTI-WEARABLE: update - InitialWearableData * temp_wearable_data = new InitialWearableData(type, 0, linked_item->getLinkedUUID(), base_item->getAssetUUID()); - current_outfit_links.push_back(temp_wearable_data); - } - else - { - llwarns << "Null base_item in LLOutfitFolderFetch::done, linkedUUID is " << linked_item->getLinkedUUID().asString() << llendl; - } - } - else - { - llwarns << "Null linked_item in LLOutfitFolderFetch::done, UUID is " << item_array.get(i)->getUUID().asString() << llendl; + continue; } + EWearableType type = (EWearableType) (item->getFlags() & LLInventoryItem::II_FLAGS_WEARABLES_MASK); + // MULTI-WEARABLE: update + InitialWearableData wearable_data(type, 0, item->getUUID(), item->getAssetUUID()); + mCOFInitialWearables.push_back(wearable_data); } gInventory.removeObserver(this); - LLAgentWearables::fetchInitialWearables(current_outfit_links, mAgentInitialWearables); - mAgentInitialWearables.clear(); + processInitialWearables(); delete this; } +// This will either grab the contents of the Current Outfit Folder if they exist, +// or use the old-style initial agent wearables message. +void LLInitialWearablesFetch::processInitialWearables() +{ +#ifdef USE_CURRENT_OUTFIT_FOLDER + if (!mCOFInitialWearables.empty()) + { + for (U8 i = 0; i < mCOFInitialWearables.size(); ++i) + { + // Fetch the wearables in the current outfit folder + InitialWearableData *wearable_data = new InitialWearableData(mCOFInitialWearables[i]); // This will be deleted in the callback. + LLWearableList::instance().getAsset(wearable_data->mAssetID, + LLStringUtil::null, + LLWearableDictionary::getAssetType(wearable_data->mType), + LLAgentWearables::onInitialWearableAssetArrived, (void*)(wearable_data)); + } + } + else +#endif + if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead. + { + LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); + for (U8 i = 0; i < mAgentInitialWearables.size(); ++i) + { + // Populate the current outfit folder with links to the wearables passed in the message + InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback. +#ifdef USE_CURRENT_OUTFIT_FOLDER + const std::string link_name = "WearableLink"; // Unimportant what this is named, it isn't exposed. + link_inventory_item(gAgent.getID(), wearable_data->mItemID, current_outfit_id, link_name, + LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL)); +#endif + // Fetch the wearables + LLWearableList::instance().getAsset(wearable_data->mAssetID, + LLStringUtil::null, + LLWearableDictionary::getAssetType(wearable_data->mType), + LLAgentWearables::onInitialWearableAssetArrived, (void*)(wearable_data)); + } + } + else + { + LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL; + } +} diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h index 971fd9ee37..b415ef9eb3 100644 --- a/indra/newview/llagentwearables.h +++ b/indra/newview/llagentwearables.h @@ -43,30 +43,16 @@ class LLInventoryItem; class LLVOAvatarSelf; class LLWearable; - -// Forward Declaration -class LLInventoryFetchDescendentsObserver; +class LLInitialWearablesFetch; class LLAgentWearables { //-------------------------------------------------------------------- - // Data Types - //-------------------------------------------------------------------- - typedef struct _InitialWearableData - { - EWearableType mType; - U32 mIndex; - LLUUID mItemID; - LLUUID mAssetID; - _InitialWearableData(EWearableType type, U32 index, LLUUID itemID, LLUUID assetID) : - mType(type), mIndex(index), mItemID(itemID), mAssetID(assetID) { } - } InitialWearableData; - typedef std::vector<InitialWearableData *> initial_wearable_data_vec_t; - - //-------------------------------------------------------------------- // Constructors / destructors / Initializers //-------------------------------------------------------------------- public: + friend class LLInitialWearablesFetch; + LLAgentWearables(); virtual ~LLAgentWearables(); void setAvatarObject(LLVOAvatarSelf *avatar); @@ -149,7 +135,6 @@ protected: public: // Processes the initial wearables update message (if necessary, since the outfit folder makes it redundant) static void processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data); - static void fetchInitialWearables(initial_wearable_data_vec_t & current_outfit_links, initial_wearable_data_vec_t & message_wearables); protected: void sendAgentWearablesUpdate(); void sendAgentWearablesRequest(); @@ -161,6 +146,8 @@ protected: // Outfits //-------------------------------------------------------------------- public: + void getAllWearablesArray(LLDynamicArray<S32>& wearables); + // Note: wearables_to_include should be a list of EWearableType types // attachments_to_include should be a list of attachment points void makeNewOutfit(const std::string& new_folder_name, @@ -170,10 +157,10 @@ public: // Note: wearables_to_include should be a list of EWearableType types // attachments_to_include should be a list of attachment points - void makeNewOutfitLinks(const std::string& new_folder_name, + LLUUID makeNewOutfitLinks(const std::string& new_folder_name); + LLUUID makeNewOutfitLinks(const std::string& new_folder_name, const LLDynamicArray<S32>& wearables_to_include, - const LLDynamicArray<S32>& attachments_to_include, - BOOL rename_clothing); + const LLDynamicArray<S32>& attachments_to_include); private: void makeNewOutfitDone(S32 type, U32 index); @@ -254,17 +241,6 @@ private: U32 mTodo; LLPointer<LLRefCount> mCB; }; - - // Outfit folder fetching callback structure. - class LLOutfitFolderFetch : public LLInventoryFetchDescendentsObserver - { - public: - LLOutfitFolderFetch() {} - ~LLOutfitFolderFetch() {} - virtual void done(); - - LLAgentWearables::initial_wearable_data_vec_t mAgentInitialWearables; - }; }; // LLAgentWearables diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp index 718719fe57..3c66a2add1 100644 --- a/indra/newview/llfloaterinventory.cpp +++ b/indra/newview/llfloaterinventory.cpp @@ -1138,10 +1138,10 @@ const std::string& get_item_icon_name(LLAssetType::EType asset_type, idx = LANDMARK_ICON_NAME; break; case LLAssetType::AT_LINK: - idx = BODYPART_ICON_NAME; // Seraph replace this with broken item link icon + idx = LINKITEM_ICON_NAME; break; case LLAssetType::AT_LINK_FOLDER: - idx = BODYPART_ICON_NAME; // Seraph replace this with broken folder link icon + idx = LINKFOLDER_ICON_NAME; break; default: break; @@ -1684,6 +1684,7 @@ void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& it fv->startRenamingSelectedItem(); } } + // Seraph - Put determineFolderType in here for ensemble typing? } //---------------------------------------------------------------------------- diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index 69ce2f0e0e..de6a1a097d 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -2115,6 +2115,14 @@ BOOL LLFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask ) BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask ) { + const LLUUID &cat_uuid = getListener()->getUUID(); + const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_uuid); + if (cat && cat->getPreferredType() == LLAssetType::AT_OUTFIT) + { + getListener()->performAction(NULL, NULL,"replaceoutfit"); + return TRUE; + } + BOOL handled = FALSE; if( mIsOpen ) { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 59041792a2..45003fe56c 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -155,6 +155,9 @@ std::string ICON_NAME[ICON_NAME_COUNT] = "inv_item_animation.tga", "inv_item_gesture.tga", + + "inv_item_linkitem.tga", + "inv_item_linkfolder.tga" }; BOOL gAddToOutfit = FALSE; @@ -2309,8 +2312,6 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) else if(isAgentInventory()) // do not allow creating in library { mItems.push_back(std::string("New Folder")); - mItems.push_back(std::string("New Outfit")); - mItems.push_back(std::string("New My Outfits")); mItems.push_back(std::string("New Script")); mItems.push_back(std::string("New Note")); mItems.push_back(std::string("New Gesture")); @@ -4157,6 +4158,58 @@ void wear_inventory_category_on_avatar( LLInventoryCategory* category, BOOL appe } } +void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventoryModel::item_array_t& src) +{ + LLInventoryModel::item_array_t new_dst; + std::set<LLUUID> mark_inventory; + std::set<LLUUID> mark_asset; + + S32 inventory_dups = 0; + S32 asset_dups = 0; + + for (LLInventoryModel::item_array_t::const_iterator src_pos = src.begin(); + src_pos != src.end(); + ++src_pos) + { + LLUUID src_item_id = (*src_pos)->getLinkedUUID(); + mark_inventory.insert(src_item_id); + LLUUID src_asset_id = (*src_pos)->getAssetUUID(); + mark_asset.insert(src_asset_id); + } + + for (LLInventoryModel::item_array_t::const_iterator dst_pos = dst.begin(); + dst_pos != dst.end(); + ++dst_pos) + { + LLUUID dst_item_id = (*dst_pos)->getLinkedUUID(); + + if (mark_inventory.find(dst_item_id) == mark_inventory.end()) + { + } + else + { + inventory_dups++; + } + + LLUUID dst_asset_id = (*dst_pos)->getAssetUUID(); + + if (mark_asset.find(dst_asset_id) == mark_asset.end()) + { + // Item is not already present in COF. + new_dst.put(*dst_pos); + mark_asset.insert(dst_item_id); + } + else + { + asset_dups++; + } + } + llinfos << "removeDups, original " << dst.count() << " final " << new_dst.count() + << " inventory dups " << inventory_dups << " asset_dups " << asset_dups << llendl; + + dst = new_dst; +} + void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOOL append, BOOL follow_folder_links ) { // Find all the wearables that are in the category's subtree. @@ -4205,22 +4258,35 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO } const LLUUID ¤t_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); + // Processes that take time should show the busy cursor + inc_busy_count(); + + LLInventoryModel::cat_array_t co_cat_array; + LLInventoryModel::item_array_t co_item_array; + gInventory.collectDescendents(current_outfit_id, co_cat_array, co_item_array, + LLInventoryModel::EXCLUDE_TRASH); + if (append) + { + // Remove duplicates and update counts. + removeDuplicateItems(item_array,co_item_array); + wearable_count = item_array.count(); + + removeDuplicateItems(obj_item_array,co_item_array); + obj_count = obj_item_array.count(); + + removeDuplicateItems(gest_item_array,co_item_array); + gest_count = gest_item_array.count(); + } + if (wearable_count > 0 || obj_count > 0) { - // Processes that take time should show the busy cursor - inc_busy_count(); - - // Remove all current outfit folder links if we're now replacing the contents. - if (!append) + if (!append) { - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - gInventory.collectDescendents(current_outfit_id, cat_array, item_array, - LLInventoryModel::EXCLUDE_TRASH); - for (i = 0; i < item_array.count(); ++i) + // Remove all current outfit folder links if we're now replacing the contents. + for (i = 0; i < co_item_array.count(); ++i) { - gInventory.purgeObject(item_array.get(i)->getUUID()); + gInventory.purgeObject(co_item_array.get(i)->getUUID()); } } } @@ -4272,10 +4338,10 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO // Fetch the wearables about to be worn. LLWearableList::instance().getAsset(found->mAssetID, - found->mName, - found->mAssetType, - wear_inventory_category_on_avatar_loop, - (void*)holder); + found->mName, + found->mAssetType, + wear_inventory_category_on_avatar_loop, + (void*)holder); } } @@ -4352,9 +4418,10 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO } } - // Create a link to the folder that we wore. + // In the particular case that we're switching to a different outfit, + // create a link to the folder that we wore. LLViewerInventoryCategory* catp = gInventory.getCategory(category); - if (catp) + if (!append && catp && catp->getPreferredType() == LLAssetType::AT_OUTFIT) { link_inventory_item(gAgent.getID(), category, current_outfit_id, catp->getName(), LLAssetType::AT_LINK_FOLDER, LLPointer<LLInventoryCallback>(NULL)); @@ -5240,6 +5307,10 @@ std::string LLLinkItemBridge::sPrefix("Link: "); LLUIImagePtr LLLinkItemBridge::getIcon() const { + if (LLViewerInventoryItem *item = getItem()) + { + return get_item_icon(item->getActualType(), LLInventoryType::IT_NONE, 0, FALSE); + } return get_item_icon(LLAssetType::AT_LINK, LLInventoryType::IT_NONE, 0, FALSE); } diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 5cfebe6c15..3af54c52ea 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -76,6 +76,9 @@ enum EInventoryIcon ANIMATION_ICON_NAME, GESTURE_ICON_NAME, + LINKITEM_ICON_NAME, + LINKFOLDER_ICON_NAME, + ICON_NAME_COUNT }; diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 596211f16c..f5525ec1f2 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -111,7 +111,15 @@ BOOL LLInventoryFilter::check(LLFolderViewItem* item) } else { - passed_type |= ((1LL << listener->getInventoryType() & mFilterOps.mFilterTypes) != U64(0)) || listener->getInventoryType() == LLInventoryType::IT_NONE; + passed_type |= ((1LL << listener->getInventoryType() & mFilterOps.mFilterTypes) != U64(0)); + if (listener->getInventoryType() == LLInventoryType::IT_NONE) + { + const LLInventoryObject *obj = gInventory.getObject(listener->getUUID()); + if (!obj->getIsLinkType()) + { + passed_type = TRUE; + } + } } BOOL passed = passed_type diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index b27fbbff88..aadda3fbfd 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1790,7 +1790,7 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) // The item will show up as a broken link. if (item->getIsBrokenLink()) { - llwarns << "Add link item without baseobj present ( itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) " << llendl; + llwarns << "Add link item without baseobj present ( name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << llendl; } mItemMap[item->getUUID()] = item; //mInventory[item->getUUID()] = item; @@ -2041,6 +2041,7 @@ bool LLInventoryModel::loadSkeleton( { cat_array_t categories; item_array_t items; + cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. std::string owner_id_str; owner_id.toString(owner_id_str); std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, owner_id_str)); @@ -2106,7 +2107,7 @@ bool LLInventoryModel::loadSkeleton( } // go ahead and add the cats returned during the download - std::set<LLUUID>::iterator not_cached_id = cached_ids.end(); + std::set<LLUUID>::const_iterator not_cached_id = cached_ids.end(); cached_category_count = cached_ids.size(); for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) { @@ -2126,30 +2127,28 @@ bool LLInventoryModel::loadSkeleton( // category with a correctly cached parent count = items.count(); cat_map_t::iterator unparented = mCategoryMap.end(); - for(int i = 0; i < count; ++i) + for(item_array_t::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) { - LLViewerInventoryItem *item = items[i].get(); - cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); + LLViewerInventoryItem *item = (*item_iter).get(); + const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); if(cit != unparented) { - LLViewerInventoryCategory* cat = cit->second; + const LLViewerInventoryCategory* cat = cit->second.get(); if(cat->getVersion() != NO_VERSION) { + // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache. if (item->getIsBrokenLink()) { llinfos << "Attempted to cached link item without baseobj present ( itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) " << llendl; - child_counts[cat->getUUID()].mValue = -1; // Invalidate this category's cache. + invalid_categories.insert(cit->second); continue; } addItem(item); cached_item_count += 1; - - // If this category had any broken links, keep it invalidated. - if (child_counts[cat->getUUID()].mValue != -1) - { - ++child_counts[cat->getUUID()]; - } + ++child_counts[cat->getUUID()]; } } } @@ -2169,29 +2168,35 @@ bool LLInventoryModel::loadSkeleton( // At this point, we need to set the known descendents for each // category which successfully cached so that we do not // needlessly fetch descendents for categories which we have. - update_map_t::iterator no_child_counts = child_counts.end(); - update_map_t::iterator the_count; + update_map_t::const_iterator no_child_counts = child_counts.end(); for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) { - LLViewerInventoryCategory* cat = (*it); + LLViewerInventoryCategory* cat = (*it).get(); if(cat->getVersion() != NO_VERSION) { - the_count = child_counts.find(cat->getUUID()); + update_map_t::const_iterator the_count = child_counts.find(cat->getUUID()); if(the_count != no_child_counts) { - S32 num_descendents = (*the_count).second.mValue; - - // -1 means that one of the children was a broken link, so we can't consider this folder successfully cached. - if (num_descendents != -1) - { - cat->setDescendentCount(num_descendents); - continue; - } + cat->setDescendentCount((*the_count).second.mValue); + } + else + { + cat->setDescendentCount(0); } - cat->setDescendentCount(0); } } + // Invalidate all categories that failed fetching descendents for whatever + // reason (e.g. one of the descendents was a broken link). + for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); + invalid_cat_it != invalid_categories.end(); + invalid_cat_it++) + { + LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); + cat->setVersion(NO_VERSION); + llinfos << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << llendl; + } + if(remove_inventory_file) { // clean up the gunzipped file. diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 9a090be76a..4645b9bf59 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -612,10 +612,7 @@ void LLViewerInventoryCategory::determineFolderType() return; if (item->getInventoryType() == LLInventoryType::IT_WEARABLE) { - U32 flags = item->getFlags(); - if (flags > WT_COUNT) - return; - const EWearableType wearable_type = EWearableType(flags); + const EWearableType wearable_type = EWearableType(item->getFlags() & LLInventoryItem::II_FLAGS_WEARABLES_MASK); const std::string& wearable_name = LLWearableDictionary::getTypeName(wearable_type); U64 valid_folder_types = LLFolderType::lookupValidFolderTypes(wearable_name); folder_valid |= valid_folder_types; diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 9df25bdb11..5b4a649ee1 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -990,6 +990,19 @@ LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *viewer_obj return attachment; } +void LLVOAvatarSelf::getAllAttachmentsArray(LLDynamicArray<S32>& attachments) +{ + for (LLVOAvatar::attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if ( attachment && (attachment->getNumObjects() > 0)) + { + attachments.push_back(iter->first); + } + } +} + U32 LLVOAvatarSelf::getNumWearables(LLVOAvatarDefines::ETextureIndex i) const { EWearableType type = LLVOAvatarDictionary::getInstance()->getTEWearableType(i); diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h index e34f09aca2..17744cce1b 100644 --- a/indra/newview/llvoavatarself.h +++ b/indra/newview/llvoavatarself.h @@ -261,6 +261,7 @@ public: LLViewerObject* getWornAttachment(const LLUUID& inv_item_id ) const; const std::string getAttachedPointName(const LLUUID& inv_item_id) const; /*virtual*/ LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object); + void getAllAttachmentsArray(LLDynamicArray<S32>& attachments); //-------------------------------------------------------------------- // HUDs diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 1515a34eeb..ad208806b7 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -414,6 +414,8 @@ <texture name="inv_item_jacket.tga"/> <texture name="inv_item_landmark.tga"/> <texture name="inv_item_landmark_visited.tga"/> + <texture name="inv_item_linkitem.tga"/> + <texture name="inv_item_linkfolder.tga"/> <texture name="inv_item_notecard.tga"/> <texture name="inv_item_object.tga"/> <texture name="inv_item_object_multi.tga"/> diff --git a/indra/newview/skins/default/xui/en/floater_customize.xml b/indra/newview/skins/default/xui/en/floater_customize.xml index 41bd417c12..824df082d8 100644 --- a/indra/newview/skins/default/xui/en/floater_customize.xml +++ b/indra/newview/skins/default/xui/en/floater_customize.xml @@ -3561,14 +3561,4 @@ scratch and wear it. name="Ok" right="-116" width="100" /> - <button - follows="left|bottom" - height="20" - label="Make Outfit..." - label_selected="Make Outfit..." - layout="topleft" - left_delta="-178" - name="Make Outfit" - top_delta="0" - width="100" /> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_inventory.xml b/indra/newview/skins/default/xui/en/floater_inventory.xml index 610c62a21a..37c6cbf391 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory.xml @@ -207,22 +207,6 @@ parameter="category" /> </menu_item_call> <menu_item_call - label="New Outfit" - layout="topleft" - name="New Outfit"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="outfit" /> - </menu_item_call> - <menu_item_call - label="New My Outfits" - layout="topleft" - name="New My Outfits"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="my_otfts" /> - </menu_item_call> - <menu_item_call label="New Script" layout="topleft" name="New Script"> diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index dd8acea4ed..7762a7f667 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -77,30 +77,6 @@ parameter="category" /> </menu_item_call> <menu_item_call - label="New Current" - layout="topleft" - name="New Current"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="current" /> - </menu_item_call> - <menu_item_call - label="New Outfit" - layout="topleft" - name="New Outfit"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="outfit" /> - </menu_item_call> - <menu_item_call - label="New My Outfits" - layout="topleft" - name="New My Outfits"> - <menu_item_call.on_click - function="Inventory.DoCreate" - parameter="my_otfts" /> - </menu_item_call> - <menu_item_call label="New Script" layout="topleft" name="New Script"> @@ -338,14 +314,6 @@ function="Inventory.DoToSelected" parameter="change_folder_type_undershirt" /> </menu_item_call> - <menu_item_call - label="Outfit" - layout="topleft" - name="Outfit"> - <menu_item_call.on_click - function="Inventory.DoToSelected" - parameter="change_folder_type_outfit" /> - </menu_item_call> </menu> <menu_item_call label="Teleport" diff --git a/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml b/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml index 7ea059ba6a..e87517e200 100644 --- a/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml +++ b/indra/newview/skins/default/xui/en/panel_sidetray_home_tab.xml @@ -149,11 +149,11 @@ text_color="white" top="40" word_wrap="true"> - Change your profile, your look and quick links to your outfits. + Change your profile. </text> </panel> <panel - background_visible="true" + background_visible="true" bg_alpha_color="DkGray2" class="panel_sidetray_home_info" follows="left|top|right" @@ -197,7 +197,7 @@ text_color="white" top="40" word_wrap="true"> - Change your appearance. + Change your apperance and looks. </text> - </panel> + </panel> </panel> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index fb1aa25b25..f89625c535 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -149,6 +149,7 @@ <string name="gesture">gesture</string> <string name="simstate">simstate</string> <string name="favorite">favorite</string> + <string name="symbolic link">link</string> <!-- llvoavatar. Displayed in the avatar chat bubble --> <string name="AvatarEditingAppearance">(Editing Appearance)</string> |