diff options
author | Loren Shih <seraph@lindenlab.com> | 2009-07-23 23:41:12 +0000 |
---|---|---|
committer | Loren Shih <seraph@lindenlab.com> | 2009-07-23 23:41:12 +0000 |
commit | 363de6c3bc231183224aed8ba287efe450adb00b (patch) | |
tree | a75bd8d0449ab119f25db4b0024989cba0b71697 | |
parent | 80deb2a5358e5e912455a781b0d4aa5f29080e30 (diff) |
svn merge -r 127683:128178 svn+ssh://svn.lindenlab.com/svn/linden/branches/avatar-pipeline/folder-links__merge__viewer-2.0.0.3-r127634 into svn+ssh://svn.lindenlab.com/svn/linden/branches/viewer/viewer-2.0.0-3
For DEV-36425 : Viewer merge for Folder Links and Types [VIEWER]
Test plans - EXTERNAL
* [ Test against a 1.30 server ]
* Test various inventory operations -- move, copy, paste-as-link, etc. on both folders and inventory items.
* Test ability to change user-created folder types. Test inventory operations on these folder types.
Test plans - INTERNAL
* Test against any inventory smoke tests.
* See test plan in QAR-1643 for full FolderLinks&Types test plan.
25 files changed, 701 insertions, 171 deletions
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index e4102a622d..d431071c25 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -44,19 +44,29 @@ struct AssetEntry : public LLDictionaryEntry { AssetEntry(const char *desc_name, const char *type_name, // 8 character limit! - const char *human_name, + const char *human_name, // for decoding to human readable form; put any and as many printable characters you want in each one const char *category_name, // used by llinventorymodel when creating new categories EDragAndDropType dad_type, - bool can_link); + bool can_link, // can you create a link to this type? + bool is_protected) // can the viewer change categories of this type? + : + LLDictionaryEntry(desc_name), + mTypeName(type_name), + mHumanName(human_name), + mCategoryName(category_name), + mDadType(dad_type), + mCanLink(can_link), + mIsProtected(is_protected) + { + llassert(strlen(mTypeName) <= 8); + } - // limited to 8 characters const char *mTypeName; - // human readable form. Put as many printable characters you want in each one. - // (c.f. llinventory.cpp INVENTORY_TYPE_HUMAN_NAMES). const char *mHumanName; const char *mCategoryName; EDragAndDropType mDadType; bool mCanLink; + bool mIsProtected; }; class LLAssetDictionary : public LLSingleton<LLAssetDictionary>, @@ -68,52 +78,49 @@ public: LLAssetDictionary::LLAssetDictionary() { - addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", "Textures", DAD_TEXTURE, FALSE)); - addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", "Sounds", DAD_SOUND, FALSE)); - addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", "Calling Cards", DAD_CALLINGCARD, FALSE)); - addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", "Landmarks", DAD_LANDMARK, FALSE)); - addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", "Scripts", DAD_NONE, FALSE)); - addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", "Clothing", DAD_CLOTHING, TRUE)); - addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", "Objects", DAD_OBJECT, TRUE)); - addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", "Notecards", DAD_NOTECARD, FALSE)); - addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", "New Folder", DAD_CATEGORY, TRUE)); - addEntry(LLAssetType::AT_ROOT_CATEGORY, new AssetEntry("ROOT_CATEGORY", "root", "root", "Inventory", DAD_ROOT_CATEGORY, TRUE)); - addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", "Scripts", DAD_SCRIPT, FALSE)); - addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", "Scripts", DAD_NONE, FALSE)); - addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", "Uncompressed Images", DAD_NONE, FALSE)); - addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", "Body Parts", DAD_BODYPART, TRUE)); - addEntry(LLAssetType::AT_TRASH, new AssetEntry("TRASH", "trash", "trash", "Trash", DAD_NONE, FALSE)); - addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot", "snapshot", "Photo Album", DAD_NONE, FALSE)); - addEntry(LLAssetType::AT_LOST_AND_FOUND, new AssetEntry("LOST_AND_FOUND", "lstndfnd", "lost and found", "Lost And Found", DAD_NONE, FALSE)); - addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", "Uncompressed SoundS", DAD_NONE, FALSE)); - addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", "Uncompressed Images", DAD_NONE, FALSE)); - addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", "Uncompressed Images", DAD_NONE, FALSE)); - addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", "Animations", DAD_ANIMATION, FALSE)); - addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", "Gestures", DAD_GESTURE, FALSE)); - addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", "New Folder", DAD_NONE, FALSE)); - addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "favorite", "favorite", DAD_NONE, FALSE)); + // DESCRIPTION TYPE NAME HUMAN NAME CATEGORY NAME DRAG&DROP CAN LINK? PROTECTED? + // |--------------------|-----------|-------------------|-------------------|---------------|-----------|-----------| + addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", "Textures", DAD_TEXTURE, FALSE, TRUE)); + addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", "Sounds", DAD_SOUND, FALSE, TRUE)); + addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", "Calling Cards", DAD_CALLINGCARD, FALSE, TRUE)); + addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", "Landmarks", DAD_LANDMARK, FALSE, TRUE)); + addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", "Scripts", DAD_NONE, FALSE, TRUE)); + addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", "Clothing", DAD_CLOTHING, TRUE, TRUE)); + addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", "Objects", DAD_OBJECT, TRUE, TRUE)); + addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", "Notecards", DAD_NOTECARD, FALSE, TRUE)); + addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", "New Folder", DAD_CATEGORY, TRUE, TRUE)); + addEntry(LLAssetType::AT_ROOT_CATEGORY, new AssetEntry("ROOT_CATEGORY", "root", "root", "Inventory", DAD_ROOT_CATEGORY, TRUE, TRUE)); + addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", "Scripts", DAD_SCRIPT, FALSE, TRUE)); + addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", "Scripts", DAD_NONE, FALSE, TRUE)); + addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", "Uncompressed Images", DAD_NONE, FALSE, TRUE)); + addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", "Body Parts", DAD_BODYPART, TRUE, TRUE)); + addEntry(LLAssetType::AT_TRASH, new AssetEntry("TRASH", "trash", "trash", "Trash", DAD_NONE, FALSE, TRUE)); + addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot", "snapshot", "Photo Album", DAD_NONE, FALSE, TRUE)); + addEntry(LLAssetType::AT_LOST_AND_FOUND, new AssetEntry("LOST_AND_FOUND", "lstndfnd", "lost and found", "Lost And Found", DAD_NONE, FALSE, TRUE)); + addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", "Uncompressed SoundS", DAD_NONE, FALSE, TRUE)); + 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_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)); - addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "symbolic link", "New Folder", DAD_NONE, FALSE)); - addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "symbolic folder link", "New Folder", DAD_NONE, FALSE)); + addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "symbolic link", "Link", DAD_LINK, FALSE, TRUE)); + addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "symbolic folder link", "New Folder", DAD_LINK, FALSE, TRUE)); - addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, "New Folder", DAD_NONE, FALSE)); -}; + for (S32 ensemble_num = S32(LLAssetType::AT_FOLDER_ENSEMBLE_START); + ensemble_num <= S32(LLAssetType::AT_FOLDER_ENSEMBLE_END); + ensemble_num++) + { + addEntry(LLAssetType::EType(ensemble_num), new AssetEntry("ENSEMBLE", "ensemble", "ensemble", "New Folder", DAD_CATEGORY, TRUE, FALSE)); + } -AssetEntry::AssetEntry(const char *desc_name, - const char *type_name, - const char *human_name, - const char *category_name, - EDragAndDropType dad_type, - bool can_link) : - LLDictionaryEntry(desc_name), - mTypeName(type_name), - mHumanName(human_name), - mCategoryName(category_name), - mDadType(dad_type), - mCanLink(can_link) -{ - llassert(strlen(mTypeName) <= 8); -} + 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_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)); +}; // static LLAssetType::EType LLAssetType::getType(const std::string& desc_name) @@ -128,11 +135,11 @@ const std::string &LLAssetType::getDesc(LLAssetType::EType asset_type) { const AssetEntry *entry = LLAssetDictionary::getInstance()->lookup(asset_type); if (entry) -{ + { return entry->mName; } else - { + { static const std::string error_string = "BAD TYPE"; return error_string; } @@ -154,7 +161,7 @@ const char *LLAssetType::lookup(LLAssetType::EType asset_type) } // static -LLAssetType::EType LLAssetType::lookup( const char* name ) +LLAssetType::EType LLAssetType::lookup(const char* name) { return lookup(ll_safe_string(name)); } @@ -191,7 +198,7 @@ const char *LLAssetType::lookupHumanReadable(LLAssetType::EType asset_type) } // static -LLAssetType::EType LLAssetType::lookupHumanReadable( const char* name ) +LLAssetType::EType LLAssetType::lookupHumanReadable(const char* name) { return lookupHumanReadable(ll_safe_string(name)); } @@ -261,6 +268,21 @@ bool LLAssetType::lookupIsLinkType(EType asset_type) return false; } +// static +// Only ensembles and plain folders aren't protected. "Protected" means +// you can't change certain properties such as their type. +bool LLAssetType::lookupIsProtectedCategoryType(EType asset_type) +{ + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const AssetEntry *entry = dict->lookup(asset_type); + if (entry) + { + return entry->mIsProtected; + } + return true; +} + + // static. Generate a good default description void LLAssetType::generateDescriptionFor(LLAssetType::EType asset_type, std::string& description) diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 353bd57bb9..8ab7510494 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -125,7 +125,7 @@ public: AT_SIMSTATE = 22, // Simstate file. - + AT_FAVORITE = 23, // favorite items @@ -135,21 +135,35 @@ public: AT_LINK_FOLDER = 25, // Inventory folder link - AT_COUNT = 26, + AT_FOLDER_ENSEMBLE_START = 26, + AT_FOLDER_ENSEMBLE_END = 45, + // This range is reserved for special clothing folder types. + + AT_CURRENT_OUTFIT = 46, + // Current outfit - // +************************************************+ - // | TO ADD AN ELEMENT TO THIS ENUM: | - // +************************************************+ - // | 1. INSERT BEFORE AT_COUNT | - // | 2. INCREMENT AT_COUNT BY 1 | - // | 3. ADD TO LLAssetDictionary in llassettype.cpp | - // +************************************************+ + AT_OUTFIT = 47, + // Predefined outfit ("look") + + AT_MY_OUTFITS = 48, + // Folder that holds your outfits. + + + AT_COUNT = 49, + // +*********************************************************+ + // | TO ADD AN ELEMENT TO THIS ENUM: | + // +*********************************************************+ + // | 1. INSERT BEFORE AT_COUNT | + // | 2. INCREMENT AT_COUNT BY 1 | + // | 3. ADD TO LLAssetDictionary in LLAssetType.cpp | + // | 3. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp | + // +*********************************************************+ AT_NONE = -1 }; // machine transation between type and strings - static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate + static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate static EType lookup(const std::string& type_name); static const char* lookup(EType asset_type); @@ -158,8 +172,6 @@ public: static EType lookupHumanReadable(const std::string& readable_name); static const char* lookupHumanReadable(EType asset_type); - static const char* lookupCategoryName(EType asset_type); - // Generate a good default description. You may want to add a verb // or agent name after this depending on your application. static void generateDescriptionFor(LLAssetType::EType asset_type, @@ -168,9 +180,13 @@ public: static EType getType(const std::string& desc_name); static const std::string& getDesc(EType asset_type); static EDragAndDropType lookupDragAndDropType(EType asset_type); + static bool lookupCanLink(EType asset_type); static bool lookupIsLinkType(EType asset_type); + static const char* lookupCategoryName(EType asset_type); + static bool lookupIsProtectedCategoryType(EType asset_type); + /* TODO: Change return types from "const char *" to "const std::string &". This is fairly straightforward, but requires changing some calls to use .c_str(). e.g.: @@ -180,8 +196,8 @@ public: private: // don't instantiate or derive one of these objects - LLAssetType() {} - ~LLAssetType() {} + LLAssetType( void ) {} + ~LLAssetType( void ) {} }; #endif // LL_LLASSETTYPE_H diff --git a/indra/llcommon/lldictionary.h b/indra/llcommon/lldictionary.h index 856947def8..436b689ca6 100644 --- a/indra/llcommon/lldictionary.h +++ b/indra/llcommon/lldictionary.h @@ -95,6 +95,10 @@ public: protected: void addEntry(Index index, Entry *entry) { + if (lookup(index)) + { + llerrs << "Dictionary entry already added (attempted to add duplicate entry)" << llendl; + } (*this)[index] = entry; } }; diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h index 41da51fce3..1a5678dde1 100644 --- a/indra/llcommon/stdenums.h +++ b/indra/llcommon/stdenums.h @@ -54,7 +54,8 @@ enum EDragAndDropType DAD_BODYPART = 11, DAD_ANIMATION = 12, DAD_GESTURE = 13, - DAD_COUNT = 14, // number of types in this enum + DAD_LINK = 14, + DAD_COUNT = 15, // number of types in this enum }; // Reasons for drags to be denied. diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 597e19e7ea..2d507bd560 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -1624,7 +1624,7 @@ LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat) rv[INV_PARENT_ID_LABEL] = cat->getParentUUID(); rv[INV_NAME_LABEL] = cat->getName(); rv[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(cat->getType()); - if(LLAssetType::AT_NONE != cat->getPreferredType()) + if(LLAssetType::lookupIsProtectedCategoryType(cat->getPreferredType())) { rv[INV_PREFERRED_TYPE_LABEL] = LLAssetType::lookup(cat->getPreferredType()); diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp index 2dc229226f..a445466b26 100644 --- a/indra/llinventory/llinventorytype.cpp +++ b/indra/llinventory/llinventorytype.cpp @@ -44,9 +44,23 @@ static const std::string empty_string; ///---------------------------------------------------------------------------- struct InventoryEntry : public LLDictionaryEntry { - InventoryEntry(const std::string &name, - const std::string &human_name, - int num_asset_types = 0, ...); + InventoryEntry(const std::string &name, // unlike asset type names, not limited to 8 characters; need not match asset type names + const std::string &human_name, // for decoding to human readable form; put any and as many printable characters you want in each one. + int num_asset_types = 0, ...) + : + LLDictionaryEntry(name), + mHumanName(human_name) + { + va_list argp; + va_start(argp, num_asset_types); + // Read in local textures + for (U8 i=0; i < num_asset_types; i++) + { + LLAssetType::EType t = (LLAssetType::EType)va_arg(argp,int); + mAssetTypes.push_back(t); + } + } + const std::string mHumanName; typedef std::vector<LLAssetType::EType> asset_vec_t; asset_vec_t mAssetTypes; @@ -115,25 +129,35 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] = LLInventoryType::IT_GESTURE, // AT_GESTURE LLInventoryType::IT_NONE, // AT_SIMSTATE LLInventoryType::IT_FAVORITE, // AT_FAVORITE + LLInventoryType::IT_NONE, // AT_LINK LLInventoryType::IT_NONE, // AT_LINK_FOLDER -}; -InventoryEntry::InventoryEntry(const std::string &name, - const std::string &human_name, - int num_asset_types, ...) : - LLDictionaryEntry(name), - mHumanName(human_name) -{ - va_list argp; - va_start(argp, num_asset_types); - // Read in local textures - for (U8 i=0; i < num_asset_types; i++) - { - LLAssetType::EType t = (LLAssetType::EType)va_arg(argp,int); - mAssetTypes.push_back(t); - } -} + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + LLInventoryType::IT_CATEGORY, // AT_ENSEMBLE + + LLInventoryType::IT_CATEGORY, // AT_CURRENT_OUTFIT + LLInventoryType::IT_CATEGORY, // AT_OUTFIT + LLInventoryType::IT_CATEGORY, // AT_MY_OUTFITS +}; // static const std::string &LLInventoryType::lookup(EType type) @@ -173,6 +197,21 @@ LLInventoryType::EType LLInventoryType::defaultForAssetType(LLAssetType::EType a } } + +// add any types that we don't want the user to be able to change permissions on. +// static +bool LLInventoryType::cannotRestrictPermissions(LLInventoryType::EType type) +{ + switch(type) + { + case IT_CALLINGCARD: + case IT_LANDMARK: + return true; + default: + return false; + } +} + bool inventory_and_asset_types_match(LLInventoryType::EType inventory_type, LLAssetType::EType asset_type) { diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h index 1aad90d51b..14b28bfe4b 100644 --- a/indra/llinventory/llinventorytype.h +++ b/indra/llinventory/llinventorytype.h @@ -83,10 +83,13 @@ public: // return the default inventory for the given asset type. static EType defaultForAssetType(LLAssetType::EType asset_type); + // true if this type cannot have restricted permissions. + static bool cannotRestrictPermissions(EType type); + private: // don't instantiate or derive one of these objects - LLInventoryType() {} - ~LLInventoryType() {} + LLInventoryType( void ); + ~LLInventoryType( void ); }; // helper function that returns true if inventory type and asset type diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp index c715e16e34..5a1cd95ffc 100644 --- a/indra/llmessage/lltransfersourceasset.cpp +++ b/indra/llmessage/lltransfersourceasset.cpp @@ -296,10 +296,10 @@ bool is_asset_id_knowable(LLAssetType::EType type) case LLAssetType::AT_FAVORITE: case LLAssetType::AT_LINK: case LLAssetType::AT_LINK_FOLDER: - rv = true; - break; - default: - break; + rv = true; + break; + default: + break; } return rv; } diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 5dec4a8688..d06571fb7a 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -211,6 +211,7 @@ set(viewer_SOURCE_FILES llfloaterwater.cpp llfloaterwindlight.cpp llfloaterworldmap.cpp + llfoldertype.cpp llfolderview.cpp llfolderviewitem.cpp llfollowcam.cpp @@ -646,6 +647,7 @@ set(viewer_HEADER_FILES llfloaterwater.h llfloaterwindlight.h llfloaterworldmap.h + llfoldertype.h llfolderview.h llfoldervieweventlistener.h llfolderviewitem.h diff --git a/indra/newview/app_settings/foldertypes.xml b/indra/newview/app_settings/foldertypes.xml new file mode 100644 index 0000000000..4d4d479bdd --- /dev/null +++ b/indra/newview/app_settings/foldertypes.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<ensemble_defs> + <ensemble + asset_num="-1" + xui_name="default" + icon_name="inv_plain_closed.tga" + /> + <ensemble + asset_num="27" + xui_name="head" + icon_name="inv_folder_outfit_head.tga" + /> + <ensemble + asset_num="28" + xui_name="gloves" + icon_name="inv_folder_outfit_gloves.tga" + /> + <ensemble + asset_num="29" + xui_name="jacket" + icon_name="inv_folder_outfit_jacket.tga" + /> + <ensemble + asset_num="30" + xui_name="pants" + icon_name="inv_folder_outfit_pants.tga" + /> + <ensemble + asset_num="31" + xui_name="shape" + icon_name="inv_folder_outfit_shape.tga" + /> + <ensemble + asset_num="32" + xui_name="shoes" + icon_name="inv_folder_outfit_shoes.tga" + /> + <ensemble + asset_num="33" + xui_name="shirt" + icon_name="inv_folder_outfit_shirt.tga" + /> + <ensemble + asset_num="34" + xui_name="skirt" + icon_name="inv_folder_outfit_skirt.tga" + /> + <ensemble + asset_num="35" + xui_name="underpants" + icon_name="inv_folder_outfit_underpants.tga" + /> + <ensemble + asset_num="36" + xui_name="undershirt" + icon_name="inv_folder_outfit_undershirt.tga" + /> +</ensemble_defs> diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp index d326e0e970..d05a32dc88 100644 --- a/indra/newview/llfloaterinventory.cpp +++ b/indra/newview/llfloaterinventory.cpp @@ -1533,12 +1533,14 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) << ((S32) objectp->getType()) << " (shouldn't happen)" << llendl; } - else if (objectp->getType() == LLAssetType::AT_CATEGORY) // build new view for category + else if (objectp->getType() == LLAssetType::AT_CATEGORY && + objectp->getActualType() != LLAssetType::AT_LINK_FOLDER) { LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(), - LLInventoryType::IT_CATEGORY, - this, - objectp->getUUID()); + objectp->getType(), + LLInventoryType::IT_CATEGORY, + this, + objectp->getUUID()); if (new_listener) { @@ -1553,15 +1555,17 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) itemp = folderp; } } - else // build new view for item + else { + // Build new view for item LLInventoryItem* item = (LLInventoryItem*)objectp; - LLInvFVBridge* new_listener = LLInvFVBridge::createBridge( - item->getType(), - item->getInventoryType(), - this, - item->getUUID(), - item->getFlags()); + LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(item->getType(), + item->getActualType(), + item->getInventoryType(), + this, + item->getUUID(), + item->getFlags()); + if (new_listener) { LLFolderViewItem::Params params; @@ -1591,7 +1595,7 @@ void LLInventoryPanel::buildNewViews(const LLUUID& id) } } if ((id.isNull() || - (objectp && objectp->getType() == LLAssetType::AT_CATEGORY))) + (objectp && objectp->getType() == LLAssetType::AT_CATEGORY))) { LLViewerInventoryCategory::cat_array_t* categories; LLViewerInventoryItem::item_array_t* items; diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index efc273c6e5..ca7c929d74 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -658,6 +658,7 @@ void LLFloaterProperties::onCommitName(LLUICtrl* ctrl, void* data) { new_item->updateServer(FALSE); gInventory.updateItem(new_item); + gInventory.updateLinkedObjects(new_item->getUUID()); gInventory.notifyObservers(); } else diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 6ef011f1de..c54eafb67a 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -34,10 +34,12 @@ #include "llfolderview.h" +#include "llagent.h" #include "llcallbacklist.h" #include "llinventorybridge.h" #include "llinventoryclipboard.h" // *TODO: remove this once hack below gone. #include "llinventoryfilter.h" +#include "llfoldertype.h" #include "llfloaterinventory.h"// hacked in for the bonus context menu items. #include "llkeyboard.h" #include "lllineeditor.h" @@ -1094,6 +1096,35 @@ void LLFolderView::propertiesSelectedItems( void ) } } +void LLFolderView::changeType(LLInventoryModel *model, LLAssetType::EType new_folder_type) +{ + LLFolderBridge *folder_bridge = LLFolderBridge::sSelf; + + if (!folder_bridge) return; + LLViewerInventoryCategory *cat = folder_bridge->getCategory(); + if (!cat) return; + + const LLUUID &folder_id = cat->getUUID(); + const LLUUID &parent_id = cat->getParentUUID(); + const std::string &name = cat->getName(); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, folder_id); + msg->addUUIDFast(_PREHASH_ParentID, parent_id); + msg->addS8Fast(_PREHASH_Type, new_folder_type); + msg->addStringFast(_PREHASH_Name, name); + gAgent.sendReliableMessage(); + + cat->setPreferredType(new_folder_type); + gInventory.addChangedMask(LLInventoryObserver::LABEL, folder_id); + gInventory.updateLinkedObjects(folder_id); +} + void LLFolderView::autoOpenItem( LLFolderViewFolder* item ) { if (mAutoOpenItems.check() == item || mAutoOpenItems.getDepth() >= (U32)AUTO_OPEN_STACK_DEPTH) @@ -1904,6 +1935,16 @@ bool LLFolderView::doToSelected(LLInventoryModel* model, const LLSD& userdata) LLInventoryClipboard::instance().reset(); } + static const std::string change_folder_string = "change_folder_type_"; + if (action.length() > change_folder_string.length() && + (action.compare(0,change_folder_string.length(),"change_folder_type_") == 0)) + { + LLAssetType::EType new_folder_type = LLFolderType::lookupTypeFromXUIName(action.substr(change_folder_string.length())); + changeType(model, new_folder_type); + return true; + } + + std::set<LLUUID> selected_items; getSelectionList(selected_items); diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index d944a4fa18..8d9d52cd17 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -190,6 +190,9 @@ public: void openSelectedItems( void ); void propertiesSelectedItems( void ); + // change the folder type + void changeType(LLInventoryModel *model, LLAssetType::EType new_folder_type); + void autoOpenItem(LLFolderViewFolder* item); void closeAutoOpenedFolders(); BOOL autoOpenTest(LLFolderViewFolder* item); diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp index 7032e86958..43f3ea8d8f 100644 --- a/indra/newview/llfolderviewitem.cpp +++ b/indra/newview/llfolderviewitem.cpp @@ -230,7 +230,7 @@ void LLFolderViewItem::refreshFromListener() // *TODO: to be removed when database supports multi language. This is a // temporary attempt to display the inventory folder in the user locale. - if (preferred_type != LLAssetType::AT_NONE) + if (LLAssetType::lookupIsProtectedCategoryType(preferred_type)) { mLabel = LLTrans::getString("InvFolder " + mLabel); }; diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h index 57807005c2..31866c83c8 100644 --- a/indra/newview/llfolderviewitem.h +++ b/indra/newview/llfolderviewitem.h @@ -157,13 +157,6 @@ protected: BOOL mIsLoading; LLTimer mTimeSinceRequestStart; - // This function clears the currently selected item, and records - // the specified selected item appropriately for display and use - // in the UI. If open is TRUE, then folders are opened up along - // the way to the selection. - void setSelectionFromRoot(LLFolderViewItem* selection, BOOL openitem, - BOOL take_keyboard_focus = TRUE); - // helper function to change the selection from the root. void changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected); @@ -176,6 +169,13 @@ protected: virtual BOOL addFolder(LLFolderViewFolder*) { return FALSE; } public: + // This function clears the currently selected item, and records + // the specified selected item appropriately for display and use + // in the UI. If open is TRUE, then folders are opened up along + // the way to the selection. + void setSelectionFromRoot(LLFolderViewItem* selection, BOOL openitem, + BOOL take_keyboard_focus = TRUE); + // This function is called when the folder view is dirty. It's // implemented here but called by derived classes when folding the // views. diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index b705543e44..edbeed2aa4 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -51,6 +51,7 @@ #include "llviewercontrol.h" #include "llfirstuse.h" +#include "llfoldertype.h" #include "llfloaterchat.h" #include "llfloatercustomize.h" #include "llfloaterproperties.h" @@ -604,7 +605,7 @@ BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const if(obj) { - *type = LLAssetType::lookupDragAndDropType(obj->getType()); + *type = LLAssetType::lookupDragAndDropType(obj->getActualType()); if(*type == DAD_NONE) { return FALSE; @@ -653,11 +654,11 @@ BOOL LLInvFVBridge::isLinkedObjectInTrash() const { if (isInTrash()) return TRUE; - LLInventoryModel* model = getInventoryModel(); - if(!model) return FALSE; - LLInventoryObject *obj = model->getObject(mUUID); + LLInventoryObject *obj = getInventoryObject(); if (obj && LLAssetType::lookupIsLinkType(obj->getActualType())) { + LLInventoryModel* model = getInventoryModel(); + if(!model) return FALSE; const LLUUID& trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); return model->isObjectDescendentOf(obj->getLinkedUUID(), trash_id); } @@ -735,6 +736,7 @@ const std::string safe_inv_type_lookup(LLInventoryType::EType inv_type) } LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, + LLAssetType::EType actual_asset_type, LLInventoryType::EType inv_type, LLInventoryPanel* inventory, const LLUUID& uuid, @@ -833,12 +835,22 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, break; case LLAssetType::AT_CATEGORY: case LLAssetType::AT_ROOT_CATEGORY: + if (actual_asset_type == LLAssetType::AT_LINK_FOLDER) + { + // Create a link folder handler instead. + new_listener = new LLLinkFolderBridge(inventory, uuid); + break; + } new_listener = new LLFolderBridge(inventory, uuid); break; case LLAssetType::AT_LINK: // Only should happen for broken links. new_listener = new LLLinkItemBridge(inventory, uuid); break; + case LLAssetType::AT_LINK_FOLDER: + // Only should happen for broken links. + new_listener = new LLLinkItemBridge(inventory, uuid); + break; default: llinfos << "Unhandled asset type (llassetstorage.h): " << (S32)asset_type << llendl; @@ -875,6 +887,10 @@ void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) { + if ("goto" == action) + { + gotoItem(folder); + } if ("open" == action) { openItem(); @@ -1005,6 +1021,19 @@ void LLItemBridge::restoreToWorld() } } +void LLItemBridge::gotoItem(LLFolderView *folder) +{ + LLInventoryObject *obj = getInventoryObject(); + if (obj && LLAssetType::lookupIsLinkType(obj->getActualType())) + { + LLInventoryPanel* active_panel = LLFloaterInventory::getActiveInventory()->getPanel(); + if (active_panel) + { + active_panel->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO); + } + } +} + LLUIImagePtr LLItemBridge::getIcon() const { return LLUI::getUIImage(ICON_NAME[OBJECT_ICON_NAME]); @@ -1075,7 +1104,8 @@ std::string LLItemBridge::getLabelSuffix() const static std::string NO_COPY =LLTrans::getString("no_copy"); static std::string NO_MOD = LLTrans::getString("no_modify"); static std::string NO_XFER = LLTrans::getString("no_transfer"); - + static std::string LINK = LLTrans::getString("link"); + static std::string BROKEN_LINK = LLTrans::getString("broken_link"); std::string suffix; LLInventoryItem* item = getItem(); if(item) @@ -1084,8 +1114,10 @@ std::string LLItemBridge::getLabelSuffix() const if(LLAssetType::AT_CALLINGCARD != item->getType() && item->getPermissions().getOwner() == gAgent.getID()) { - BOOL link = (item->getActualType() == LLAssetType::AT_LINK); - const char* LINK = " (link)"; // *TODO: Seraph translate + BOOL broken_link = LLAssetType::lookupIsLinkType(item->getType()); + if (broken_link) return BROKEN_LINK; + + BOOL link = LLAssetType::lookupIsLinkType(item->getActualType()); if (link) return LINK; BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID()); @@ -1146,7 +1178,7 @@ BOOL LLItemBridge::renameItem(const std::string& new_name) buildDisplayName(new_item, mDisplayName); new_item->updateServer(FALSE); model->updateItem(new_item); - renameLinkedItems(item->getUUID(),new_name); + model->updateLinkedObjects(item->getUUID()); model->notifyObservers(); } @@ -1204,7 +1236,7 @@ BOOL LLItemBridge::isItemCopyable() const // All items can be copied, not all can be pasted. // The only time an item can't be copied is if it's a link // return (item->getPermissions().allowCopyBy(gAgent.getID())); - if (item->getActualType() == LLAssetType::AT_LINK) + if (LLAssetType::lookupIsLinkType(item->getActualType())) { return FALSE; } @@ -1259,7 +1291,7 @@ BOOL LLFolderBridge::isItemMovable() LLInventoryObject* obj = getInventoryObject(); if(obj) { - return (LLAssetType::AT_NONE == ((LLInventoryCategory*)obj)->getPreferredType()); + return (!LLAssetType::lookupIsProtectedCategoryType(((LLInventoryCategory*)obj)->getPreferredType())); } return FALSE; } @@ -1295,7 +1327,7 @@ BOOL LLFolderBridge::isItemRemovable() return FALSE; } - if( LLAssetType::AT_NONE != category->getPreferredType() ) + if(LLAssetType::lookupIsProtectedCategoryType(category->getPreferredType())) { return FALSE; } @@ -1308,7 +1340,7 @@ BOOL LLFolderBridge::isItemRemovable() for( i = 0; i < descendent_categories.count(); i++ ) { LLInventoryCategory* category = descendent_categories[i]; - if( LLAssetType::AT_NONE != category->getPreferredType() ) + if(LLAssetType::lookupIsProtectedCategoryType(category->getPreferredType())) { return FALSE; } @@ -1403,7 +1435,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); - BOOL is_movable = (LLAssetType::AT_NONE == inv_cat->getPreferredType()); + BOOL is_movable = (!LLAssetType::lookupIsProtectedCategoryType(inv_cat->getPreferredType())); if( is_movable ) { gInventory.collectDescendents( cat_id, descendent_categories, descendent_items, FALSE ); @@ -1411,7 +1443,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, for( i = 0; i < descendent_categories.count(); i++ ) { LLInventoryCategory* category = descendent_categories[i]; - if( LLAssetType::AT_NONE != category->getPreferredType() ) + if(LLAssetType::lookupIsProtectedCategoryType(category->getPreferredType())) { // ...can't move "special folders" like Textures is_movable = FALSE; @@ -1868,7 +1900,7 @@ void LLFolderBridge::openItem() BOOL LLFolderBridge::isItemRenameable() const { LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)getCategory(); - if(cat && (cat->getPreferredType() == LLAssetType::AT_NONE) + if(cat && !LLAssetType::lookupIsProtectedCategoryType(cat->getPreferredType()) && (cat->getOwnerID() == gAgent.getID())) { return TRUE; @@ -1904,13 +1936,26 @@ LLAssetType::EType LLFolderBridge::getPreferredType() const // Icons for folders are based on the preferred type LLUIImagePtr LLFolderBridge::getIcon() const { - const char* control = NULL; LLAssetType::EType preferred_type = LLAssetType::AT_NONE; LLViewerInventoryCategory* cat = getCategory(); if(cat) { preferred_type = cat->getPreferredType(); } + return getIcon(preferred_type); +} + +LLUIImagePtr LLFolderBridge::getIcon(LLAssetType::EType preferred_type) +{ + if (preferred_type >= LLAssetType::AT_FOLDER_ENSEMBLE_START && + preferred_type <= LLAssetType::AT_FOLDER_ENSEMBLE_END) + { + LLUIImage* icon = LLUI::getUIImage(LLFolderType::lookupIconName(preferred_type)); + if (icon) + return icon; + } + + const char* control = NULL; switch(preferred_type) { case LLAssetType::AT_TEXTURE: @@ -1984,7 +2029,7 @@ BOOL LLFolderBridge::renameItem(const std::string& new_name) new_cat->rename(new_name); new_cat->updateServer(FALSE); model->updateCategory(new_cat); - renameLinkedItems(cat->getUUID(),new_name); + model->updateLinkedObjects(cat->getUUID()); model->notifyObservers(); } @@ -2066,15 +2111,24 @@ void LLFolderBridge::pasteLinkFromClipboard() LLInventoryModel* model = getInventoryModel(); if(model) { - LLInventoryItem* item = NULL; LLDynamicArray<LLUUID> objects; LLInventoryClipboard::instance().retrieve(objects); S32 count = objects.count(); LLUUID parent_id(mUUID); for(S32 i = 0; i < count; i++) { - item = model->getItem(objects.get(i)); - if (item) + const LLUUID &object_id = objects.get(i); + if (LLInventoryCategory *cat = model->getCategory(object_id)) + { + link_inventory_item( + gAgent.getID(), + cat->getUUID(), + parent_id, + cat->getName(), + LLAssetType::AT_LINK_FOLDER, + LLPointer<LLInventoryCallback>(NULL)); + } + else if (LLInventoryItem *item = model->getItem(object_id)) { link_inventory_item( gAgent.getID(), @@ -2103,7 +2157,7 @@ void LLFolderBridge::folderOptionsMenu() const LLInventoryCategory* category = model->getCategory(mUUID); bool is_default_folder = category && - (LLAssetType::AT_NONE != category->getPreferredType()); + (LLAssetType::lookupIsProtectedCategoryType(category->getPreferredType())); // calling card related functionality for folders. @@ -2199,7 +2253,14 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) mItems.push_back(std::string("New Gesture")); mItems.push_back(std::string("New Clothes")); mItems.push_back(std::string("New Body Parts")); + mItems.push_back(std::string("Change Type")); + LLViewerInventoryCategory *cat = getCategory(); + if (cat && LLAssetType::lookupIsProtectedCategoryType(cat->getPreferredType())) + { + mDisabledItems.push_back(std::string("Change Type")); + } + getClipboardEntries(false, mItems, mDisabledItems, flags); //Added by spatters to force inventory pull on right-click to display folder options correctly. 07-17-06 @@ -2268,26 +2329,27 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, BOOL accept = FALSE; switch(cargo_type) { - case DAD_TEXTURE: - case DAD_SOUND: - case DAD_CALLINGCARD: - case DAD_LANDMARK: - case DAD_SCRIPT: - case DAD_OBJECT: - case DAD_NOTECARD: - case DAD_CLOTHING: - case DAD_BODYPART: - case DAD_ANIMATION: - case DAD_GESTURE: - accept = dragItemIntoFolder((LLInventoryItem*)cargo_data, - drop); - break; - case DAD_CATEGORY: - accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, + case DAD_TEXTURE: + case DAD_SOUND: + case DAD_CALLINGCARD: + case DAD_LANDMARK: + case DAD_SCRIPT: + case DAD_OBJECT: + case DAD_NOTECARD: + case DAD_CLOTHING: + case DAD_BODYPART: + case DAD_ANIMATION: + case DAD_GESTURE: + case DAD_LINK: + accept = dragItemIntoFolder((LLInventoryItem*)cargo_data, drop); - break; - default: - break; + break; + case DAD_CATEGORY: + accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, + drop); + break; + default: + break; } return accept; } @@ -2490,14 +2552,14 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { BOOL is_movable = TRUE; - switch( inv_item->getType() ) + switch( inv_item->getActualType() ) { case LLAssetType::AT_ROOT_CATEGORY: is_movable = FALSE; break; case LLAssetType::AT_CATEGORY: - is_movable = ( LLAssetType::AT_NONE == ((LLInventoryCategory*)inv_item)->getPreferredType() ); + is_movable = !LLAssetType::lookupIsProtectedCategoryType(((LLInventoryCategory*)inv_item)->getPreferredType()); break; default: break; @@ -2511,11 +2573,11 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { case LLAssetType::AT_CLOTHING: case LLAssetType::AT_BODYPART: - is_movable = !gAgentWearables.isWearingItem(inv_item->getUUID()); + is_movable = !gAgentWearables.isWearingItem(inv_item->getUUID(), TRUE); break; case LLAssetType::AT_OBJECT: - is_movable = !avatar->isWearingAttachment(inv_item->getUUID()); + is_movable = !avatar->isWearingAttachment(inv_item->getUUID(), TRUE); break; default: break; @@ -3435,7 +3497,7 @@ LLFontGL::StyleFlags LLObjectBridge::getLabelStyle() const } LLInventoryItem* item = getItem(); - if (item->getActualType() == LLAssetType::AT_LINK) + if (LLAssetType::lookupIsLinkType(item->getActualType())) { font |= LLFontGL::ITALIC; } @@ -3533,13 +3595,18 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { + LLInventoryItem* item = getItem(); + if (item && LLAssetType::lookupIsLinkType(item->getActualType())) + { + items.push_back(std::string("Goto Link")); + } + items.push_back(std::string("Properties")); getClipboardEntries(true, items, disabled_items, flags); LLObjectBridge::sContextMenuItemID = mUUID; - LLInventoryItem* item = getItem(); if(item) { LLVOAvatarSelf* avatarp = gAgent.getAvatarObject(); @@ -3619,7 +3686,7 @@ BOOL LLObjectBridge::renameItem(const std::string& new_name) buildDisplayName(new_item, mDisplayName); new_item->updateServer(FALSE); model->updateItem(new_item); - renameLinkedItems(item->getUUID(),new_name); + model->updateLinkedObjects(item->getUUID()); model->notifyObservers(); @@ -4513,6 +4580,11 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Open")); } + if (item && LLAssetType::lookupIsLinkType(item->getActualType())) + { + items.push_back(std::string("Goto Link")); + } + items.push_back(std::string("Properties")); getClipboardEntries(true, items, disabled_items, flags); @@ -5093,3 +5165,94 @@ void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } hideContextEntries(menu, items, disabled_items); } + + +// +=================================================+ +// | LLLinkBridge | +// +=================================================+ +// For broken links. + +std::string LLLinkFolderBridge::sPrefix("Link: "); + + +LLUIImagePtr LLLinkFolderBridge::getIcon() const +{ + LLAssetType::EType preferred_type = LLAssetType::AT_NONE; + if (LLViewerInventoryItem *item = getItem()) + { + if (const LLViewerInventoryCategory* cat = item->getLinkedCategory()) + { + preferred_type = cat->getPreferredType(); + } + } + return LLFolderBridge::getIcon(preferred_type); +} + +void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + // *TODO: Translate + lldebugs << "LLLink::buildContextMenu()" << llendl; + std::vector<std::string> items; + std::vector<std::string> disabled_items; + + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + items.push_back(std::string("Goto Link")); + items.push_back(std::string("Delete")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Delete")); + } + } + hideContextEntries(menu, items, disabled_items); +} + +void LLLinkFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if ("goto" == action) + { + gotoItem(folder); + return; + } + LLItemBridge::performAction(folder,model,action); +} + +void LLLinkFolderBridge::gotoItem(LLFolderView *folder) +{ + const LLUUID &cat_uuid = getFolderID(); + if (!cat_uuid.isNull()) + { + if (LLFolderViewItem *base_folder = folder->getItemByID(cat_uuid)) + { + if (LLInventoryModel* model = getInventoryModel()) + { + model->fetchDescendentsOf(cat_uuid); + } + base_folder->setOpen(TRUE); + folder->setSelectionFromRoot(base_folder,TRUE); + } + } +} + +const LLUUID &LLLinkFolderBridge::getFolderID() const +{ + if (LLViewerInventoryItem *link_item = getItem()) + { + if (const LLViewerInventoryCategory *cat = link_item->getLinkedCategory()) + { + const LLUUID& cat_uuid = cat->getUUID(); + return cat_uuid; + } + } + return LLUUID::null; +} diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index a37b7969ed..915dfec629 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -133,6 +133,7 @@ public: // This method is a convenience function which creates the correct // type of bridge based on some basic information static LLInvFVBridge* createBridge(LLAssetType::EType asset_type, + LLAssetType::EType actual_asset_type, LLInventoryType::EType inv_type, LLInventoryPanel* inventory, const LLUUID& uuid, @@ -156,6 +157,7 @@ public: } virtual std::string getLabelSuffix() const { return LLStringUtil::null; } virtual void openItem() {} + virtual void gotoItem(LLFolderView *folder) {} // for links virtual void previewItem() {openItem();} virtual void showProperties(); virtual BOOL isItemRenameable() const { return TRUE; } @@ -231,6 +233,7 @@ public: virtual void selectItem(); virtual void restoreItem(); virtual void restoreToWorld(); + virtual void gotoItem(LLFolderView *folder); virtual LLUIImagePtr getIcon() const; virtual const std::string& getDisplayName() const; @@ -274,6 +277,8 @@ public: virtual LLAssetType::EType getPreferredType() const; virtual LLUIImagePtr getIcon() const; + static LLUIImagePtr getIcon(LLAssetType::EType asset_type); + virtual BOOL renameItem(const std::string& new_name); virtual BOOL removeItem(); virtual void pasteFromClipboard(); @@ -591,6 +596,27 @@ protected: static std::string sPrefix; }; + +class LLLinkFolderBridge : public LLItemBridge +{ + friend class LLInvFVBridge; +public: + virtual const std::string& getPrefix() { return sPrefix; } + + virtual LLUIImagePtr getIcon() const; + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual void gotoItem(LLFolderView *folder); + +protected: + LLLinkFolderBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : + LLItemBridge(inventory, uuid) {} + const LLUUID &getFolderID() const; + +protected: + static std::string sPrefix; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInvFVBridgeAction (& its derived classes) // diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 2c281a4615..bba0c9a90d 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -475,6 +475,35 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, } } +void LLInventoryModel::updateLinkedObjects(const LLUUID& object_id) +{ + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + LLLinkedItemIDMatches is_linked_item_match(object_id); + collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + item_array, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); + + for (LLInventoryModel::cat_array_t::iterator cat_iter = cat_array.begin(); + cat_iter != cat_array.end(); + cat_iter++) + { + LLViewerInventoryCategory *linked_cat = (*cat_iter); + addChangedMask(LLInventoryObserver::LABEL, linked_cat->getUUID()); + }; + + for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + LLViewerInventoryItem *linked_item = (*iter); + addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); + }; + notifyObservers(); +} + void LLInventoryModel::collectLinkedItems(const LLUUID& id, item_array_t& items) { @@ -825,10 +854,10 @@ void LLInventoryModel::purgeObject(const LLUUID &id) void LLInventoryModel::purgeLinkedObjects(const LLUUID &id) { - LLInventoryItem* itemp = getItem(id); - if (!itemp) return; + LLInventoryObject* objectp = getObject(id); + if (!objectp) return; - if (LLAssetType::lookupIsLinkType(itemp->getActualType())) + if (LLAssetType::lookupIsLinkType(objectp->getActualType())) { return; } diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index c402fea886..f470a77985 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -181,7 +181,6 @@ public: cat_array_t& categories, item_array_t& items, BOOL include_trash); - void collectDescendentsIf(const LLUUID& id, cat_array_t& categories, item_array_t& items, @@ -192,8 +191,9 @@ public: // Assumes item_id is itself not a linked item. void collectLinkedItems(const LLUUID& item_id, item_array_t& items); - - // This method will return false if this inventory model is in an usabel state. + // Updates all linked objects pointing to this id. + void updateLinkedObjects(const LLUUID& object_id); + // The inventory model usage is sensitive to the initial construction of the // model. bool isInventoryUsable(); diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 3a7ef4dfc9..d2e07f0725 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -473,6 +473,14 @@ LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::sDragAndDrop3d[DAD_COUNT] &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND }, + // Source: DAD_LINK + { + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT + &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND + }, }; LLToolDragAndDrop::LLToolDragAndDrop() @@ -1894,7 +1902,7 @@ BOOL LLToolDragAndDrop::isInventoryGroupGiveAcceptable(LLInventoryItem* item) acceptable = FALSE; break; case LLAssetType::AT_OBJECT: - if(my_avatar->isWearingAttachment(item->getUUID())) + if(my_avatar->isWearingAttachment(item->getUUID(), TRUE)) { acceptable = FALSE; } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index 54b0a4f568..66da7d89fb 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -403,7 +403,8 @@ void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const void LLViewerInventoryCategory::updateServer(BOOL is_new) const { // communicate that change with the server. - if(LLAssetType::AT_NONE != mPreferredType) + + if (LLAssetType::lookupIsProtectedCategoryType(mPreferredType)) { LLNotifications::instance().add("CannotModifyProtectedCategories"); return; @@ -427,7 +428,7 @@ void LLViewerInventoryCategory::removeFromServer( void ) llinfos << "Removing inventory category " << mUUID << " from server." << llendl; // communicate that change with the server. - if(LLAssetType::AT_NONE != mPreferredType) + if(LLAssetType::lookupIsProtectedCategoryType(mPreferredType)) { LLNotifications::instance().add("CannotRemoveProtectedCategories"); return; @@ -977,7 +978,10 @@ LLAssetType::EType LLViewerInventoryItem::getType() const { return linked_item->getType(); } - + if (const LLViewerInventoryCategory *linked_category = getLinkedCategory()) + { + return linked_category->getType(); + } return LLInventoryItem::getType(); } @@ -997,6 +1001,10 @@ const std::string& LLViewerInventoryItem::getName() const { return linked_item->getName(); } + if (const LLViewerInventoryCategory *linked_category = getLinkedCategory()) + { + return linked_category->getName(); + } return LLInventoryItem::getName(); } diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 7084c9f37a..5198f5efc7 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -141,7 +141,6 @@ public: }; LLTransactionID getTransactionID() const { return mTransactionID; } -protected: const LLViewerInventoryItem *getLinkedItem() const; const LLViewerInventoryCategory *getLinkedCategory() const; diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index 6f2fd5e5e5..c788f8f095 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -77,6 +77,14 @@ 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 Script" layout="topleft" name="New Script"> @@ -230,6 +238,91 @@ parameter="eyes" /> </menu_item_call> </menu> + <menu + label="Change Type" + layout="topleft" + name="Change Type"> + <menu_item_call + label="Default" + layout="topleft" + name="Default"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="change_folder_type_default" /> + </menu_item_call> + <menu_item_call + label="Gloves" + layout="topleft" + name="Gloves"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="change_folder_type_gloves" /> + </menu_item_call> + <menu_item_call + label="Jacket" + layout="topleft" + name="Jacket"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="change_folder_type_jacket" /> + </menu_item_call> + <menu_item_call + label="Pants" + layout="topleft" + name="Pants"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="change_folder_type_pants" /> + </menu_item_call> + <menu_item_call + label="Shape" + layout="topleft" + name="Shape"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="change_folder_type_shape" /> + </menu_item_call> + <menu_item_call + label="Shoes" + layout="topleft" + name="Shoes"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="change_folder_type_shoes" /> + </menu_item_call> + <menu_item_call + label="Shirt" + layout="topleft" + name="Shirt"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="change_folder_type_shirt" /> + </menu_item_call> + <menu_item_call + label="Skirt" + layout="topleft" + name="Skirt"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="change_folder_type_skirt" /> + </menu_item_call> + <menu_item_call + label="Underpants" + layout="topleft" + name="Underpants"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="change_folder_type_underpants" /> + </menu_item_call> + <menu_item_call + label="Undershirt" + layout="topleft" + name="Undershirt"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="change_folder_type_undershirt" /> + </menu_item_call> + </menu> <menu_item_call label="Teleport" layout="topleft" @@ -271,6 +364,14 @@ parameter="restore" /> </menu_item_call> <menu_item_call + label="Goto Link" + layout="topleft" + name="Goto Link"> + <menu_item_call.on_click + function="Inventory.DoToSelected" + parameter="goto" /> + </menu_item_call> + <menu_item_call label="Open" layout="topleft" name="Open"> diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index e54ef88f34..626c084f0c 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -346,6 +346,8 @@ this texture in your inventory <string name="no_modify" value=" (no modify)" /> <string name="no_copy" value=" (no copy)" /> <string name="worn" value=" (worn)" /> + <string name="link" value=" (link)" /> + <string name="broken_link" value=" (broken_link)" /> <string name="LoadingContents">Loading contents...</string> <string name="NoContents">No contents</string> |