Automated merge with ssh://hg.lindenlab.com/viewer/viewer-2-0/

meow-7.2.2
Eric M. Tulla (BigPapi) 2009-11-23 20:02:09 -05:00
commit bfd2605bf8
9 changed files with 240 additions and 105 deletions

View File

@ -34,6 +34,7 @@
#include "linden_common.h"
#include "llurlentry.h"
#include "lluri.h"
#include "llcachename.h"
#include "lltrans.h"
#include "lluicolortable.h"
@ -383,6 +384,38 @@ std::string LLUrlEntryGroup::getLabel(const std::string &url, const LLUrlLabelCa
}
}
//
// LLUrlEntryInventory Describes a Second Life inventory Url, e.g.,
// secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select
//
LLUrlEntryInventory::LLUrlEntryInventory()
{
mPattern = boost::regex("secondlife:///app/inventory/[\\da-f-]+/\\w+",
boost::regex::perl|boost::regex::icase);
mMenuName = "menu_url_inventory.xml";
}
std::string LLUrlEntryInventory::getLabel(const std::string &url, const LLUrlLabelCallback &cb)
{
return unescapeUrl(url);
// TODO: Figure out if we can somehow access the inventory from here to get the actual item name
/*
std::string inventory_id_string = getIDStringFromUrl(url);
if (inventory_id_string.empty())
{
// something went wrong, give raw url
return unescapeUrl(url);
}
LLUUID inventory_id(inventory_id_string);
LLInventoryItem* item = gInventory.getItem(inventory_id);
if(!item)
{
return unescapeUrl(url);
}
return item->getName(); */
}
///
/// LLUrlEntryParcel Describes a Second Life parcel Url, e.g.,
/// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about

View File

@ -173,6 +173,19 @@ private:
const std::string& last, BOOL is_group);
};
///
/// LLUrlEntryInventory Describes a Second Life inventory Url, e.g.,
/// secondlife:///app/inventory/0e346d8b-4433-4d66-a6b0-fd37083abc4c/select
///
class LLUrlEntryInventory : public LLUrlEntryBase
{
public:
LLUrlEntryInventory();
/*virtual*/ std::string getLabel(const std::string &url, const LLUrlLabelCallback &cb);
private:
};
///
/// LLUrlEntryParcel Describes a Second Life parcel Url, e.g.,
/// secondlife:///app/parcel/0000060e-4b39-e00b-d0c3-d98b1934e3a8/about

View File

@ -55,6 +55,7 @@ LLUrlRegistry::LLUrlRegistry()
registerUrl(new LLUrlEntryPlace());
registerUrl(new LLUrlEntrySL());
registerUrl(new LLUrlEntrySLLabel());
registerUrl(new LLUrlEntryInventory());
}
LLUrlRegistry::~LLUrlRegistry()

View File

@ -113,7 +113,7 @@ public:
bool isEverythingComplete() const;
void fetchItems(const item_ref_t& ids);
virtual void done() = 0;
virtual void done() {};
protected:
item_ref_t mComplete;

View File

@ -56,11 +56,43 @@
#include "lltrans.h"
#include "llappearancemgr.h"
#include "llfloatercustomize.h"
#include "llcommandhandler.h"
#include "llviewermessage.h"
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
///----------------------------------------------------------------------------
class LLInventoryHandler : public LLCommandHandler
{
public:
// requires trusted browser to trigger
LLInventoryHandler() : LLCommandHandler("inventory", UNTRUSTED_THROTTLE) { }
bool handle(const LLSD& params, const LLSD& query_map,
LLMediaCtrl* web)
{
if (params.size() < 2) return false;
LLUUID inventory_id;
if (!inventory_id.set(params[0], FALSE))
{
return false;
}
const std::string verb = params[1].asString();
//if (verb == "select")
{
std::vector<LLUUID> items_to_open;
items_to_open.push_back(inventory_id);
open_inventory_offer(items_to_open, "");
return true;
}
return false;
}
};
LLInventoryHandler gInventoryHandler;
///----------------------------------------------------------------------------
/// Class LLViewerInventoryItem
///----------------------------------------------------------------------------

View File

