svn merge -r129617:130277 svn+ssh://svn.lindenlab.com/svn/linden/branches/avatar-pipeline/currently-worn-folder-5 into svn+ssh://svn.lindenlab.com/svn/linden/branches/viewer/viewer-2.0.0-3

For DEV-34223 : AVP Current Outfit Folder
For DEV-37485 : AVP Appearance Side Panel
For DEV-35335 : AVP Automatic Folder Classification

This merges the Appearance Side Panel / Ensemble Typing / Current Outfit Folder work for the AVP team.
master
Loren Shih 2009-08-12 19:03:20 +00:00
parent 0bf4b5f222
commit 7bbc5cdea6
32 changed files with 855 additions and 122 deletions

View File

@ -282,6 +282,12 @@ bool LLAssetType::lookupIsProtectedCategoryType(EType asset_type)
return true;
}
// static
bool LLAssetType::lookupIsEnsembleCategoryType(EType asset_type)
{
return (asset_type >= AT_FOLDER_ENSEMBLE_START &&
asset_type <= AT_FOLDER_ENSEMBLE_END);
}
// static. Generate a good default description
void LLAssetType::generateDescriptionFor(LLAssetType::EType asset_type,

View File

@ -186,6 +186,7 @@ public:
static const char* lookupCategoryName(EType asset_type);
static bool lookupIsProtectedCategoryType(EType asset_type);
static bool lookupIsEnsembleCategoryType(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().

View File

@ -133,6 +133,11 @@ LLAssetType::EType LLInventoryObject::getActualType() const
return mType;
}
BOOL LLInventoryObject::getIsLinkType() const
{
return LLAssetType::lookupIsLinkType(mType);
}
// See LLInventoryItem override.
// virtual
const LLUUID& LLInventoryObject::getLinkedUUID() const

View File

@ -97,7 +97,7 @@ public:
virtual const std::string& getName() const;
virtual LLAssetType::EType getType() const;
LLAssetType::EType getActualType() const; // bypasses indirection for linked items
BOOL getIsLinkType() const;
// mutators - will not call updateServer();
void setUUID(const LLUUID& new_uuid);
void rename(const std::string& new_name);

View File

@ -278,6 +278,8 @@ set(viewer_SOURCE_FILES
llnotify.cpp
lloutputmonitorctrl.cpp
lloverlaybar.cpp
llpanelappearance.cpp
llpanelappearancetab.cpp
llpanelavatar.cpp
llpanelavatarrow.cpp
llpanelavatartag.cpp
@ -305,6 +307,8 @@ set(viewer_SOURCE_FILES
llpanellandmarks.cpp
llpanellandmedia.cpp
llpanellogin.cpp
llpanellookinfo.cpp
llpanellooks.cpp
llpanelmedia.cpp
llpanelmeprofile.cpp
llpanelmovetip.cpp
@ -719,6 +723,8 @@ set(viewer_HEADER_FILES
llnotify.h
lloutputmonitorctrl.h
lloverlaybar.h
llpanelappearance.h
llpanelappearancetab.h
llpanelavatar.h
llpanelavatarrow.h
llpanelavatartag.h
@ -746,6 +752,8 @@ set(viewer_HEADER_FILES
llpanellandmarks.h
llpanellandmedia.h
llpanellogin.h
llpanellookinfo.h
llpanellooks.h
llpanelmedia.h
llpanelmeprofile.h
llpanelmovetip.h

View File

@ -9,50 +9,66 @@
asset_num="27"
xui_name="head"
icon_name="inv_folder_outfit_head.tga"
allowed="hair,eyes"
/>
<ensemble
asset_num="28"
xui_name="gloves"
icon_name="inv_folder_outfit_gloves.tga"
allowed="gloves"
/>
<ensemble
asset_num="29"
xui_name="jacket"
icon_name="inv_folder_outfit_jacket.tga"
allowed="jacket"
/>
<ensemble
asset_num="30"
xui_name="pants"
icon_name="inv_folder_outfit_pants.tga"
allowed="pants,underpants"
/>
<ensemble
asset_num="31"
xui_name="shape"
icon_name="inv_folder_outfit_shape.tga"
allowed="shape,skin,hair,eyes"
/>
<ensemble
asset_num="32"
xui_name="shoes"
icon_name="inv_folder_outfit_shoes.tga"
allowed="shoes,socks"
/>
<ensemble
asset_num="33"
xui_name="shirt"
icon_name="inv_folder_outfit_shirt.tga"
allowed="shirt,undershirt"
/>
<ensemble
asset_num="34"
xui_name="skirt"
icon_name="inv_folder_outfit_skirt.tga"
allowed=""
/>
<ensemble
asset_num="35"
xui_name="underpants"
icon_name="inv_folder_outfit_underpants.tga"
allowed="underpants"
/>
<ensemble
asset_num="36"
xui_name="undershirt"
icon_name="inv_folder_outfit_undershirt.tga"
allowed="undershirt"
/>
<ensemble
asset_num="47"
xui_name="outfit"
icon_name="inv_folder_outfit.tga"
allowed="outfit"
/>
</ensemble_defs>

View File

@ -37,6 +37,7 @@
#include "llfloatercustomize.h"
#include "llfloaterinventory.h"
#include "llinventorybridge.h"
#include "llinventorymodel.h"
#include "llnotify.h"
#include "llviewerregion.h"
@ -46,6 +47,9 @@
#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
LLAgentWearables gAgentWearables;
@ -662,13 +666,6 @@ BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id, BOOL include_linked_
return FALSE;
}
struct InitialWearableData
{
S32 mType;
U32 mIndex;
LLUUID mItemID;
};
// MULTI-WEARABLE: update for multiple
// static
void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data)
@ -696,14 +693,18 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs
return;
}
// 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();
//lldebugs << "processAgentInitialWearablesUpdate()" << llendl;
// Add wearables
LLUUID asset_id_array[WT_COUNT];
LLUUID item_id_array[WT_COUNT];
// MULTI-WEARABLE: TODO: update once messages change. Currently use results to populate the zeroth element.
gAgentWearables.mItemsAwaitingWearableUpdate.clear();
for (S32 i=0; i < num_wearables; i++)
{
// Parse initial werables data from message system
U8 type_u8 = 0;
gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i);
if (type_u8 >= WT_COUNT)
@ -711,10 +712,10 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs
continue;
}
const EWearableType type = (EWearableType) type_u8;
LLUUID item_id;
gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i);
LLUUID asset_id;
gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i);
if (asset_id.isNull())
@ -728,33 +729,76 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs
{
continue;
}
// MULTI-WEARABLE: extend arrays to index by type + index.
gAgentWearables.mItemsAwaitingWearableUpdate.insert(item_id);
item_id_array[type] = item_id;
asset_id_array[type] = asset_id;
// 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);
}
lldebugs << " " << LLWearableDictionary::getTypeLabel(type) << llendl;
}
// now that we have the asset ids...request the wearable assets
for (S32 i = 0; i < WT_COUNT; i++)
// What we do here is get the complete information on the items in
// the inventory, and set up an observer that will wait for that to
// happen.
LLInventoryFetchDescendentsObserver::folder_ref_t folders;
folders.push_back(current_outfit_id);
outfit->fetchDescendents(folders);
if(outfit->isEverythingComplete())
{
// MULTI-WEARABLE: TODO: update once messages change.
// Currently use results to populate the zeroth element.
if (!item_id_array[i].isNull())
{
InitialWearableData *wear_data = new InitialWearableData;
wear_data->mType = i;
wear_data->mIndex = 0; // MULTI-WEARABLE: update
wear_data->mItemID = item_id_array[i];
LLWearableList::instance().getAsset(asset_id_array[i],
LLStringUtil::null,
LLWearableDictionary::getAssetType((EWearableType) i),
onInitialWearableAssetArrived, (void*)wear_data);
}
// everything is already here - call done.
outfit->done();
}
else
{
// it's all on it's way - add an observer, and the inventory
// will call done for us when everything is here.
gInventory.addObserver(outfit);
}
}
}
// 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;
}
}
@ -763,7 +807,7 @@ void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgs
void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void* userdata)
{
boost::scoped_ptr<InitialWearableData> wear_data((InitialWearableData*)userdata);
const EWearableType type = (EWearableType)wear_data->mType;
const EWearableType type = wear_data->mType;
const U32 index = wear_data->mIndex;
LLVOAvatarSelf* avatar = gAgent.getAvatarObject();
@ -775,10 +819,11 @@ void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void*
if (wearable)
{
llassert(type == wearable->getType());
// MULTI-WEARABLE: is this always zeroth element? Change sometime.
wearable->setItemID(wear_data->mItemID);
gAgentWearables.setWearable(type,index,wearable);
gAgentWearables.setWearable(type, index, wearable);
gAgentWearables.mItemsAwaitingWearableUpdate.erase(wear_data->mItemID);
// disable composites if initial textures are baked
avatar->setupComposites();
@ -954,6 +999,8 @@ void LLAgentWearables::createStandardWearablesAllDone()
mAvatarObject->onFirstTEMessageReceived();
}
// 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,
const LLDynamicArray<S32>& wearables_to_include,
const LLDynamicArray<S32>& attachments_to_include,
@ -1087,6 +1134,98 @@ void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name,
}
}
// 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)
{
if (mAvatarObject.isNull())
{
return;
}
// First, make a folder in the Clothes directory.
LLUUID folder_id = gInventory.createNewCategory(
gInventory.findCategoryUUIDForType(LLAssetType::AT_MY_OUTFITS),
LLAssetType::AT_OUTFIT,
new_folder_name);
// bool found_first_item = false;
///////////////////
// Wearables
if (wearables_to_include.count())
{
// Then, iterate though each of the wearables and save links to them in the folder.
S32 i;
S32 count = wearables_to_include.count();
LLDynamicArray<LLUUID> delete_items;
LLPointer<LLRefCount> cbdone = NULL;
for (i = 0; i < count; ++i)
{
const S32 type = wearables_to_include[i];
for (U32 j=0; j<getWearableCount((EWearableType)i); j++)
{
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));
// BAP TODO
LLPointer<LLInventoryCallback> cb = NULL;
link_inventory_item(gAgent.getID(),
item->getUUID(),
folder_id,
new_name,
LLAssetType::AT_LINK,
cb);
}
}
}
gInventory.notifyObservers();
}
///////////////////
// Attachments
if (attachments_to_include.count())
{
for (S32 i = 0; i < attachments_to_include.count(); i++)
{
S32 attachment_pt = attachments_to_include[i];
LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL);
if (!attachment) continue;
LLViewerObject* attached_object = attachment->getObject();
if (!attached_object) continue;
const LLUUID& item_id = attachment->getItemID();
if (item_id.isNull()) continue;
LLInventoryItem* item = gInventory.getItem(item_id);
if (!item) continue;
// BAP link here
LLPointer<LLInventoryCallback> cb = NULL;
link_inventory_item(gAgent.getID(),
item->getUUID(),
folder_id,
item->getName(),
LLAssetType::AT_LINK,
cb);
}
}
}
void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index)
{
LLUUID first_item_id = getWearableItemID((EWearableType)type, index);
@ -1635,3 +1774,56 @@ void LLAgentWearables::updateServer()
sendAgentWearablesUpdate();
gAgent.sendAgentSetAppearance();
}
void LLAgentWearables::LLOutfitFolderFetch::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.
LLInventoryModel::cat_array_t cat_array;
LLInventoryModel::item_array_t item_array;
gInventory.collectDescendents(mCompleteFolders.front(),
cat_array,
item_array,
LLInventoryModel::EXCLUDE_TRASH);
S32 count = item_array.count();
LLAgentWearables::initial_wearable_data_vec_t current_outfit_links;
current_outfit_links.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)
{
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;
}
}
gInventory.removeObserver(this);
LLAgentWearables::fetchInitialWearables(current_outfit_links, mAgentInitialWearables);
mAgentInitialWearables.clear();
delete this;
}

