From e98792209e632a231025d4ed5847782444cf10f8 Mon Sep 17 00:00:00 2001 From: Inusaito Sayori Date: Fri, 17 Oct 2014 00:33:33 -0400 Subject: [PATCH] Issue 1151: Add share to LLAvatarActions Syncs LLGiveInventory and LLFloaterAvatarPicker with upstream. Syncsyncsync~ Translators: menu_inventory.xml menu_radar.xml and menu_avs_list.xml: Share notifications.xml: ShareNotification, ShareItemsConfirmation, ShareFolderConfirmation, ItemsShared strings.xml: share_alert --- indra/llmessage/aihttptimeoutpolicy.cpp | 1 - indra/newview/CMakeLists.txt | 1 + indra/newview/app_settings/settings.xml | 33 ++ indra/newview/llavataractions.cpp | 393 +++++++++++++++++- indra/newview/llavataractions.h | 28 ++ indra/newview/llfloateravatarpicker.cpp | 196 ++++++--- indra/newview/llfloateravatarpicker.h | 14 +- indra/newview/llfoldervieweventlistener.h | 2 +- indra/newview/llgiveinventory.cpp | 56 ++- indra/newview/llgiveinventory.h | 8 +- indra/newview/llinventoryactions.cpp | 12 + indra/newview/llinventorybridge.cpp | 100 ++++- indra/newview/llinventorybridge.h | 33 +- indra/newview/llpanelobjectinventory.cpp | 6 +- indra/newview/llshareavatarhandler.cpp | 67 +++ indra/newview/llviewermenu.cpp | 33 +- .../skins/default/xui/en-us/menu_avs_list.xml | 4 + .../default/xui/en-us/menu_inventory.xml | 8 + .../skins/default/xui/en-us/menu_radar.xml | 4 + .../skins/default/xui/en-us/notifications.xml | 71 +++- .../skins/default/xui/en-us/strings.xml | 3 + 21 files changed, 937 insertions(+), 136 deletions(-) create mode 100644 indra/newview/llshareavatarhandler.cpp diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp index 2b0b8af6b..fbd143c30 100644 --- a/indra/llmessage/aihttptimeoutpolicy.cpp +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -906,7 +906,6 @@ AIHTTPTimeoutPolicy const* AIHTTPTimeoutPolicy::getTimeoutPolicyByName(std::stri // Policy name Policy P(assetReportHandler); -P(avatarPickerResponder); P(authHandler); P(avatarNameResponder); P2(baseCapabilitiesComplete, transfer_18s_connect_5s); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index cbe0737ae..ea87148b5 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -444,6 +444,7 @@ set(viewer_SOURCE_FILES llscrollingpanelparam.cpp llscrollingpanelparambase.cpp llselectmgr.cpp + llshareavatarhandler.cpp llsky.cpp llslurl.cpp llspatialpartition.cpp diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index dfc036096..633294259 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -5084,6 +5084,39 @@ This should be as low as possible, but too low may break functionality Value 0 + ContextConeInAlpha + + Comment + Cone In Alpha + Persist + 0 + Type + F32 + Value + 0.0 + + ContextConeOutAlpha + + Comment + Cone Out Alpha + Persist + 0 + Type + F32 + Value + 1.0 + + ContextConeFadeTime + + Comment + Cone Fade Time + Persist + 0 + Type + F32 + Value + .08 + CookiesEnabled Comment diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index 2af9ee120..1282ba0cc 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -37,20 +37,26 @@ #include "llagent.h" #include "llcallingcard.h" // for LLAvatarTracker #include "llfloateravatarinfo.h" +#include "llfloateravatarpicker.h" // for LLFloaterAvatarPicker +#include "llfloaterchatterbox.h" #include "llfloatergroupbulkban.h" #include "llfloatergroupinvite.h" #include "llfloatergroups.h" #include "llfloaterwebprofile.h" #include "llfloaterworldmap.h" +#include "llgiveinventory.h" #include "llgivemoney.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llinventorypanel.h" #include "llimview.h" // for gIMMgr -#include "llinventoryobserver.h" #include "llmutelist.h" #include "llpanelprofile.h" #include "lltrans.h" #include "llvoiceclient.h" #include "llweb.h" #include "llslurl.h" // IDEVO +#include "llpanelmaininventory.h" #include "llavatarname.h" #include "llagentui.h" // [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0) @@ -569,7 +575,262 @@ void LLAvatarActions::csr(const LLUUID& id) LLWeb::loadURL(url); } -// Singu TODO: Share inventory code block should live here +//static +void LLAvatarActions::share(const LLUUID& id) +{ + /* + LLSD key; + LLFloaterSidePanelContainer::showPanel("inventory", key); + LLFloaterReg::showInstance("im_container"); + */ + LLInventoryView::getActiveInventory()->setVisible(true); + + LLUUID session_id = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL, id); + + if (!gIMMgr->hasSession(session_id)) + { + startIM(id); + } + + if (gIMMgr->hasSession(session_id)) + { + // we should always get here, but check to verify anyways + LLIMMgr::getInstance()->addMessage(session_id, LLUUID::null, SYSTEM_FROM, LLTrans::getString("share_alert")); + LLFloaterChatterBox::showInstance(session_id); + } +} + +namespace action_give_inventory +{ + /** + * Returns a pointer to 'Add More' inventory panel of Edit Outfit SP. + * + static LLInventoryPanel* get_outfit_editor_inventory_panel() + { + LLPanelOutfitEdit* panel_outfit_edit = dynamic_cast(LLFloaterSidePanelContainer::getPanel("appearance", "panel_outfit_edit")); + if (NULL == panel_outfit_edit) return NULL; + + LLInventoryPanel* inventory_panel = panel_outfit_edit->findChild("folder_view"); + return inventory_panel; + }*/ + + /** + * @return active inventory panel, or NULL if there's no such panel + */ + static LLInventoryPanel* get_active_inventory_panel() + { + LLInventoryPanel* active_panel = LLInventoryPanel::getActiveInventoryPanel(FALSE); + /*if (!active_panel) + { + active_panel = get_outfit_editor_inventory_panel(); + }*/ + + return active_panel; + } + + /** + * Checks My Inventory visibility. + */ + + static bool is_give_inventory_acceptable() + { + // check selection in the panel + const std::set inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(); + if (inventory_selected_uuids.empty()) return false; // nothing selected + + bool acceptable = false; + std::set::const_iterator it = inventory_selected_uuids.begin(); + const std::set::const_iterator it_end = inventory_selected_uuids.end(); + for (; it != it_end; ++it) + { + LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it); + // any category can be offered. + if (inv_cat) + { + acceptable = true; + continue; + } + + LLViewerInventoryItem* inv_item = gInventory.getItem(*it); + // check if inventory item can be given + if (LLGiveInventory::isInventoryGiveAcceptable(inv_item)) + { + acceptable = true; + continue; + } + + // there are neither item nor category in inventory + acceptable = false; + break; + } + return acceptable; + } + + static void build_items_string(const std::set& inventory_selected_uuids , std::string& items_string) + { + llassert(inventory_selected_uuids.size() > 0); + + const std::string& separator = LLTrans::getString("words_separator"); + for (std::set::const_iterator it = inventory_selected_uuids.begin(); ; ) + { + LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it); + if (NULL != inv_cat) + { + items_string = inv_cat->getName(); + break; + } + LLViewerInventoryItem* inv_item = gInventory.getItem(*it); + if (NULL != inv_item) + { + items_string.append(inv_item->getName()); + } + if(++it == inventory_selected_uuids.end()) + { + break; + } + items_string.append(separator); + } + } + + struct LLShareInfo : public LLSingleton + { + std::vector mAvatarNames; + uuid_vec_t mAvatarUuids; + }; + + static void give_inventory_cb(const LLSD& notification, const LLSD& response) + { + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + // if Cancel pressed + if (option == 1) + { + return; + } + + const std::set inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(); + if (inventory_selected_uuids.empty()) + { + return; + } + + S32 count = LLShareInfo::instance().mAvatarNames.size(); + bool shared = count && !inventory_selected_uuids.empty(); + + // iterate through avatars + for(S32 i = 0; i < count; ++i) + { + const LLUUID& avatar_uuid = LLShareInfo::instance().mAvatarUuids[i]; + + // We souldn't open IM session, just calculate session ID for logging purpose. See EXT-6710 + const LLUUID session_id = gIMMgr->computeSessionID(IM_NOTHING_SPECIAL, avatar_uuid); + + std::set::const_iterator it = inventory_selected_uuids.begin(); + const std::set::const_iterator it_end = inventory_selected_uuids.end(); + + const std::string& separator = LLTrans::getString("words_separator"); + std::string noncopy_item_names; + LLSD noncopy_items = LLSD::emptyArray(); + // iterate through selected inventory objects + for (; it != it_end; ++it) + { + LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it); + if (inv_cat) + { + if (!LLGiveInventory::doGiveInventoryCategory(avatar_uuid, inv_cat, session_id, "ItemsShared")) + { + shared = false; + } + break; + } + LLViewerInventoryItem* inv_item = gInventory.getItem(*it); + if (!inv_item->getPermissions().allowCopyBy(gAgentID)) + { + if (!noncopy_item_names.empty()) + { + noncopy_item_names.append(separator); + } + noncopy_item_names.append(inv_item->getName()); + noncopy_items.append(*it); + } + else + { + if (!LLGiveInventory::doGiveInventoryItem(avatar_uuid, inv_item, session_id)) + { + shared = false; + } + } + } + if (noncopy_items.beginArray() != noncopy_items.endArray()) + { + LLSD substitutions; + substitutions["ITEMS"] = noncopy_item_names; + LLSD payload; + payload["agent_id"] = avatar_uuid; + payload["items"] = noncopy_items; + payload["success_notification"] = "ItemsShared"; + LLNotificationsUtil::add("CannotCopyWarning", substitutions, payload, + &LLGiveInventory::handleCopyProtectedItem); + shared = false; + break; + } + } + if (shared) + { + if (LLFloaterAvatarPicker::instanceExists()) LLFloaterAvatarPicker::instance().close(); + LLNotificationsUtil::add("ItemsShared"); + } + } + + /** + * Performs "give inventory" operations for provided avatars. + * + * Sends one requests to give all selected inventory items for each passed avatar. + * Avatars are represent by two vectors: names and UUIDs which must be sychronized with each other. + * + * @param avatar_names - avatar names request to be sent. + * @param avatar_uuids - avatar names request to be sent. + */ + static void give_inventory(const uuid_vec_t& avatar_uuids, const std::vector avatar_names) + { + llassert(avatar_names.size() == avatar_uuids.size()); + + const std::set inventory_selected_uuids = LLAvatarActions::getInventorySelectedUUIDs(); + if (inventory_selected_uuids.empty()) + { + return; + } + + std::string residents; + LLAvatarActions::buildResidentsString(avatar_names, residents); + + std::string items; + build_items_string(inventory_selected_uuids, items); + + int folders_count = 0; + std::set::const_iterator it = inventory_selected_uuids.begin(); + + //traverse through selected inventory items and count folders among them + for ( ; it != inventory_selected_uuids.end() && folders_count <=1 ; ++it) + { + LLViewerInventoryCategory* inv_cat = gInventory.getCategory(*it); + if (NULL != inv_cat) + { + folders_count++; + } + } + + // EXP-1599 + // In case of sharing multiple folders, make the confirmation + // dialog contain a warning that only one folder can be shared at a time. + std::string notification = (folders_count > 1) ? "ShareFolderConfirmation" : "ShareItemsConfirmation"; + LLSD substitutions; + substitutions["RESIDENTS"] = residents; + substitutions["ITEMS"] = items; + LLShareInfo::instance().mAvatarNames = avatar_names; + LLShareInfo::instance().mAvatarUuids = avatar_uuids; + LLNotificationsUtil::add(notification, substitutions, LLSD(), &give_inventory_cb); + } +} // static void LLAvatarActions::buildResidentsString(std::vector avatar_names, std::string& residents_string) @@ -611,7 +872,118 @@ void LLAvatarActions::buildResidentsString(const uuid_vec_t& avatar_uuids, std:: } } -// Singu TODO: Share inventory code block should live here, too +//static +std::set LLAvatarActions::getInventorySelectedUUIDs() +{ + LLInventoryPanel* active_panel = action_give_inventory::get_active_inventory_panel(); + return active_panel ? active_panel->getRootFolder()->getSelectionList() : std::set(); + /*std::set inventory_selected; + + LLInventoryPanel* active_panel = action_give_inventory::get_active_inventory_panel(); + if (active_panel) + { + inventory_selected= active_panel->getRootFolder()->getSelectionList(); + } + + if (inventory_selected.empty()) + { + LLSidepanelInventory *sidepanel_inventory = LLFloaterSidePanelContainer::getPanel("inventory"); + if (sidepanel_inventory) + { + inventory_selected= sidepanel_inventory->getInboxSelectionList(); + } + } + + std::set inventory_selected_uuids; + for (std::set::iterator it = inventory_selected.begin(), end_it = inventory_selected.end(); + it != end_it; + ++it) + { + inventory_selected_uuids.insert(static_cast((*it)->getViewModelItem())->getUUID()); + } + return inventory_selected_uuids;*/ +} + +//static +void LLAvatarActions::shareWithAvatars(LLView * panel) +{ + using namespace action_give_inventory; + + LLFloater* root_floater = gFloaterView->getParentFloater(panel); + LLFloaterAvatarPicker* picker = + LLFloaterAvatarPicker::show(boost::bind(give_inventory, _1, _2), TRUE, FALSE, FALSE, root_floater->getName()); + if (!picker) + { + return; + } + + picker->setOkBtnEnableCb(boost::bind(is_give_inventory_acceptable)); + picker->openFriendsTab(); + + if (root_floater) + { + root_floater->addDependentFloater(picker); + } + LLNotificationsUtil::add("ShareNotification"); +} + + +// static +bool LLAvatarActions::canShareSelectedItems(LLInventoryPanel* inv_panel /* = NULL*/) +{ + using namespace action_give_inventory; + + if (!inv_panel) + { + LLInventoryPanel* active_panel = get_active_inventory_panel(); + if (!active_panel) return false; + inv_panel = active_panel; + } + + // check selection in the panel + LLFolderView* root_folder = inv_panel->getRootFolder(); + if (!root_folder) + { + return false; + } + const std::set inventory_selected = root_folder->getSelectionList(); + if (inventory_selected.empty()) return false; // nothing selected + + bool can_share = true; + const LLUUID& trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH); // + std::set::const_iterator it = inventory_selected.begin(); + const std::set::const_iterator it_end = inventory_selected.end(); + for (; it != it_end; ++it) + { + const LLUUID id(*it); + LLViewerInventoryCategory* inv_cat = gInventory.getCategory(id); + // any category can be offered. + if (inv_cat && !gInventory.isObjectDescendentOf(inv_cat->getUUID(), trash_id)) // + { + continue; + } + + // check if inventory item can be given + else if (!inv_cat && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID())) // Singu Note: These three ifs comprise the item half of LLInvFVBridge::canShare, which LL calls here. + if (LLViewerInventoryItem* item = gInventory.getItem(id)) + if (LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item) && LLGiveInventory::isInventoryGiveAcceptable(item)) + /* + LLFolderViewItem* item = *it; + if (!item) return false; + LLInvFVBridge* bridge = dynamic_cast(item->getViewModelItem()); + if (bridge && bridge->canShare()) + */ + { + continue; + } + + // there are neither item nor category in inventory + can_share = false; + break; + } + + return can_share; +} // static void LLAvatarActions::toggleBlock(const LLUUID& id) @@ -898,6 +1270,21 @@ bool LLAvatarActions::canBlock(const LLUUID& id) return !is_self && !is_linden; } +//static +bool LLAvatarActions::isAgentMappable(const LLUUID& agent_id) +{ + const LLRelationship* buddy_info = NULL; + bool is_friend = LLAvatarActions::isFriend(agent_id); + + if (is_friend) + buddy_info = LLAvatarTracker::instance().getBuddyInfo(agent_id); + + return (buddy_info && + buddy_info->isOnline() && + buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION) + ); +} + // static void LLAvatarActions::copyUUIDs(const uuid_vec_t& ids) { diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h index 5488c34c2..57e1ddd17 100644 --- a/indra/newview/llavataractions.h +++ b/indra/newview/llavataractions.h @@ -28,7 +28,9 @@ #define LL_LLAVATARACTIONS_H class LLAvatarName; +class LLInventoryPanel; class LLFloater; +class LLView; /** * Friend-related actions (add, remove, offer teleport, etc) @@ -108,6 +110,16 @@ public: static void teleportRequest(const LLUUID& id); static void teleport_request_callback(const LLSD& notification, const LLSD& response); + /** + * Share items with the avatar. + */ + static void share(const LLUUID& id); + + /** + * Share items with the picked avatars. + */ + static void shareWithAvatars(LLView * panel); + /** * Block/unblock the avatar. */ @@ -190,6 +202,20 @@ public: */ static bool canOfferTeleport(const uuid_vec_t& ids); + /** + * Checks whether all items selected in the given inventory panel can be shared + * + * @param inv_panel Inventory panel to get selection from. If NULL, the active inventory panel is used. + * + * @return false if the selected items cannot be shared or the active inventory panel cannot be obtained + */ + static bool canShareSelectedItems(LLInventoryPanel* inv_panel = NULL); + + /** + * Checks whether agent is mappable + */ + static bool isAgentMappable(const LLUUID& agent_id); + /** * Builds a string of residents' display names separated by "words_separator" string. * @@ -206,6 +232,8 @@ public: */ static void buildResidentsString(const uuid_vec_t& avatar_uuids, std::string& residents_string); + static std::set getInventorySelectedUUIDs(); + /** * Copy the selected avatar's UUID to clipboard */ diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 7bc196997..a7c97f02f 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -50,6 +50,7 @@ #include "llscrolllistitem.h" #include "lltabcontainer.h" #include "lluictrlfactory.h" +#include "lldraghandle.h" #include "message.h" @@ -58,17 +59,21 @@ static std::map sAvatarNameMap; LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(select_callback_t callback, BOOL allow_multiple, - BOOL closeOnSelect) + BOOL closeOnSelect, + BOOL skip_agent, + const std::string& name, + LLView * frustumOrigin) { // *TODO: Use a key to allow this not to be an effective singleton - - LLFloaterAvatarPicker* floater = getInstance(); + LLFloaterAvatarPicker* floater = + getInstance(); floater->open(); floater->mSelectionCallback = callback; floater->setAllowMultiple(allow_multiple); floater->mNearMeListComplete = FALSE; floater->mCloseOnSelect = closeOnSelect; + floater->mExcludeAgentFromSearchResults = skip_agent; if (!closeOnSelect) { @@ -79,6 +84,11 @@ LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(select_callback_t callback, floater->getChild("cancel_btn")->setLabel(close_string); } + if(frustumOrigin) + { + floater->mFrustumOrigin = frustumOrigin->getHandle(); + } + return floater; } @@ -87,10 +97,18 @@ LLFloaterAvatarPicker::LLFloaterAvatarPicker() : LLFloater(), mNumResultsReturned(0), mNearMeListComplete(FALSE), - mCloseOnSelect(FALSE) + mCloseOnSelect(FALSE), + mContextConeOpacity (0.f), + mContextConeInAlpha(0.f), + mContextConeOutAlpha(0.f), + mContextConeFadeTime(0.f) { mCommitCallbackRegistrar.add("Refresh.FriendList", boost::bind(&LLFloaterAvatarPicker::populateFriend, this)); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_avatar_picker.xml", NULL); + + mContextConeInAlpha = gSavedSettings.getF32("ContextConeInAlpha"); + mContextConeOutAlpha = gSavedSettings.getF32("ContextConeOutAlpha"); + mContextConeFadeTime = gSavedSettings.getF32("ContextConeFadeTime"); } BOOL LLFloaterAvatarPicker::postBuild() @@ -188,11 +206,10 @@ static void addAvatarUUID(const LLUUID av_id, uuid_vec_t& avatar_ids, std::vecto static void getSelectedAvatarData(const LLUICtrl* from, uuid_vec_t& avatar_ids, std::vector& avatar_names) { - const LLScrollListCtrl* list = dynamic_cast(from); - if(list) + if(const LLScrollListCtrl* list = dynamic_cast(from)) { - std::vector items = list->getAllSelected(); - for (std::vector::iterator iter = items.begin(); iter != items.end(); ++iter) + const std::vector items = list->getAllSelected(); + for (std::vector::const_iterator iter = items.begin(); iter != items.end(); ++iter) { addAvatarUUID((*iter)->getUUID(), avatar_ids, avatar_names); } @@ -366,8 +383,67 @@ void LLFloaterAvatarPicker::populateFriend() friends_scroller->sortByColumnIndex(0, TRUE); } +void LLFloaterAvatarPicker::drawFrustum() +{ + if (mFrustumOrigin.get()) + { + LLView * frustumOrigin = mFrustumOrigin.get(); + LLRect origin_rect; + frustumOrigin->localRectToOtherView(frustumOrigin->getLocalRect(), &origin_rect, this); + // draw context cone connecting color picker with color swatch in parent floater + LLRect local_rect = getLocalRect(); + if (hasFocus() && frustumOrigin->isInVisibleChain() && mContextConeOpacity > 0.001f) + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLGLEnable(GL_CULL_FACE); + gGL.begin(LLRender::QUADS); + { + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); + gGL.vertex2i(origin_rect.mRight, origin_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mRight, local_rect.mTop); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mTop); + gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom); + gGL.vertex2i(origin_rect.mLeft, origin_rect.mTop); + + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mRight, local_rect.mBottom); + gGL.vertex2i(local_rect.mRight, local_rect.mTop); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mRight, origin_rect.mTop); + gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom); + + gGL.color4f(0.f, 0.f, 0.f, mContextConeOutAlpha * mContextConeOpacity); + gGL.vertex2i(local_rect.mLeft, local_rect.mBottom); + gGL.vertex2i(local_rect.mRight, local_rect.mBottom); + gGL.color4f(0.f, 0.f, 0.f, mContextConeInAlpha * mContextConeOpacity); + gGL.vertex2i(origin_rect.mRight, origin_rect.mBottom); + gGL.vertex2i(origin_rect.mLeft, origin_rect.mBottom); + } + gGL.end(); + } + + if (gFocusMgr.childHasMouseCapture(getDragHandle())) + { + mContextConeOpacity = lerp(mContextConeOpacity, gSavedSettings.getF32("PickerContextOpacity"), LLCriticalDamp::getInterpolant(mContextConeFadeTime)); + } + else + { + mContextConeOpacity = lerp(mContextConeOpacity, 0.f, LLCriticalDamp::getInterpolant(mContextConeFadeTime)); + } + } +} + void LLFloaterAvatarPicker::draw() { + drawFrustum(); + // sometimes it is hard to determine when Select/Ok button should be disabled (see LLAvatarActions::shareWithAvatars). // lets check this via mOkButtonValidateSignal callback periodically. static LLFrameTimer timer; @@ -411,19 +487,20 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const return FALSE; } -extern AIHTTPTimeoutPolicy avatarPickerResponder_timeout; class LLAvatarPickerResponder : public LLHTTPClient::ResponderWithCompleted { + LOG_CLASS(LLAvatarPickerResponder); public: LLUUID mQueryID; LLAvatarPickerResponder(const LLUUID& id) : mQueryID(id) { } - /*virtual*/ void httpCompleted(void) +protected: + /*virtual*/ void httpCompleted() { //std::ostringstream ss; - //LLSDSerialize::toPrettyXML(mContent, ss); - //llinfos << ss.str() << llendl; + //LLSDSerialize::toPrettyXML(content, ss); + //LL_INFOS() << ss.str() << LL_ENDL; // in case of invalid characters, the avatar picker returns a 400 // just set it to process so it displays 'not found' @@ -436,12 +513,11 @@ public: } else { - llwarns << "avatar picker failed " << mStatus << " reason " << mReason << llendl; + llwarns << "avatar picker failed " << dumpResponse() << LL_ENDL; } } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return avatarPickerResponder_timeout; } /*virtual*/ char const* getName(void) const { return "LLAvatarPickerResponder"; } }; @@ -460,9 +536,7 @@ void LLFloaterAvatarPicker::find() LLViewerRegion* region = gAgent.getRegion(); url = region->getCapability("AvatarPickerSearch"); // Prefer use of capabilities to search on both SLID and display name - // but allow display name search to be manually turned off for test - if (!url.empty() - && LLAvatarNameCache::useDisplayNames()) + if (!url.empty()) { // capability urls don't end in '/', but we need one to parse // query parameters correctly @@ -471,6 +545,7 @@ void LLFloaterAvatarPicker::find() url += "/"; } url += "?page_size=100&names="; + std::replace(text.begin(), text.end(), '.', ' '); url += LLURI::escape(text); llinfos << "avatar picker " << url << llendl; LLHTTPClient::get(url, new LLAvatarPickerResponder(mQueryID)); @@ -595,8 +670,7 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void* // Not for us if (agent_id != gAgent.getID()) return; - if(!instanceExists()) - return; + if (!instanceExists()) return; LLFloaterAvatarPicker* floater = getInstance(); // floater is closed or these are not results from our last request @@ -620,35 +694,38 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void* msg->getUUIDFast( _PREHASH_Data,_PREHASH_AvatarID, avatar_id, i); msg->getStringFast(_PREHASH_Data,_PREHASH_FirstName, first_name, i); msg->getStringFast(_PREHASH_Data,_PREHASH_LastName, last_name, i); - - std::string avatar_name; - if (avatar_id.isNull()) - { - LLStringUtil::format_map_t map; - map["[TEXT]"] = floater->getChild("Edit")->getValue().asString(); - avatar_name = floater->getString("not_found", map); - search_results->setEnabled(FALSE); - floater->getChildView("ok_btn")->setEnabled(FALSE); - } - else - { - avatar_name = LLCacheName::buildFullName(first_name, last_name); - search_results->setEnabled(TRUE); - found_one = TRUE; - LLAvatarName av_name; - av_name.mLegacyFirstName = first_name; - av_name.mLegacyLastName = last_name; - av_name.mDisplayName = avatar_name; - const LLUUID& agent_id = avatar_id; - sAvatarNameMap[agent_id] = av_name; + if (avatar_id != agent_id || !floater->isExcludeAgentFromSearchResults()) // exclude agent from search results? + { + std::string avatar_name; + if (avatar_id.isNull()) + { + LLStringUtil::format_map_t map; + map["[TEXT]"] = floater->getChild("Edit")->getValue().asString(); + avatar_name = floater->getString("not_found", map); + search_results->setEnabled(FALSE); + floater->getChildView("ok_btn")->setEnabled(FALSE); + } + else + { + avatar_name = LLCacheName::buildFullName(first_name, last_name); + search_results->setEnabled(TRUE); + found_one = TRUE; + LLAvatarName av_name; + av_name.mLegacyFirstName = first_name; + av_name.mLegacyLastName = last_name; + av_name.mDisplayName = avatar_name; + const LLUUID& agent_id = avatar_id; + sAvatarNameMap[agent_id] = av_name; + + } + LLSD element; + element["id"] = avatar_id; // value + element["columns"][0]["column"] = "name"; + element["columns"][0]["value"] = avatar_name; + search_results->addElement(element); } - LLSD element; - element["id"] = avatar_id; // value - element["columns"][0]["column"] = "name"; - element["columns"][0]["value"] = avatar_name; - search_results->addElement(element); } if (found_one) @@ -690,18 +767,21 @@ void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD& for ( ; it != agents.endArray(); ++it) { const LLSD& row = *it; - item["id"] = row["id"]; - LLSD& columns = item["columns"]; - columns[0]["column"] = "name"; - columns[0]["value"] = row["display_name"]; - columns[1]["column"] = "username"; - columns[1]["value"] = row["username"]; - search_results->addElement(item); + if (row["id"].asUUID() != gAgent.getID() || !mExcludeAgentFromSearchResults) + { + item["id"] = row["id"]; + LLSD& columns = item["columns"]; + columns[0]["column"] = "name"; + columns[0]["value"] = row["display_name"]; + columns[1]["column"] = "username"; + columns[1]["value"] = row["username"]; + search_results->addElement(item); - // add the avatar name to our list - LLAvatarName avatar_name; - avatar_name.fromLLSD(row); - sAvatarNameMap[row["id"].asUUID()] = avatar_name; + // add the avatar name to our list + LLAvatarName avatar_name; + avatar_name.fromLLSD(row); + sAvatarNameMap[row["id"].asUUID()] = avatar_name; + } } getChildView("ok_btn")->setEnabled(true); @@ -713,10 +793,10 @@ void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD& void LLFloaterAvatarPicker::editKeystroke(LLLineEditor* caller) { - if(caller->getName() == "Edit") + if (caller->getName() == "Edit") getChildView("Find")->setEnabled(caller->getText().size() >= 3); else - childSetEnabled("Select", caller->getValue().asUUID().notNull()); + getChildView("Select")->setEnabled(caller->getValue().asUUID().notNull()); } // virtual diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h index 799d28790..f4fcc91f4 100644 --- a/indra/newview/llfloateravatarpicker.h +++ b/indra/newview/llfloateravatarpicker.h @@ -45,11 +45,15 @@ public: // Call this to select an avatar. static LLFloaterAvatarPicker* show(select_callback_t callback, BOOL allow_multiple = FALSE, - BOOL closeOnSelect = FALSE); + BOOL closeOnSelect = FALSE, + BOOL skip_agent = FALSE, + const std::string& name = "", + LLView * frustumOrigin = NULL); // do not call these directly LLFloaterAvatarPicker(); virtual ~LLFloaterAvatarPicker(); + virtual BOOL postBuild(); void setOkBtnEnableCb(validate_callback_t cb); @@ -63,6 +67,7 @@ public: std::string& tooltip_msg); void openFriendsTab(); + BOOL isExcludeAgentFromSearchResults() { return mExcludeAgentFromSearchResults; } private: void editKeystroke(class LLLineEditor* caller); @@ -84,6 +89,7 @@ private: void setAllowMultiple(BOOL allow_multiple); LLScrollListCtrl* getActiveList(); + void drawFrustum(); virtual void draw(); virtual BOOL handleKeyHere(KEY key, MASK mask); @@ -91,6 +97,12 @@ private: int mNumResultsReturned; BOOL mNearMeListComplete; BOOL mCloseOnSelect; + BOOL mExcludeAgentFromSearchResults; + LLHandle mFrustumOrigin; + F32 mContextConeOpacity; + F32 mContextConeInAlpha; + F32 mContextConeOutAlpha; + F32 mContextConeFadeTime; validate_signal_t mOkButtonValidateSignal; select_callback_t mSelectionCallback; diff --git a/indra/newview/llfoldervieweventlistener.h b/indra/newview/llfoldervieweventlistener.h index 39e96424a..62c7a67ec 100644 --- a/indra/newview/llfoldervieweventlistener.h +++ b/indra/newview/llfoldervieweventlistener.h @@ -82,7 +82,7 @@ public: virtual void pasteLinkFromClipboard() = 0; virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0; virtual BOOL isUpToDate() const = 0; - virtual BOOL hasChildren() const = 0; + virtual bool hasChildren() const = 0; virtual LLInventoryType::EType getInventoryType() const = 0; virtual void performAction(LLInventoryModel* model, std::string action) = 0; virtual LLWearableType::EType getWearableType() const = 0; diff --git a/indra/newview/llgiveinventory.cpp b/indra/newview/llgiveinventory.cpp index 8cdcf5589..c5db73390 100644 --- a/indra/newview/llgiveinventory.cpp +++ b/indra/newview/llgiveinventory.cpp @@ -231,23 +231,25 @@ bool LLGiveInventory::doGiveInventoryItem(const LLUUID& to_agent, return res; } -void LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent, +bool LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent, const LLInventoryCategory* cat, - const LLUUID& im_session_id) + const LLUUID& im_session_id, + const std::string& notification_name) { if (!cat) { - return; + return false; } llinfos << "LLGiveInventory::giveInventoryCategory() - " << cat->getUUID() << llendl; if (!isAgentAvatarValid()) { - return; + return false; } + bool give_successful = true; // Test out how many items are being given. LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; @@ -270,24 +272,24 @@ void LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent, if(!complete) { LLNotificationsUtil::add("IncompleteInventory"); - return; + give_successful = false; } count = items.count() + cats.count(); if(count > MAX_ITEMS) { LLNotificationsUtil::add("TooManyItems"); - return; + give_successful = false; } else if(count == 0) { LLNotificationsUtil::add("NoItems"); - return; + give_successful = false; } - else + else if (give_successful) { if(0 == giveable.countNoCopy()) { - LLGiveInventory::commitGiveInventoryCategory(to_agent, cat, im_session_id); + give_successful = LLGiveInventory::commitGiveInventoryCategory(to_agent, cat, im_session_id); } else { @@ -296,9 +298,16 @@ void LLGiveInventory::doGiveInventoryCategory(const LLUUID& to_agent, LLSD payload; payload["agent_id"] = to_agent; payload["folder_id"] = cat->getUUID(); + if (!notification_name.empty()) + { + payload["success_notification"] = notification_name; + } LLNotificationsUtil::add("CannotCopyCountItems", args, payload, &LLGiveInventory::handleCopyProtectedCategory); + give_successful = false; } } + + return give_successful; } ////////////////////////////////////////////////////////////////////////// @@ -377,6 +386,10 @@ bool LLGiveInventory::handleCopyProtectedItem(const LLSD& notification, const LL give_successful = false; } } + if (give_successful && notification["payload"]["success_notification"].isDefined()) + { + LLNotificationsUtil::add(notification["payload"]["success_notification"].asString()); + } break; default: // no, cancel, whatever, who cares, not yes. @@ -445,13 +458,14 @@ bool LLGiveInventory::handleCopyProtectedCategory(const LLSD& notification, cons { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); LLInventoryCategory* cat = NULL; + bool give_successful = true; switch(option) { case 0: // "Yes" cat = gInventory.getCategory(notification["payload"]["folder_id"].asUUID()); if(cat) { - LLGiveInventory::commitGiveInventoryCategory(notification["payload"]["agent_id"].asUUID(), + give_successful = LLGiveInventory::commitGiveInventoryCategory(notification["payload"]["agent_id"].asUUID(), cat); LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; @@ -467,29 +481,36 @@ bool LLGiveInventory::handleCopyProtectedCategory(const LLSD& notification, cons gInventory.deleteObject(items.get(i)->getUUID()); } gInventory.notifyObservers(); + + if (give_successful && notification["payload"]["success_notification"].isDefined()) + { + LLNotificationsUtil::add(notification["payload"]["success_notification"].asString()); + } } else { LLNotificationsUtil::add("CannotGiveCategory"); + give_successful = false; } break; default: // no, cancel, whatever, who cares, not yes. LLNotificationsUtil::add("TransactionCancelled"); + give_successful = false; break; } - return false; + return give_successful; } // static -void LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent, +bool LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent, const LLInventoryCategory* cat, const LLUUID& im_session_id) { - if(!cat) + if (!cat) { - return; + return false; } llinfos << "LLGiveInventory::commitGiveInventoryCategory() - " << cat->getUUID() << llendl; @@ -504,6 +525,7 @@ void LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent, LLInventoryModel::EXCLUDE_TRASH, giveable); + bool give_successful = true; // MAX ITEMS is based on (sizeof(uuid)+2) * count must be < // MTUBYTES or 18 * count < 1200 => count < 1200/18 => // 66. I've cut it down a bit from there to give some pad. @@ -511,12 +533,12 @@ void LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent, if(count > MAX_ITEMS) { LLNotificationsUtil::add("TooManyItems"); - return; + give_successful = false; } else if(count == 0) { LLNotificationsUtil::add("NoItems"); - return; + give_successful = false; } else { @@ -589,6 +611,8 @@ void LLGiveInventory::commitGiveInventoryCategory(const LLUUID& to_agent, logInventoryOffer(to_agent, im_session_id); } + + return give_successful; } // EOF diff --git a/indra/newview/llgiveinventory.h b/indra/newview/llgiveinventory.h index 19dab82a5..85bc1ed49 100644 --- a/indra/newview/llgiveinventory.h +++ b/indra/newview/llgiveinventory.h @@ -62,9 +62,11 @@ public: /** * Gives passed inventory category to specified avatar in specified session. */ - static void doGiveInventoryCategory(const LLUUID& to_agent, + static bool doGiveInventoryCategory(const LLUUID& to_agent, const LLInventoryCategory* item, - const LLUUID &session_id = LLUUID::null); + const LLUUID &session_id = LLUUID::null, + const std::string& notification = std::string()); + // give inventory item functionality static bool handleCopyProtectedItem(const LLSD& notification, const LLSD& response); @@ -84,7 +86,7 @@ private: // give inventory category functionality static bool handleCopyProtectedCategory(const LLSD& notification, const LLSD& response); - static void commitGiveInventoryCategory(const LLUUID& to_agent, + static bool commitGiveInventoryCategory(const LLUUID& to_agent, const LLInventoryCategory* cat, const LLUUID &im_session_id = LLUUID::null); diff --git a/indra/newview/llinventoryactions.cpp b/indra/newview/llinventoryactions.cpp index 5e2729820..20fe180d7 100644 --- a/indra/newview/llinventoryactions.cpp +++ b/indra/newview/llinventoryactions.cpp @@ -34,6 +34,7 @@ #include "llagentwearables.h" #include "llappearancemgr.h" +#include "llavataractions.h" #include "llfloaterperms.h" #include "llfoldervieweventlistener.h" #include "llimview.h" @@ -627,6 +628,7 @@ void init_object_inventory_panel_actions(LLPanelObjectInventory *panel) void init_inventory_actions(LLInventoryView *floater) { + (new LLDoToSelectedFloater())->registerListener(floater, "Inventory.DoToSelected"); (new LLDoToSelectedFloater())->registerListener(floater, "Inventory.DoToSelected"); (new LLCloseAllFoldersFloater())->registerListener(floater, "Inventory.CloseAllFolders"); (new LLEmptyTrashFloater())->registerListener(floater, "Inventory.EmptyTrash"); @@ -640,6 +642,15 @@ void init_inventory_actions(LLInventoryView *floater) (new LLSetSearchType())->registerListener(floater, "Inventory.SetSearchType"); } +class LLShare : public inventory_panel_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + LLAvatarActions::shareWithAvatars(mPtr); + return true; + } +}; + void init_inventory_panel_actions(LLInventoryPanel *panel) { (new LLDoToSelected())->registerListener(panel, "Inventory.DoToSelected"); @@ -649,4 +660,5 @@ void init_inventory_panel_actions(LLInventoryPanel *panel) (new LLEmptyLostAndFound())->registerListener(panel, "Inventory.EmptyLostAndFound"); (new LLDoCreate())->registerListener(panel, "Inventory.DoCreate"); (new LLBeginIMSession())->registerListener(panel, "Inventory.BeginIMSession"); + (new LLShare())->registerListener(panel, "Inventory.Share"); } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 17927a225..368bb3284 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -804,6 +804,12 @@ void LLInvFVBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } + addOpenRightClickMenuOption(items); items.push_back(std::string("Properties")); @@ -1235,6 +1241,33 @@ void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) } } +bool LLInvFVBridge::canShare() const +{ + bool can_share = false; + + if (!isItemInTrash() && isAgentInventory()) + { + const LLInventoryModel* model = getInventoryModel(); + if (model) + { + const LLViewerInventoryItem *item = model->getItem(mUUID); + if (item) + { + if (LLInventoryCollectFunctor::itemTransferCommonlyAllowed(item)) + { + can_share = LLGiveInventory::isInventoryGiveAcceptable(item); + } + } + else + { + // Categories can be given. + can_share = (model->getCategory(mUUID) != NULL); + } + } + } + + return can_share; +} bool LLInvFVBridge::canListOnMarketplace() const { @@ -2613,8 +2646,17 @@ void LLRightClickInventoryFetchDescendentsObserver::execute(bool clear_observer) LLInventoryModel::item_array_t* item_array; gInventory.getDirectDescendentsOf(*current_folder, cat_array, item_array); - S32 item_count = item_array->count(); - S32 cat_count = cat_array->count(); + S32 item_count(0); + if (item_array) + { + item_count = item_array->count(); + } + + S32 cat_count(0); + if (cat_array) + { + cat_count = cat_array->count(); + } // Move to next if current folder empty if ((item_count == 0) && (cat_count == 0)) @@ -3387,6 +3429,15 @@ void LLFolderBridge::buildContextMenuBaseOptions(U32 flags) { mDisabledItems.push_back(std::string("Delete System Folder")); } + + if (!isOutboxFolder() && !isItemInTrash()) // + { + mItems.push_back(std::string("Share")); + if (!canShare()) + { + mDisabledItems.push_back(std::string("Share")); + } + } } void LLFolderBridge::buildContextMenuFolderOptions(U32 flags) @@ -3528,7 +3579,7 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) menu.arrangeAndClear(); } -BOOL LLFolderBridge::hasChildren() const +bool LLFolderBridge::hasChildren() const { LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; @@ -4321,6 +4372,12 @@ void LLTextureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } + addOpenRightClickMenuOption(items); items.push_back(std::string("Properties")); @@ -4412,6 +4469,11 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } items.push_back(std::string("Sound Open")); items.push_back(std::string("Properties")); @@ -4465,6 +4527,11 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } items.push_back(std::string("Landmark Open")); items.push_back(std::string("Properties")); @@ -4734,6 +4801,11 @@ void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } /* Singu Note: Multiple profiles get opened in a multifloater if ((flags & FIRST_SELECTED_ITEM) == 0) { @@ -5039,6 +5111,11 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } addOpenRightClickMenuOption(items); items.push_back(std::string("Properties")); @@ -5094,6 +5171,11 @@ void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } items.push_back(std::string("Animation Open")); items.push_back(std::string("Properties")); @@ -5411,6 +5493,12 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } + items.push_back(std::string("Properties")); getClipboardEntries(true, items, disabled_items, flags); @@ -5819,6 +5907,12 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { can_open = FALSE; } + items.push_back(std::string("Share")); + if (!canShare()) + { + disabled_items.push_back(std::string("Share")); + } + if (can_open) { addOpenRightClickMenuOption(items); diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 5fa3641a7..d5d604cd8 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -69,6 +69,7 @@ public: U32 flags = 0x00); virtual ~LLInvFVBridge() {} + bool canShare() const; bool canListOnMarketplace() const; bool canListOnMarketplaceNow() const; @@ -121,6 +122,8 @@ public: void* cargo_data) { return FALSE; } virtual LLInventoryType::EType getInventoryType() const { return mInvType; } virtual LLWearableType::EType getWearableType() const { return LLWearableType::WT_NONE; } + virtual LLInventoryObject* getInventoryObject() const; + //-------------------------------------------------------------------- // Convenience functions for adding various common menu options. @@ -137,16 +140,15 @@ protected: protected: LLInvFVBridge(LLInventoryPanel* inventory, LLFolderView* root, const LLUUID& uuid); - LLInventoryObject* getInventoryObject() const; LLInventoryModel* getInventoryModel() const; BOOL isLinkedObjectInTrash() const; // Is this obj or its baseobj in the trash? BOOL isLinkedObjectMissing() const; // Is this a linked obj whose baseobj is not in inventory? BOOL isAgentInventory() const; // false if lost or in the inventory library - BOOL isCOFFolder() const; // true if COF or descendent of - BOOL isInboxFolder() const; // true if COF or descendent of marketplace inbox - BOOL isOutboxFolder() const; // true if COF or descendent of marketplace outbox + BOOL isCOFFolder() const; // true if COF or descendant of + BOOL isInboxFolder() const; // true if COF or descendant of marketplace inbox + BOOL isOutboxFolder() const; // true if COF or descendant of marketplace outbox BOOL isOutboxFolderDirectParent() const; const LLUUID getOutboxFolder() const; @@ -165,7 +167,7 @@ protected: LLFolderView* mRoot; const LLUUID mUUID; // item id LLInventoryType::EType mInvType; - BOOL mIsLink; + bool mIsLink; void purgeItem(LLInventoryModel *model, const LLUUID &uuid); }; @@ -213,7 +215,7 @@ public: virtual BOOL renameItem(const std::string& new_name); virtual BOOL removeItem(); virtual BOOL isItemCopyable() const; - virtual BOOL hasChildren() const { return FALSE; } + virtual bool hasChildren() const { return FALSE; } virtual BOOL isUpToDate() const { return TRUE; } static void showFloaterImagePreview(LLInventoryItem* item, AIFilePicker* filepicker); @@ -235,8 +237,8 @@ class LLFolderBridge : public LLInvFVBridge public: LLFolderBridge(LLInventoryPanel* inventory, LLFolderView* root, - const LLUUID& uuid) : - LLInvFVBridge(inventory, root, uuid), + const LLUUID& uuid) + : LLInvFVBridge(inventory, root, uuid), mCallingCards(FALSE), mWearables(FALSE) {} @@ -265,7 +267,7 @@ public: virtual void pasteFromClipboard(bool only_copies = false); virtual void pasteLinkFromClipboard(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - virtual BOOL hasChildren() const; + virtual bool hasChildren() const; virtual BOOL dragOrDrop(MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data); @@ -326,8 +328,9 @@ public: static void staticFolderOptionsMenu(); private: - BOOL mCallingCards; - BOOL mWearables; + + bool mCallingCards; + bool mWearables; menuentry_vec_t mItems; menuentry_vec_t mDisabledItems; LLRootHandle mHandle; @@ -405,7 +408,6 @@ protected: LLCallingCardObserver* mObserver; }; - class LLNotecardBridge : public LLItemBridge { public: @@ -436,7 +438,6 @@ public: static void playGesture(const LLUUID& item_id); }; - class LLAnimationBridge : public LLItemBridge { public: @@ -450,7 +451,6 @@ public: virtual void openItem(); }; - class LLObjectBridge : public LLItemBridge { public: @@ -515,8 +515,6 @@ public: void editOnAvatar(); static BOOL canRemoveFromAvatar( void* userdata ); - //static void onRemoveFromAvatar( void* userdata ); - //static void onRemoveFromAvatarArrived( LLViewerWearable* wearable, void* userdata ); //static void removeAllClothesFromAvatar(); void removeFromAvatar(); protected: @@ -629,7 +627,8 @@ public: class LLRecentInventoryBridgeBuilder : public LLInventoryFVBridgeBuilder { public: - LLRecentInventoryBridgeBuilder(): LLInventoryFVBridgeBuilder() {} + LLRecentInventoryBridgeBuilder() {} + // Overrides FolderBridge for Recent Inventory Panel. // It use base functionality for bridges other than FolderBridge. virtual LLInvFVBridge* createBridge(LLAssetType::EType asset_type, diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp index 87d6c3844..95bbf36fc 100644 --- a/indra/newview/llpanelobjectinventory.cpp +++ b/indra/newview/llpanelobjectinventory.cpp @@ -137,7 +137,7 @@ public: virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual void performAction(LLInventoryModel* model, std::string action); virtual BOOL isUpToDate() const { return TRUE; } - virtual BOOL hasChildren() const { return FALSE; } + virtual bool hasChildren() const { return FALSE; } virtual LLInventoryType::EType getInventoryType() const { return LLInventoryType::IT_NONE; } virtual LLWearableType::EType getWearableType() const { return LLWearableType::WT_NONE; } @@ -872,7 +872,7 @@ public: virtual BOOL renameItem(const std::string& new_name); virtual BOOL isItemRemovable() const; virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - virtual BOOL hasChildren() const; + virtual bool hasChildren() const; virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const; virtual BOOL dragOrDrop(MASK mask, BOOL drop, EDragAndDropType cargo_type, @@ -922,7 +922,7 @@ void LLTaskCategoryBridge::buildContextMenu(LLMenuGL& menu, U32 flags) hide_context_entries(menu, items, disabled_items); } -BOOL LLTaskCategoryBridge::hasChildren() const +bool LLTaskCategoryBridge::hasChildren() const { // return TRUE if we have or do know know if we have children. // *FIX: For now, return FALSE - we will know for sure soon enough. diff --git a/indra/newview/llshareavatarhandler.cpp b/indra/newview/llshareavatarhandler.cpp new file mode 100644 index 000000000..959556a51 --- /dev/null +++ b/indra/newview/llshareavatarhandler.cpp @@ -0,0 +1,67 @@ +/** + * @file llshareavatarhandler.cpp + * @brief slapp to handle sharing with an avatar + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llcommandhandler.h" +#include "llavataractions.h" +#include "llnotificationsutil.h" +#include "llui.h" + +class LLShareWithAvatarHandler : public LLCommandHandler +{ +public: + // requires trusted browser to trigger + LLShareWithAvatarHandler() : LLCommandHandler("sharewithavatar", UNTRUSTED_THROTTLE) + { + } + + bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + { + /*if (!LLUI::sSettingGroups["config"]->getBOOL("EnableAvatarShare")) + { + LLNotificationsUtil::add("NoAvatarShare", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); + return true; + }*/ + + //Make sure we have some parameters + if (params.size() == 0) + { + return false; + } + + //Get the ID + LLUUID id; + if (!id.set( params[0], FALSE)) + { + return false; + } + + //instigate share with this avatar + LLAvatarActions::share(id); + return true; + } +}; +LLShareWithAvatarHandler gShareWithAvatar; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 0a57d3a1f..444247924 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -2930,6 +2930,7 @@ class LLObjectImportUpload : public view_listener_t //--------------------------------------------------------------------------- // Parcel freeze, eject, etc. //--------------------------------------------------------------------------- +void send_freeze(const LLUUID& avatar_id, bool freeze); bool callback_freeze(const LLSD& notification, const LLSD& response) { LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); @@ -2937,27 +2938,7 @@ bool callback_freeze(const LLSD& notification, const LLSD& response) if (0 == option || 1 == option) { - U32 flags = KICK_FLAGS_FREEZE; - if (1 == option) - { - // unfreeze - flags |= KICK_FLAGS_UNFREEZE; - } - - LLMessageSystem* msg = gMessageSystem; - LLVOAvatar* avatarp = gObjectList.findAvatar(avatar_id); - - if (avatarp && avatarp->getRegion()) - { - msg->newMessage("FreezeUser"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("TargetID", avatar_id ); - msg->addU32("Flags", flags ); - msg->sendReliable( avatarp->getRegion()->getHost() ); - } + send_freeze(avatar_id, !option); } return false; } @@ -9105,6 +9086,15 @@ class ListRequestTeleport : public view_listener_t } }; +class ListShare : public view_listener_t +{ + bool handleEvent(LLPointer event, const LLSD& userdata) + { + LLAvatarActions::share(get_focused_list_id_selected()); + return true; + } +}; + class ListShowProfile : public view_listener_t { bool handleEvent(LLPointer event, const LLSD& userdata) @@ -9559,6 +9549,7 @@ void initialize_menus() addMenu(new ListRemoveFriend(), "List.RemoveFriend"); addMenu(new ListRequestFriendship(), "List.RequestFriendship"); addMenu(new ListRequestTeleport(), "List.RequestTeleport"); + addMenu(new ListShare(), "List.Share"); addMenu(new ListShowProfile(), "List.ShowProfile"); addMenu(new ListShowWebProfile(), "List.ShowWebProfile"); addMenu(new ListStartAdhocCall(), "List.StartAdhocCall"); diff --git a/indra/newview/skins/default/xui/en-us/menu_avs_list.xml b/indra/newview/skins/default/xui/en-us/menu_avs_list.xml index feb47745d..1bd2aea10 100644 --- a/indra/newview/skins/default/xui/en-us/menu_avs_list.xml +++ b/indra/newview/skins/default/xui/en-us/menu_avs_list.xml @@ -56,6 +56,10 @@ + + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_inventory.xml b/indra/newview/skins/default/xui/en-us/menu_inventory.xml index 6f0f02133..4d896ce33 100644 --- a/indra/newview/skins/default/xui/en-us/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en-us/menu_inventory.xml @@ -1,6 +1,14 @@ + + + diff --git a/indra/newview/skins/default/xui/en-us/menu_radar.xml b/indra/newview/skins/default/xui/en-us/menu_radar.xml index 624b577c6..540416be0 100644 --- a/indra/newview/skins/default/xui/en-us/menu_radar.xml +++ b/indra/newview/skins/default/xui/en-us/menu_radar.xml @@ -57,6 +57,10 @@ + + + + diff --git a/indra/newview/skins/default/xui/en-us/notifications.xml b/indra/newview/skins/default/xui/en-us/notifications.xml index a93e2468e..f026201f5 100644 --- a/indra/newview/skins/default/xui/en-us/notifications.xml +++ b/indra/newview/skins/default/xui/en-us/notifications.xml @@ -2142,15 +2142,6 @@ Multiple parcels selected. Try selecting a single parcel. - - Deed to group failed. - group - fail - - + +Select residents to share with. + + + + +Are you sure you want to share the following items: + +[ITEMS] + +With the following Residents: + +[RESIDENTS] + confirm + + + + +Only one folder at a time can be shared. + +Are you sure you want to share the following items: + +[ITEMS] + +With the following Residents: + +[RESIDENTS] + confirm + + + + +Items successfully shared. + + + + Deed to group failed. + group + fail + + Inventory item offered to [NAME] + + Drag items from inventory here +