@ -169,7 +169,6 @@ static const F32 LLREQUEST_PERMISSION_THROTTLE_INTERVAL = 10.0f; // seconds
extern BOOL gDebugClicks;
// function prototypes
void open_offer(const std::vector<LLUUID>& items, const std::string& from_name);
bool check_offer_throttle(const std::string& from_name, bool check_only);
//inventory offer throttle globals
@ -726,7 +725,7 @@ public:
LLOpenAgentOffer(const std::string& from_name) : mFromName(from_name) {}
/*virtual*/ void done()
{
open_offer(mComplete, mFromName);
open_inventory_offer(mComplete, mFromName);
gInventory.removeObserver(this);
delete this;
}
@ -744,7 +743,7 @@ class LLOpenTaskOffer : public LLInventoryAddedObserver
protected:
/*virtual*/ void done()
{
open_offer(mAdded, "");
open_inventory_offer(mAdded, "");
mAdded.clear();
}
};
@ -875,7 +874,7 @@ bool check_offer_throttle(const std::string& from_name, bool check_only)
}
}
void open_offer(const std::vector<LLUUID>& items, const std::string& from_name)
void open_inventory_offer(const std::vector<LLUUID>& items, const std::string& from_name)
{
std::vector<LLUUID>::const_iterator it = items.begin();
std::vector<LLUUID>::const_iterator end = items.end();
@ -1065,22 +1064,8 @@ LLSD LLOfferInfo::asLLSD()
return sd;
}
bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response)
{
LLChat chat;
std::string log_message;
S32 button = LLNotification::getSelectedOption(notification, response);
// For muting, we need to add the mute, then decline the offer.
// This must be done here because:
// * callback may be called immediately,
// * adding the mute sends a message,
// * we can't build two messages at once.
if (2 == button)
{
gCacheName->get(mFromID, mFromGroup, &inventory_offer_mute_callback);
}
void LLOfferInfo::send_auto_receive_response(void)
{
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_ImprovedInstantMessage);
msg->nextBlockFast(_PREHASH_AgentData);
@ -1099,6 +1084,31 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
msg->addU32Fast(_PREHASH_ParentEstateID, 0);
msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null);
msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent());
// Auto Receive Message. The math for the dialog works, because the accept
// for inventory_offered, task_inventory_offer or
// group_notice_inventory is 1 greater than the offer integer value.
// Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED,
// or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData),
sizeof(mFolderID.mData));
// send the message
msg->sendReliable(mHost);
if(IM_INVENTORY_OFFERED == mIM)
{
// add buddy to recent people list
LLRecentPeople::instance().add(mFromID);
}
}
bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& response)
{
LLChat chat;
std::string log_message;
S32 button = LLNotification::getSelectedOption(notification, response);
LLInventoryObserver* opener = NULL;
LLViewerInventoryCategory* catp = NULL;
catp = (LLViewerInventoryCategory*)gInventory.getCategory(mObjectID);
@ -1107,6 +1117,16 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
{
itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID);
}
// For muting, we need to add the mute, then decline the offer.
// This must be done here because:
// * callback may be called immediately,
// * adding the mute sends a message,
// * we can't build two messages at once.
if (2 == button)
{
gCacheName->get(mFromID, mFromGroup, &inventory_offer_mute_callback);
}
std::string from_string; // Used in the pop-up.
std::string chatHistory_string; // Used in chat history.
@ -1157,64 +1177,54 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
switch(button)
{
case IOR_ACCEPT:
// ACCEPT. The math for the dialog works, because the accept
// for inventory_offered, task_inventory_offer or
// group_notice_inventory is 1 greater than the offer integer value.
// Generates IM_INVENTORY_ACCEPTED, IM_TASK_INVENTORY_ACCEPTED,
// or IM_GROUP_NOTICE_INVENTORY_ACCEPTED
msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 1));
msg->addBinaryDataFast(_PREHASH_BinaryBucket, &(mFolderID.mData),
sizeof(mFolderID.mData));
// send the message
msg->sendReliable(mHost);
//don't spam them if they are getting flooded
if (check_offer_throttle(mFromName, true))
{
log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
chat.mText = log_message;
LLFloaterChat::addChatHistory(chat);
}
case IOR_SHOW:
// we will want to open this item when it comes back.
LL_DEBUGS("Messaging") << "Initializing an opener for tid: " << mTransactionID
<< LL_ENDL;
switch (mIM)
{
case IM_INVENTORY_OFFERED:
{
// This is an offer from an agent. In this case, the back
// end has already copied the items into your inventory,
// so we can fetch it out of our inventory.
LLInventoryFetchObserver::item_ref_t items;
items.push_back(mObjectID);
LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(from_string);
open_agent_offer->fetchItems(items);
if(catp || (itemp && itemp->isComplete()))
{
open_agent_offer->done();
// This is an offer from an agent. In this case, the back
// end has already copied the items into your inventory,
// so we can fetch it out of our inventory.
LLInventoryFetchObserver::item_ref_t items;
items.push_back(mObjectID);
LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(from_string);
open_agent_offer->fetchItems(items);
if(catp || (itemp && itemp->isComplete()))
{
open_agent_offer->done();
}
else
{
opener = open_agent_offer;
}
}
else
{
opener = open_agent_offer;
}
}
break;
case IM_TASK_INVENTORY_OFFERED:
case IM_GROUP_NOTICE:
case IM_GROUP_NOTICE_REQUESTED:
{
// This is an offer from a task or group.
// We don't use a new instance of an opener
// We instead use the singular observer gOpenTaskOffer
// Since it already exists, we don't need to actually do anything
}
break;
break;
default:
LL_WARNS("Messaging") << "inventory_offer_callback: unknown offer type" << LL_ENDL;
break;
} // end switch (mIM)
// Show falls through to accept.
case IOR_ACCEPT:
//don't spam them if they are getting flooded
if (check_offer_throttle(mFromName, true))
{
log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString(".");
chat.mText = log_message;
LLFloaterChat::addChatHistory(chat);
}
break;
case IOR_BUSY:
@ -1223,31 +1233,15 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
case IOR_MUTE:
// MUTE falls through to decline
case IOR_DECLINE:
// DECLINE. The math for the dialog works, because the decline
// for inventory_offered, task_inventory_offer or
// group_notice_inventory is 2 greater than the offer integer value.
// Generates IM_INVENTORY_DECLINED, IM_TASK_INVENTORY_DECLINED,
// or IM_GROUP_NOTICE_INVENTORY_DECLINED
default:
// close button probably (or any of the fall-throughs from above)
msg->addU8Fast(_PREHASH_Dialog, (U8)(mIM + 2));
msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE);
// send the message
msg->sendReliable(mHost);
log_message = LLTrans::getString("InvOfferYouDecline") + " " + mDesc + " " + LLTrans::getString("InvOfferFrom") + " " + mFromName +".";
chat.mText = log_message;
if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269
{
chat.mMuted = TRUE;
}
LLFloaterChat::addChatHistory(chat);
// If it's from an agent, we have to fetch the item to throw
// it away. If it's from a task or group, just denying the
// request will suffice to discard the item.
if(IM_INVENTORY_OFFERED == mIM)
{
log_message = LLTrans::getString("InvOfferYouDecline") + " " + mDesc + " " + LLTrans::getString("InvOfferFrom") + " " + mFromName +".";
chat.mText = log_message;
if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269
{
chat.mMuted = TRUE;
}
LLFloaterChat::addChatHistory(chat);
LLInventoryFetchComboObserver::folder_ref_t folders;
LLInventoryFetchComboObserver::item_ref_t items;
items.push_back(mObjectID);
@ -1263,20 +1257,21 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
opener = discard_agent_offer;
}
if (busy && (!mFromGroup && !mFromObject))
{
busy_message(gMessageSystem, mFromID);
}
break;
}
if (busy && (!mFromGroup && !mFromObject))
{
busy_message(msg,mFromID);
}
default:
// close button probably
// The item has already been fetched and is in your inventory, we simply won't highlight it
// OR delete it if the notification gets killed, since we don't want that to be a vector for
// losing inventory offers.
break;
}
if(IM_INVENTORY_OFFERED == mIM)
{
// add buddy to recent people list
LLRecentPeople::instance().add(mFromID);
}
if(opener)
{
gInventory.addObserver(opener);
@ -1388,7 +1383,25 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task)
{
p.name = "UserGiveItem";
}
// Prefetch the item into your local inventory.
LLInventoryFetchObserver::item_ref_t items;
items.push_back(info->mObjectID);
LLInventoryFetchObserver* fetch_item = new LLInventoryFetchObserver();
fetch_item->fetchItems(items);
if(fetch_item->isEverythingComplete())
{
fetch_item->done();
}
else
{
gInventory.addObserver(fetch_item);
}
// In viewer 2 we're now auto receiving inventory offers and messaging as such (not sending reject messages).
info->send_auto_receive_response();
// Pop up inv offer notification and let the user accept (keep), or reject (and silently delete) the inventory.
LLNotifications::instance().add(p);
}