View File

@ -36,14 +36,33 @@
#include "llmemory.h"
#include "lluuid.h"
#include "llinventory.h"
#include "llinventorymodel.h"
#include "llviewerinventory.h"
#include "llvoavatardefines.h"
class LLInventoryItem;
class LLVOAvatarSelf;
class LLWearable;
// Forward Declaration
class LLInventoryFetchDescendentsObserver;
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
//--------------------------------------------------------------------
@ -85,13 +104,14 @@ public:
U32 getWearableCount(const EWearableType type) const;
//--------------------------------------------------------------------
// Setters
//--------------------------------------------------------------------
private:
// Low-level data structure setter - public access is via setWearableItem, etc.
void setWearable(const EWearableType type, U32 index, LLWearable *wearable);
//--------------------------------------------------------------------
// Setters
//--------------------------------------------------------------------
public:
void setWearableItem(LLInventoryItem* new_item, LLWearable* wearable, bool do_append = false);
void setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLWearable* >& wearables, BOOL remove);
@ -127,7 +147,9 @@ protected:
// Server Communication
//--------------------------------------------------------------------
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();
@ -139,10 +161,19 @@ protected:
// Outfits
//--------------------------------------------------------------------
public:
// 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,
const LLDynamicArray<S32>& wearables_to_include,
const LLDynamicArray<S32>& attachments_to_include,
BOOL rename_clothing);protected:
BOOL rename_clothing);
// 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,
const LLDynamicArray<S32>& wearables_to_include,
const LLDynamicArray<S32>& attachments_to_include,
BOOL rename_clothing);
private:
void makeNewOutfitDone(S32 type, U32 index);
@ -223,6 +254,17 @@ 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