View File

@ -59,7 +59,8 @@ enum InventoryOfferResponse
IOR_ACCEPT,
IOR_DECLINE,
IOR_MUTE,
IOR_BUSY
IOR_BUSY,
IOR_SHOW
};
BOOL can_afford_transaction(S32 cost);
@ -197,6 +198,7 @@ void invalid_message_callback(LLMessageSystem*, void*, EMessageException);
void process_initiate_download(LLMessageSystem* msg, void**);
void start_new_inventory_observer();
void open_inventory_offer(const std::vector<LLUUID>& items, const std::string& from_name);
struct LLOfferInfo
{
@ -218,6 +220,7 @@ struct LLOfferInfo
LLHost mHost;
LLSD asLLSD();
void send_auto_receive_response(void);
bool inventory_offer_callback(const LLSD& notification, const LLSD& response);
};

View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<context_menu
layout="topleft"
name="Url Popup">
<menu_item_call
label="Show Inventory Item"
layout="topleft"
name="show_item">
<menu_item_call.on_click
function="Url.Execute" />
</menu_item_call>
<menu_item_separator
layout="topleft" />
<menu_item_call
label="Copy Name to clipboard"
layout="topleft"
name="url_copy_label">
<menu_item_call.on_click
function="Url.CopyLabel" />
</menu_item_call>
<menu_item_call
label="Copy SLurl to clipboard"
layout="topleft"
name="url_copy">
<menu_item_call.on_click
function="Url.CopyUrl" />
</menu_item_call>
</context_menu>