View File

@ -1274,9 +1274,9 @@ void LLInventoryPanel::draw()
LLPanel::draw();
}
void LLInventoryPanel::setFilterTypes(U32 filter_types)
void LLInventoryPanel::setFilterTypes(U64 filter_types, BOOL filter_for_categories)
{
mFolders->getFilter()->setFilterTypes(filter_types);
mFolders->getFilter()->setFilterTypes(filter_types, filter_for_categories);
}
void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask)

View File

@ -133,7 +133,7 @@ public:
void setSelectCallback(const LLFolderView::signal_t::slot_type& cb) { if (mFolders) mFolders->setSelectCallback(cb); }
void clearSelection();
LLInventoryFilter* getFilter() { return mFolders->getFilter(); }
void setFilterTypes(U32 filter);
void setFilterTypes(U64 filter, BOOL filter_for_categories = FALSE); // if filter_for_categories is true, operate on folder preferred asset type
U32 getFilterTypes() const { return mFolders->getFilterTypes(); }
void setFilterPermMask(PermissionMask filter_perm_mask);
U32 getFilterPermMask() const { return mFolders->getFilterPermissions(); }

View File

@ -244,7 +244,7 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item)
const BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm,
GP_OBJECT_SET_SALE) &&
!cannot_restrict_permissions;
const BOOL is_link = LLAssetType::lookupIsLinkType(i->getActualType());
const BOOL is_link = i->getIsLinkType();
// You need permission to modify the object to modify an inventory
// item in it.

View File

@ -1103,26 +1103,7 @@ void LLFolderView::changeType(LLInventoryModel *model, LLAssetType::EType new_fo
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);
cat->changeType(new_folder_type);
}
void LLFolderView::autoOpenItem( LLFolderViewFolder* item )

View File

@ -62,6 +62,7 @@ public:
virtual LLFontGL::StyleFlags getLabelStyle() const = 0;
virtual std::string getLabelSuffix() const = 0;
virtual void openItem( void ) = 0;
virtual void closeItem( void ) = 0;
virtual void previewItem( void ) = 0;
virtual void selectItem(void) = 0;
virtual void showProperties(void) = 0;

View File

@ -1912,12 +1912,16 @@ void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType r
{
BOOL was_open = mIsOpen;
mIsOpen = openitem;
if(!was_open && openitem)
if (mListener)
{
if(mListener)
if(!was_open && openitem)
{
mListener->openItem();
}
else if(was_open && !openitem)
{
mListener->closeItem();
}
}
if (recurse == RECURSE_DOWN || recurse == RECURSE_UP_DOWN)

View File

@ -113,7 +113,7 @@ void dec_busy_count()
struct LLWearableHoldingPattern;
void wear_add_inventory_item_on_avatar(LLInventoryItem* item);
void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append);
void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOOL append);
void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOOL append, BOOL follow_folder_links);
void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*);
void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append);
void remove_inventory_category_from_avatar(LLInventoryCategory* category);
@ -219,7 +219,7 @@ void LLInvFVBridge::renameLinkedItems(const LLUUID &item_id, const std::string&
LLInventoryItem* itemp = model->getItem(mUUID);
if (!itemp) return;
if (LLAssetType::lookupIsLinkType(itemp->getActualType()))
if (itemp->getIsLinkType())
{
return;
}
@ -654,7 +654,7 @@ BOOL LLInvFVBridge::isLinkedObjectInTrash() const
if (isInTrash()) return TRUE;
LLInventoryObject *obj = getInventoryObject();
if (obj && LLAssetType::lookupIsLinkType(obj->getActualType()))
if (obj && obj->getIsLinkType())
{
LLInventoryModel* model = getInventoryModel();
if(!model) return FALSE;
@ -1023,7 +1023,7 @@ void LLItemBridge::restoreToWorld()
void LLItemBridge::gotoItem(LLFolderView *folder)
{
LLInventoryObject *obj = getInventoryObject();
if (obj && LLAssetType::lookupIsLinkType(obj->getActualType()))
if (obj && obj->getIsLinkType())
{
LLInventoryPanel* active_panel = LLFloaterInventory::getActiveInventory()->getPanel();
if (active_panel)
@ -1089,7 +1089,7 @@ LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const
}
const LLViewerInventoryItem* item = getItem();
if (item && LLAssetType::lookupIsLinkType(item->getActualType()))
if (item && item->getIsLinkType())
{
font |= LLFontGL::ITALIC;
}
@ -1116,7 +1116,7 @@ std::string LLItemBridge::getLabelSuffix() const
BOOL broken_link = LLAssetType::lookupIsLinkType(item->getType());
if (broken_link) return BROKEN_LINK;
BOOL link = LLAssetType::lookupIsLinkType(item->getActualType());
BOOL link = item->getIsLinkType();
if (link) return LINK;
BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID());
@ -1241,7 +1241,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 (LLAssetType::lookupIsLinkType(item->getActualType()))
if (item->getIsLinkType())
{
return FALSE;
}
@ -1441,6 +1441,13 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
BOOL move_is_into_trash = (mUUID == trash_id)
|| model->isObjectDescendentOf(mUUID, trash_id);
BOOL is_movable = (!LLAssetType::lookupIsProtectedCategoryType(inv_cat->getPreferredType()));
LLUUID current_outfit_id = model->findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
BOOL move_is_into_current_outfit = (mUUID == current_outfit_id);
if (move_is_into_current_outfit)
{
// BAP - restrictions?
is_movable = true;
}
if( is_movable )
{
gInventory.collectDescendents( cat_id, descendent_categories, descendent_items, FALSE );
@ -1507,13 +1514,27 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,
}
}
// Reparent the folder and restamp children if it's moving
// into trash.
LLInvFVBridge::changeCategoryParent(
model,
(LLViewerInventoryCategory*)inv_cat,
mUUID,
move_is_into_trash);
if (current_outfit_id == mUUID) // if target is current outfit folder we use link
{
link_inventory_item(
gAgent.getID(),
inv_cat->getUUID(),
mUUID,
inv_cat->getName(),
LLAssetType::AT_LINK_FOLDER,
LLPointer<LLInventoryCallback>(NULL));
}
else
{
// Reparent the folder and restamp children if it's moving
// into trash.
LLInvFVBridge::changeCategoryParent(
model,
(LLViewerInventoryCategory*)inv_cat,
mUUID,
move_is_into_trash);
}
}
}
else if(LLToolDragAndDrop::SOURCE_WORLD == source)
@ -1899,7 +1920,29 @@ void LLFolderBridge::openItem()
lldebugs << "LLFolderBridge::openItem()" << llendl;
LLInventoryModel* model = getInventoryModel();
if(!model) return;
model->fetchDescendentsOf(mUUID);
bool fetching_inventory = model->fetchDescendentsOf(mUUID);
// Only change folder type if we have the folder contents.
if (!fetching_inventory)
{
// Disabling this for now, it's causing crash when new items are added to folders
// since folder type may change before new item item has finished processing.
// determineFolderType();
}
}
void LLFolderBridge::closeItem()
{
determineFolderType();
}
void LLFolderBridge::determineFolderType()
{
if (isUpToDate())
{
LLInventoryModel* model = getInventoryModel();
LLViewerInventoryCategory* category = model->getCategory(mUUID);
category->determineFolderType();
}
}
BOOL LLFolderBridge::isItemRenameable() const
@ -2013,6 +2056,15 @@ LLUIImagePtr LLFolderBridge::getIcon(LLAssetType::EType preferred_type)
//TODO - need icon
control = "inv_folder_plain_closed.tga";
break;
case LLAssetType::AT_OUTFIT:
control = "inv_folder_outfit.tga";
break;
case LLAssetType::AT_CURRENT_OUTFIT:
control = "inv_folder_current_outfit.tga";
break;
case LLAssetType::AT_MY_OUTFITS:
control = "inv_folder_my_outfits.tga";
break;
default:
control = "inv_folder_plain_closed.tga";
break;
@ -2199,6 +2251,10 @@ void LLFolderBridge::folderOptionsMenu()
}
mItems.push_back(std::string("Take Off Items"));
}
if (LLAssetType::AT_CURRENT_OUTFIT == category->getPreferredType())
{
mItems.push_back(std::string("Replace Outfit"));
}
hideContextEntries(*mMenu, mItems, disabled_items);
}
@ -2253,6 +2309,8 @@ 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"));
@ -2492,7 +2550,9 @@ void LLFolderBridge::modifyOutfit(BOOL append)
LLViewerInventoryCategory* cat = getCategory();
if(!cat) return;
wear_inventory_category_on_avatar( cat, append );
// BAP - was:
// wear_inventory_category_on_avatar( cat, append );
wear_inventory_category( cat, FALSE, append );
}
// helper stuff
@ -3500,7 +3560,7 @@ LLFontGL::StyleFlags LLObjectBridge::getLabelStyle() const
}
LLInventoryItem* item = getItem();
if (LLAssetType::lookupIsLinkType(item->getActualType()))
if (item && item->getIsLinkType())
{
font |= LLFontGL::ITALIC;
}
@ -3599,7 +3659,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
else
{
LLInventoryItem* item = getItem();
if (item && LLAssetType::lookupIsLinkType(item->getActualType()))
if (item && item->getIsLinkType())
{
items.push_back(std::string("Goto Link"));
}
@ -4086,17 +4146,18 @@ void wear_inventory_category_on_avatar( LLInventoryCategory* category, BOOL appe
lldebugs << "wear_inventory_category_on_avatar( " << category->getName()
<< " )" << llendl;
BOOL follow_folder_links = (category->getPreferredType() == LLAssetType::AT_CURRENT_OUTFIT || category->getPreferredType() == LLAssetType::AT_OUTFIT );
if( gFloaterCustomize )
{
gFloaterCustomize->askToSaveIfDirty(boost::bind(wear_inventory_category_on_avatar_step2, _1, category->getUUID(), append));
gFloaterCustomize->askToSaveIfDirty(boost::bind(wear_inventory_category_on_avatar_step2, _1, category->getUUID(), append, follow_folder_links));
}
else
{
wear_inventory_category_on_avatar_step2(TRUE, category->getUUID(), append );
wear_inventory_category_on_avatar_step2(TRUE, category->getUUID(), append, follow_folder_links );
}
}
void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOOL append )
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.
lldebugs << "wear_inventory_category_on_avatar_step2()" << llendl;
@ -4109,7 +4170,8 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO
cat_array,
item_array,
LLInventoryModel::EXCLUDE_TRASH,
is_wearable);
is_wearable,
follow_folder_links);
S32 i;
S32 wearable_count = item_array.count();
@ -4120,7 +4182,8 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO
obj_cat_array,
obj_item_array,
LLInventoryModel::EXCLUDE_TRASH,
is_object);
is_object,
follow_folder_links);
S32 obj_count = obj_item_array.count();
// Find all gestures in this folder
@ -4131,7 +4194,8 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO
gest_cat_array,
gest_item_array,
LLInventoryModel::EXCLUDE_TRASH,
is_gesture);
is_gesture,
follow_folder_links);
S32 gest_count = gest_item_array.count();
if( !wearable_count && !obj_count && !gest_count)
@ -4139,11 +4203,26 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO
LLNotifications::instance().add("CouldNotPutOnOutfit");
return;
}
const LLUUID &current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT);
// Processes that take time should show the busy cursor
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)
{
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)
{
gInventory.purgeObject(item_array.get(i)->getUUID());
}
}
}
// Activate all gestures in this folder
@ -4184,8 +4263,14 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO
for(i = 0; i < wearable_count; ++i)
{
gAddToOutfit = append;
found = found_container.get(i);
// Populate the current outfit folder with links to the newly added wearables
std::string link_name = "WearableLink";
link_inventory_item(gAgent.getID(), found->mItemID, current_outfit_id, link_name,
LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL));
// Fetch the wearables about to be worn.
LLWearableList::instance().getAsset(found->mAssetID,
found->mName,
found->mAssetType,
@ -4240,9 +4325,9 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO
msg->addBOOLFast(_PREHASH_FirstDetachAll, !append );
}
LLInventoryItem* item = obj_item_array.get(i);
const LLInventoryItem* item = obj_item_array.get(i).get();
msg->nextBlockFast(_PREHASH_ObjectData );
msg->addUUIDFast(_PREHASH_ItemID, item->getUUID() );
msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID());
msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner());
msg->addU8Fast(_PREHASH_AttachmentPt, 0 ); // Wear at the previous or default attachment point
pack_permissions_slam(msg, item->getFlags(), item->getPermissions());
@ -4254,9 +4339,26 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOO
// End of message chunk
msg->sendReliable( gAgent.getRegion()->getHost() );
}
}
for(i = 0; i < obj_count; ++i)
{
const std::string link_name = "AttachmentLink";
const LLInventoryItem* item = obj_item_array.get(i).get();
link_inventory_item(gAgent.getID(), item->getLinkedUUID(), current_outfit_id, link_name,
LLAssetType::AT_LINK, LLPointer<LLInventoryCallback>(NULL));
}
}
}
// Create a link to the folder that we wore.
LLViewerInventoryCategory* catp = gInventory.getCategory(category);
if (catp)
{
link_inventory_item(gAgent.getID(), category, current_outfit_id, catp->getName(),
LLAssetType::AT_LINK_FOLDER, LLPointer<LLInventoryCallback>(NULL));
}
}
}
@ -4583,7 +4685,7 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
items.push_back(std::string("Open"));
}
if (item && LLAssetType::lookupIsLinkType(item->getActualType()))
if (item && item->getIsLinkType())
{
items.push_back(std::string("Goto Link"));
}