View File

@ -4494,7 +4494,7 @@ You don&apos;t have permission to copy this.
icon="notifytip.tga"
name="InventoryAccepted"
type="notifytip">
[NAME] accepted your inventory offer.
[NAME] received your inventory offer.
</notification>
<notification
@ -4966,17 +4966,21 @@ No valid parcel could be found.
icon="notify.tga"
name="ObjectGiveItem"
type="offer">
An object named [OBJECTFROMNAME] owned by [NAME_SLURL] has offered you [OBJECTTYPE]:
An object named [OBJECTFROMNAME] owned by [NAME_SLURL] has given you [OBJECTTYPE]:
[ITEM_SLURL]
<form name="form">
<button
index="0"
name="Keep"
text="OK"/>
text="Keep"/>
<button
index="4"
name="Show"
text="Show"/>
<button
index="1"
name="Discard"
text="Cancel"/>
text="Discard"/>
<button
index="2"
name="Mute"
@ -4988,17 +4992,21 @@ An object named [OBJECTFROMNAME] owned by [NAME_SLURL] has offered you [OBJECTTY
icon="notify.tga"
name="ObjectGiveItemUnknownUser"
type="offer">
An object named [OBJECTFROMNAME] owned by (an unknown Resident) has offered you [OBJECTTYPE]:
An object named [OBJECTFROMNAME] owned by (an unknown Resident) has given you [OBJECTTYPE]:
[ITEM_SLURL]
<form name="form">
<button
index="0"
name="Keep"
text="OK"/>
text="Keep"/>
<button
index="4"
name="Show"
text="Show"/>
<button
index="1"
name="Discard"
text="Cancel"/>
text="Discard"/>
<button
index="2"
name="Mute"
@ -5010,17 +5018,21 @@ An object named [OBJECTFROMNAME] owned by (an unknown Resident) has offered you
icon="notify.tga"
name="UserGiveItem"
type="offer">
[NAME_SLURL] has offered you [OBJECTTYPE]:
[NAME_SLURL] has given you [OBJECTTYPE]:
[ITEM_SLURL]
<form name="form">
<button
index="0"
name="Keep"
text="Accept"/>
text="Keep"/>
<button
index="4"
name="Show"
text="Show"/>
<button
index="1"
name="Discard"
text="No, thanks"/>
text="Discard"/>
</form>
</notification>