View File

@ -157,6 +157,7 @@ public:
}
virtual std::string getLabelSuffix() const { return LLStringUtil::null; }
virtual void openItem() {}
virtual void closeItem() {}
virtual void gotoItem(LLFolderView *folder) {} // for links
virtual void previewItem() {openItem();}
virtual void showProperties();
@ -271,6 +272,7 @@ public:
BOOL drop);
virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action);
virtual void openItem();
virtual void closeItem();
virtual BOOL isItemRenameable() const;
virtual void selectItem();
virtual void restoreItem();
@ -325,6 +327,8 @@ protected:
BOOL checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& typeToCheck);
void modifyOutfit(BOOL append);
void determineFolderType();
public:
static LLFolderBridge* sSelf;
static void staticFolderOptionsMenu();

View File

@ -39,6 +39,7 @@
#include "llfolderviewitem.h"
#include "llinventorymodel.h" // gInventory.backgroundFetchActive()
#include "llviewercontrol.h"
#include "llviewerinventory.h"
// linden library includes
#include "lltrans.h"
@ -51,12 +52,13 @@ LLInventoryFilter::LLInventoryFilter(const std::string& name)
mModified(FALSE),
mNeedTextRebuild(TRUE)
{
mFilterOps.mFilterTypes = 0xffffffff;
mFilterOps.mFilterTypes = 0xffffffffffffffffULL;
mFilterOps.mMinDate = time_min();
mFilterOps.mMaxDate = time_max();
mFilterOps.mHoursAgo = 0;
mFilterOps.mShowFolderState = SHOW_NON_EMPTY_FOLDERS;
mFilterOps.mPermissions = PERM_NONE;
mFilterOps.mFilterForCategories = FALSE;
mOrder = SO_FOLDERS_BY_NAME; // This gets overridden by a pref immediately
@ -94,7 +96,25 @@ BOOL LLInventoryFilter::check(LLFolderViewItem* item)
}
LLFolderViewEventListener* listener = item->getListener();
mSubStringMatchOffset = mFilterSubString.size() ? item->getSearchableLabel().find(mFilterSubString) : std::string::npos;
BOOL passed = (0x1 << listener->getInventoryType() & mFilterOps.mFilterTypes || listener->getInventoryType() == LLInventoryType::IT_NONE)
bool passed_type = false;
if (mFilterOps.mFilterForCategories)
{
if (listener->getInventoryType() == LLInventoryType::IT_CATEGORY)
{
LLViewerInventoryCategory *cat = gInventory.getCategory(listener->getUUID());
if (cat)
{
passed_type |= ((1LL << cat->getPreferredType() & mFilterOps.mFilterTypes) != U64(0));
}
}
}
else
{
passed_type |= ((1LL << listener->getInventoryType() & mFilterOps.mFilterTypes) != U64(0)) || listener->getInventoryType() == LLInventoryType::IT_NONE;
}
BOOL passed = passed_type
&& (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos)
&& ((listener->getPermissionMask() & mFilterOps.mPermissions) == mFilterOps.mPermissions)
&& (listener->getCreationDate() >= earliest && listener->getCreationDate() <= mFilterOps.mMaxDate);
@ -124,7 +144,7 @@ BOOL LLInventoryFilter::isNotDefault()
BOOL LLInventoryFilter::isActive()
{
return mFilterOps.mFilterTypes != 0xffffffff
return mFilterOps.mFilterTypes != 0xffffffffffffffffULL
|| mFilterSubString.size()
|| mFilterOps.mPermissions != PERM_NONE
|| mFilterOps.mMinDate != time_min()
@ -144,7 +164,7 @@ BOOL LLInventoryFilter::isModifiedAndClear()
return ret;
}
void LLInventoryFilter::setFilterTypes(U32 types)
void LLInventoryFilter::setFilterTypes(U64 types, BOOL filter_for_categories)
{
if (mFilterOps.mFilterTypes != types)
{
@ -168,8 +188,8 @@ void LLInventoryFilter::setFilterTypes(U32 types)
{
setModified(FILTER_MORE_RESTRICTIVE);
}
}
mFilterOps.mFilterForCategories = filter_for_categories;
}
void LLInventoryFilter::setFilterSubString(const std::string& string)
@ -374,7 +394,7 @@ void LLInventoryFilter::setModified(EFilterBehavior behavior)
BOOL LLInventoryFilter::isFilterWith(LLInventoryType::EType t)
{
return mFilterOps.mFilterTypes & (0x01 << t);
return mFilterOps.mFilterTypes & (1LL << t);
}
std::string LLInventoryFilter::getFilterText()

View File

@ -64,7 +64,7 @@ public:
LLInventoryFilter(const std::string& name);
virtual ~LLInventoryFilter();
void setFilterTypes(U32 types);
void setFilterTypes(U64 types, BOOL filter_for_categories = FALSE); // if filter_for_categories is true, operate on folder preferred asset type
U32 getFilterTypes() const { return mFilterOps.mFilterTypes; }
void setFilterSubString(const std::string& string);
@ -120,7 +120,8 @@ public:
protected:
struct filter_ops
{
U32 mFilterTypes;
U64 mFilterTypes;
BOOL mFilterForCategories;
time_t mMinDate;
time_t mMaxDate;
U32 mHoursAgo;

View File

@ -434,7 +434,8 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
cat_array_t& cats,
item_array_t& items,
BOOL include_trash,
LLInventoryCollectFunctor& add)
LLInventoryCollectFunctor& add,
BOOL follow_folder_links)
{
// Start with categories
if(!include_trash)
@ -458,9 +459,38 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
}
}
// Move onto items
LLViewerInventoryItem* item = NULL;
item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id);
// Follow folder links recursively. Currently never goes more
// than one level deep (for current outfit support)
// Note: if making it fully recursive, need more checking against infinite loops.
if (follow_folder_links && item_array)
{
S32 count = item_array->count();
for(S32 i = 0; i < count; ++i)
{
item = item_array->get(i);
if (item->getActualType() == LLAssetType::AT_LINK_FOLDER)
{
// BAP either getLinkedCategory() should return non-const, or the functor should take const.
LLViewerInventoryCategory *linked_cat = const_cast<LLViewerInventoryCategory*>(item->getLinkedCategory());
if (linked_cat)
{
if(add(linked_cat,NULL))
{
// BAP should this be added here? May not
// matter if it's only being used in current
// outfit traversal.
cats.put(LLPointer<LLViewerInventoryCategory>(linked_cat));
}
collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, FALSE);
}
}
}
}
// Move onto items
if(item_array)
{
S32 count = item_array->count();
@ -872,7 +902,7 @@ void LLInventoryModel::purgeLinkedObjects(const LLUUID &id)
LLInventoryObject* objectp = getObject(id);
if (!objectp) return;
if (LLAssetType::lookupIsLinkType(objectp->getActualType()))
if (objectp->getIsLinkType())
{
return;
}
@ -1196,14 +1226,14 @@ void LLInventoryModel::fetchInventoryResponder::error(U32 status, const std::str
gInventory.notifyObservers("fetchinventory");
}
void LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)
bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)
{
LLViewerInventoryCategory* cat = getCategory(folder_id);
if(!cat)
{
llwarns << "Asked to fetch descendents of non-existent folder: "
<< folder_id << llendl;
return;
return false;
}
//S32 known_descendents = 0;
///cat_array_t* categories = get_ptr_in_map(mParentChildCategoryTree, folder_id);
@ -1216,10 +1246,7 @@ void LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id)
//{
// known_descendents += items->count();
//}
if(!cat->fetchDescendents())
{
//llinfos << "Not fetching descendents" << llendl;
}
return cat->fetchDescendents();
}
//Initialize statics.
@ -1337,6 +1364,7 @@ void fetchDescendentsResponder::result(const LLSD& content)
{
cat->setVersion(version);
cat->setDescendentCount(descendents);
cat->determineFolderType();
}
}
@ -4059,7 +4087,7 @@ bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* ite
bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item)
{
return (item &&
(LLAssetType::lookupIsLinkType(item->getActualType())) &&
(item->getIsLinkType()) &&
(item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID.
}

View File

@ -185,7 +185,8 @@ public:
cat_array_t& categories,
item_array_t& items,
BOOL include_trash,
LLInventoryCollectFunctor& add);
LLInventoryCollectFunctor& add,
BOOL follow_folder_links = FALSE);
// Collect all items in inventory that are linked to item_id.
// Assumes item_id is itself not a linked item.
@ -296,8 +297,9 @@ public:
// minimal functionality before the actual arrival of inventory.
//void mock(const LLUUID& root_id);
// make sure we have the descendents in the structure.
void fetchDescendentsOf(const LLUUID& folder_id);
// Make sure we have the descendents in the structure. Returns true
// if a fetch was performed.
bool fetchDescendentsOf(const LLUUID& folder_id);
// Add categories to a list to be fetched in bulk.
static void bulkFetch(std::string url);

View File

@ -0,0 +1,72 @@
/**
* @file llpanelteleporthistory.h
* @brief Teleport history represented by a scrolling list
* class definition
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLPANELLOOKSHISTORY_H
#define LL_LLPANELLOOKSHISTORY_H
#include "lluictrlfactory.h"
#include "llscrolllistctrl.h"
#include "llpanelappearancetab.h"
#include "lllookshistory.h"
class LLLooksHistoryPanel : public LLPanelAppearanceTab
{
public:
LLLooksHistoryPanel();
virtual ~LLLooksHistoryPanel();
/*virtual*/ BOOL postBuild();
/*virtual*/ void onSearchEdit(const std::string& string);
/*virtual*/ void onShowOnMap();
/*virtual*/ void onLooks();
///*virtual*/ void onCopySLURL();
void showLooksHistory();
void handleItemSelect(const LLSD& data);
static void onDoubleClickItem(void* user_data);
private:
enum LOOKS_HISTORY_COLUMN_ORDER
{
LIST_ICON,
LIST_ITEM_TITLE,
LIST_INDEX
};
LLLooksHistory* mLooksHistory;
LLScrollListCtrl* mHistoryItems;
std::string mFilterSubString;
};
#endif //LL_LLPANELLOOKSHISTORY_H

View File

@ -0,0 +1,65 @@
/**
* @file llpanelplacestab.h
* @brief Tabs interface for Side Bar "Places" panel
*
* $LicenseInfo:firstyear=2009&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#ifndef LL_LLPANELAPPEARANCETAB_H
#define LL_LLPANELAPPEARANCETAB_H
#include "llpanel.h"
#include "llpanelappearance.h"
class LLPanelAppearanceTab : public LLPanel
{
public:
LLPanelAppearanceTab(LLPanelAppearance *parent) :
LLPanel(),
mParent(parent)
{}
virtual ~LLPanelAppearanceTab() {}
virtual void onSearchEdit(const std::string& string) = 0;
virtual void updateVerbs() = 0; // Updates buttons at the bottom of Appearance panel
virtual void onWear() = 0;
virtual void onEdit() = 0;
virtual void onNew() = 0;
bool isTabVisible(); // Check if parent TabContainer is visible.
void setPanelAppearanceButtons(LLPanelAppearance* panel);
protected:
LLButton* mWearBtn;
LLButton* mEditBtn;
LLPanelAppearance* mParent;
};
#endif //LL_LLPANELAPPEARANCETAB_H

View File

@ -37,6 +37,7 @@
#include "indra_constants.h"
#include "llagent.h"
#include "llfoldertype.h"
#include "llviewercontrol.h"
#include "llconsole.h"
#include "llinventorymodel.h"
@ -587,6 +588,79 @@ bool LLViewerInventoryCategory::exportFileLocal(LLFILE* fp) const
return true;
}
void LLViewerInventoryCategory::determineFolderType()
{
LLAssetType::EType original_type = getPreferredType();
if (LLAssetType::lookupIsProtectedCategoryType(original_type))
return;
U64 folder_valid = 0;
U64 folder_invalid = 0;
LLInventoryModel::cat_array_t category_array;
LLInventoryModel::item_array_t item_array;
gInventory.collectDescendents(getUUID(),category_array,item_array,FALSE);
// For ensembles
if (category_array.empty())
{
for (LLInventoryModel::item_array_t::iterator item_iter = item_array.begin();
item_iter != item_array.end();
item_iter++)
{
const LLViewerInventoryItem *item = (*item_iter);
if (item->getIsLinkType())
return;
if (item->getInventoryType() == LLInventoryType::IT_WEARABLE)
{
U32 flags = item->getFlags();
if (flags > WT_COUNT)
return;
const EWearableType wearable_type = EWearableType(flags);
const std::string& wearable_name = LLWearableDictionary::getTypeName(wearable_type);
U64 valid_folder_types = LLFolderType::lookupValidFolderTypes(wearable_name);
folder_valid |= valid_folder_types;
folder_invalid |= ~valid_folder_types;
}
}
for (U8 i = LLAssetType::AT_FOLDER_ENSEMBLE_START; i <= LLAssetType::AT_FOLDER_ENSEMBLE_END; i++)
{
if ((folder_valid & (1LL << i)) &&
!(folder_invalid & (1LL << i)))
{
changeType((LLAssetType::EType)i);
return;
}
}
}
if (LLAssetType::lookupIsEnsembleCategoryType(original_type))
{
changeType(LLAssetType::AT_NONE);
}
}
void LLViewerInventoryCategory::changeType(LLAssetType::EType new_folder_type)
{
const LLUUID &folder_id = getUUID();
const LLUUID &parent_id = getParentUUID();
const std::string &name = 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();
setPreferredType(new_folder_type);
gInventory.addChangedMask(LLInventoryObserver::LABEL, folder_id);
gInventory.updateLinkedObjects(folder_id);
}
///----------------------------------------------------------------------------
/// Local function definitions
///----------------------------------------------------------------------------
@ -880,16 +954,23 @@ void menu_create_inventory_item(LLFolderView* folder, LLFolderBridge *bridge, co
{
std::string type = userdata.asString();
if ("category" == type)
if (("category" == type) || ("current" == type) || ("outfit" == type) || ("my_otfts" == type) )
{
LLAssetType::EType a_type = LLAssetType::AT_NONE;
if ("current" == type)
a_type = LLAssetType::AT_CURRENT_OUTFIT;
if ("outfit" == type)
a_type = LLAssetType::AT_OUTFIT;
if ("my_otfts" == type)
a_type = LLAssetType::AT_MY_OUTFITS;
LLUUID category;
if (bridge)
{
category = gInventory.createNewCategory(bridge->getUUID(), LLAssetType::AT_NONE, LLStringUtil::null);
category = gInventory.createNewCategory(bridge->getUUID(), a_type, LLStringUtil::null);
}
else
{
category = gInventory.createNewCategory(gInventory.getRootFolderID(), LLAssetType::AT_NONE, LLStringUtil::null);
category = gInventory.createNewCategory(gInventory.getRootFolderID(), a_type, LLStringUtil::null);
}
gInventory.notifyObservers();
folder->setSelectionByID(category, TRUE);
@ -1029,6 +1110,11 @@ const std::string& LLViewerInventoryItem::getName() const
const LLPermissions& LLViewerInventoryItem::getPermissions() const
{
if (const LLViewerInventoryItem *linked_item = getLinkedItem())
{
return linked_item->getPermissions();
}
// Use the actual permissions of the symlink, not its parent.
return LLInventoryItem::getPermissions();
}
@ -1070,6 +1156,13 @@ LLInventoryType::EType LLViewerInventoryItem::getInventoryType() const
return linked_item->getInventoryType();
}
// Categories don't have types. If this item is an AT_FOLDER_LINK,
// treat it as a category.
if (getLinkedCategory())
{
return LLInventoryType::IT_CATEGORY;
}
return LLInventoryItem::getInventoryType();
}
@ -1079,7 +1172,6 @@ U32 LLViewerInventoryItem::getFlags() const
{
return linked_item->getFlags();
}
return LLInventoryItem::getFlags();
}

View File

@ -206,7 +206,8 @@ public:
// other than cacheing.
bool exportFileLocal(LLFILE* fp) const;
bool importFileLocal(LLFILE* fp);
void determineFolderType();
void changeType(LLAssetType::EType new_folder_type);
protected:
LLUUID mOwnerID;
S32 mVersion;

Binary file not shown.

After

Width:  |  Height:  |  Size: 808 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 B

View File

@ -174,6 +174,9 @@
<texture name="Stepper_Up_Off" file_name="widgets/Stepper_Up_Off.png" preload="true"/>
<texture name="Stepper_Up_Press" file_name="widgets/Stepper_Up_Press.png" preload="true"/>
<texture name="TabIcon_Appearance_Off" file_name="taskpanel/TabIcon_Appearance_Off.png" preload="false" />
<texture name="TabIcon_Appearance_Over" file_name="taskpanel/TabIcon_Appearance_Over.png" preload="false"/>
<texture name="TabIcon_Appearance_Selected" file_name="taskpanel/TabIcon_Appearance_Selected.png" preload="false" />
<texture name="TabIcon_Close_Off" file_name="taskpanel/TabIcon_Close_Off.png" preload="false" />
<texture name="TabIcon_Close_Over" file_name="taskpanel/TabIcon_Close_Over.png" preload="false"/>
<texture name="TabIcon_Home_Off" file_name="taskpanel/TabIcon_Home_Off.png" preload="false" />

View File

@ -206,6 +206,22 @@
function="Inventory.DoCreate"
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"

View File

@ -84,6 +84,22 @@
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"
@ -322,6 +338,14 @@
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"

View File

@ -74,7 +74,7 @@
class="panel_places"
name="panel_places"
filename="panel_places.xml"
label="Places"
label="Places"
border="true"
/>
</sidetray_tab>
@ -586,5 +586,25 @@
</sidetray_tab>
-->
<sidetray_tab
name="sidebar_appearance"
tab_title="Appearance"
description="Change your looks and appearance."
image="TabIcon_Appearance_Off"
mouse_opaque="false"
background_opaque="false"
background_visible="true"
bg_opaque_color="0.5 0.5 0.5 1.0"
>
<panel
class="panel_appearance"
name="panel_appearance"
filename="panel_appearance.xml"
border="true"
/>
</sidetray_tab>
</side_tray>

View File

@ -85,6 +85,31 @@
mouse_opaque="false" name="tab_description" >
Change your profile, your look and quick links to your outfits.
</text>
</panel>
<panel
left="10" width="280" height="130"
background_visible="true"
background_opaque="false"
bg_alpha_color="0.3 0.3 0.3 1.0"
name="sidebar_appearance"
follows="left|top|right"
class="panel_sidetray_home_info">
<text
top="-10" width="200" left="5" height="30" follows="left|right|top"
font="SansSerifHugeBold" text_color="white" word_wrap="true"
mouse_opaque="false" name="tab_name" >
Appearance
</text>
<icon
top="-10" right="-10" width="20" height="20" follows="top|right"
color="1 1 1 1" enabled="true" image_name="inv_item_shirt.tga"
mouse_opaque="false" name="tab_icon"/>
<text
top="-40" left="10" right="-10" height="120" follows="left|right|bottom"
font="SansSerifBig" text_color="white" word_wrap="true"
mouse_opaque="false" name="tab_description" >
Change your appearance.
</text>
</panel>
</panel>

View File

@ -409,6 +409,8 @@ this texture in your inventory
<string name="InvFolder Animations">Animations</string>
<string name="InvFolder Gestures">Gestures</string>
<string name="InvFolder favorite">Favorites</string>
<string name="InvFolder Current Outfit">Current Outfit</string>
<string name="InvFolder My Outfits">My Outfits</string>
<!-- inventory FVBridge -->
<string name="Buy">Buy</string>