From 3ba967bdc1e6cb91800a3663e65f46ceb041d7dc Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 8 Dec 2012 00:59:37 -0600 Subject: [PATCH] Update to LLAvatarNameCache and consumers. --- indra/llmessage/aihttptimeoutpolicy.cpp | 1 + indra/llmessage/llavatarnamecache.cpp | 112 +++-- indra/llmessage/llavatarnamecache.h | 7 +- indra/newview/llfloateravatarpicker.cpp | 430 ++++++++++++------ indra/newview/llfloateravatarpicker.h | 34 +- indra/newview/llfloatergodtools.cpp | 13 +- indra/newview/llfloatergodtools.h | 3 +- indra/newview/llfloaterland.cpp | 37 +- indra/newview/llfloaterland.h | 4 +- indra/newview/llfloatermute.cpp | 11 +- indra/newview/llfloatermute.h | 3 +- indra/newview/llfloaterregioninfo.cpp | 94 ++-- indra/newview/llfloaterregioninfo.h | 10 +- indra/newview/llfloaterreporter.cpp | 15 +- indra/newview/llfloaterreporter.h | 3 +- indra/newview/llfloatersellland.cpp | 17 +- indra/newview/llpanelgroupinvite.cpp | 168 +++++-- indra/newview/llpanelgroupinvite.h | 7 +- indra/newview/llviewerparcelmgr.cpp | 8 +- indra/newview/llviewerparcelmgr.h | 2 + .../default/xui/en-us/panel_group_invite.xml | 6 + 21 files changed, 646 insertions(+), 339 deletions(-) diff --git a/indra/llmessage/aihttptimeoutpolicy.cpp b/indra/llmessage/aihttptimeoutpolicy.cpp index 4acd41267..5f7cbaf89 100644 --- a/indra/llmessage/aihttptimeoutpolicy.cpp +++ b/indra/llmessage/aihttptimeoutpolicy.cpp @@ -820,6 +820,7 @@ P(accountingCostResponder); P(agentStateResponder); P(assetUploadResponder); P(asyncConsoleResponder); +P(avatarPickerResponder); P(authHandler); P(avatarNameResponder); P2(baseCapabilitiesComplete, transfer_18s); diff --git a/indra/llmessage/llavatarnamecache.cpp b/indra/llmessage/llavatarnamecache.cpp index ae04a8105..cd71efea9 100644 --- a/indra/llmessage/llavatarnamecache.cpp +++ b/indra/llmessage/llavatarnamecache.cpp @@ -93,6 +93,9 @@ namespace LLAvatarNameCache /// Time when unrefreshed cached names were checked last static F64 sLastExpireCheck; + /// Time-to-live for a temp cache entry. + const F64 TEMP_CACHE_ENTRY_LIFETIME = 60.0; + //----------------------------------------------------------------------- // Internal methods //----------------------------------------------------------------------- @@ -291,13 +294,14 @@ void LLAvatarNameCache::handleAgentError(const LLUUID& agent_id) // Clear this agent from the pending list LLAvatarNameCache::sPendingQueue.erase(agent_id); - const LLAvatarName& av_name = existing->second; + LLAvatarName& av_name = existing->second; LL_DEBUGS("AvNameCache") << "LLAvatarNameCache use cache for agent " << agent_id << "user '" << av_name.mUsername << "' " << "display '" << av_name.mDisplayName << "' " << "expires in " << av_name.mExpires - LLFrameTimer::getTotalSeconds() << " seconds" << LL_ENDL; + av_name.mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME; // reset expiry time so we don't constantly rerequest. } } @@ -342,19 +346,23 @@ void LLAvatarNameCache::requestNamesViaCapability() // http://pdp60.lindenlab.com:8000/agents/?ids=3941037e-78ab-45f0-b421-bd6e77c1804d&ids=0012809d-7d2d-4c24-9609-af1230a37715&ids=0019aaba-24af-4f0a-aa72-6457953cf7f0 // // Apache can handle URLs of 4096 chars, but let's be conservative - const U32 NAME_URL_MAX = 4096; - const U32 NAME_URL_SEND_THRESHOLD = 3000; + static const U32 NAME_URL_MAX = 4096; + static const U32 NAME_URL_SEND_THRESHOLD = 3500; + std::string url; url.reserve(NAME_URL_MAX); std::vector agent_ids; agent_ids.reserve(128); + U32 id_total = sAskQueue.size(); U32 ids = 0; - ask_queue_t::const_iterator it = sAskQueue.begin(); - for ( ; it != sAskQueue.end(); ++it) + ask_queue_t::const_iterator it; + while(!sAskQueue.empty()) { + it = sAskQueue.begin(); const LLUUID& agent_id = *it; + sAskQueue.erase(it); if (url.empty()) { @@ -377,27 +385,17 @@ void LLAvatarNameCache::requestNamesViaCapability() if (url.size() > NAME_URL_SEND_THRESHOLD) { - LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability first " - << ids << " ids" - << LL_ENDL; - LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); - url.clear(); - agent_ids.clear(); + break; } } if (!url.empty()) { - LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability all " - << ids << " ids" + LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::requestNamesViaCapability requested " + << ids << "/" << id_total << "ids " << LL_ENDL; LLHTTPClient::get(url, new LLAvatarNameResponder(agent_ids)); - url.clear(); - agent_ids.clear(); } - - // We've moved all asks to the pending request queue - sAskQueue.clear(); } void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id, @@ -414,20 +412,25 @@ void LLAvatarNameCache::legacyNameCallback(const LLUUID& agent_id, << LL_ENDL; buildLegacyName(full_name, &av_name); - // Don't add to cache, the data already exists in the legacy name system - // cache and we don't want or need duplicate storage, because keeping the - // two copies in sync is complex. - processName(agent_id, av_name, false); + // Add to cache, because if we don't we'll keep rerequesting the + // same record forever. buildLegacyName should always guarantee + // that these records expire reasonably soon + // (in TEMP_CACHE_ENTRY_LIFETIME seconds), so if the failure was due + // to something temporary we will eventually request and get the right data. + processName(agent_id, av_name, true); } void LLAvatarNameCache::requestNamesViaLegacy() { + static const S32 MAX_REQUESTS = 100; F64 now = LLFrameTimer::getTotalSeconds(); std::string full_name; - ask_queue_t::const_iterator it = sAskQueue.begin(); - for (; it != sAskQueue.end(); ++it) + ask_queue_t::const_iterator it; + for (S32 requests = 0; !sAskQueue.empty() && requests < MAX_REQUESTS; ++requests) { + it = sAskQueue.begin(); const LLUUID& agent_id = *it; + sAskQueue.erase(it); // Mark as pending first, just in case the callback is immediately // invoked below. This should never happen in practice. @@ -439,10 +442,6 @@ void LLAvatarNameCache::requestNamesViaLegacy() boost::bind(&LLAvatarNameCache::legacyNameCallback, _1, _2, _3)); } - - // We've either answered immediately or moved all asks to the - // pending queue - sAskQueue.clear(); } void LLAvatarNameCache::initClass(bool running) @@ -519,11 +518,11 @@ void LLAvatarNameCache::idle() // *TODO: Possibly re-enabled this based on People API load measurements // 100 ms is the threshold for "user speed" operations, so we can // stall for about that long to batch up requests. - //const F32 SECS_BETWEEN_REQUESTS = 0.1f; - //if (!sRequestTimer.checkExpirationAndReset(SECS_BETWEEN_REQUESTS)) - //{ - // return; - //} + const F32 SECS_BETWEEN_REQUESTS = 0.1f; + if (!sRequestTimer.hasExpired()) + { + return; + } if (!sAskQueue.empty()) { @@ -538,6 +537,12 @@ void LLAvatarNameCache::idle() } } + if (sAskQueue.empty()) + { + // cleared the list, reset the request timer. + sRequestTimer.reset(SECS_BETWEEN_REQUESTS); + } + // erase anything that has not been refreshed for more than MAX_UNREFRESHED_TIME eraseUnrefreshed(); } @@ -595,7 +600,7 @@ void LLAvatarNameCache::buildLegacyName(const std::string& full_name, av_name->mDisplayName = full_name; av_name->mIsDisplayNameDefault = true; av_name->mIsTemporaryName = true; - av_name->mExpires = F64_MAX; // not used because these are not cached + av_name->mExpires = LLFrameTimer::getTotalSeconds() + TEMP_CACHE_ENTRY_LIFETIME; LL_DEBUGS("AvNameCache") << "LLAvatarNameCache::buildLegacyName " << full_name << LL_ENDL; @@ -673,8 +678,10 @@ void LLAvatarNameCache::fireSignal(const LLUUID& agent_id, signal(agent_id, av_name); } -void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot) +LLAvatarNameCache::callback_connection_t LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot) { + callback_connection_t connection; + if (sRunning) { // ...only do immediate lookups when cache is running @@ -690,7 +697,7 @@ void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot) { // ...name already exists in cache, fire callback now fireSignal(agent_id, slot, av_name); - return; + return connection; } } } @@ -703,7 +710,7 @@ void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot) LLAvatarName av_name; buildLegacyName(full_name, &av_name); fireSignal(agent_id, slot, av_name); - return; + return connection; } } } @@ -720,15 +727,17 @@ void LLAvatarNameCache::get(const LLUUID& agent_id, callback_slot_t slot) { // ...new callback for this id callback_signal_t* signal = new callback_signal_t(); - signal->connect(slot); + connection = signal->connect(slot); sSignalMap[agent_id] = signal; } else { // ...existing callback, bind additional slot callback_signal_t* signal = sig_it->second; - signal->connect(slot); + connection = signal->connect(slot); } + + return connection; } // [RLVa:KB] - Checked: 2010-12-08 (RLVa-1.4.0a) | Added: RLVa-1.2.2c @@ -774,12 +783,6 @@ void LLAvatarNameCache::erase(const LLUUID& agent_id) sCache.erase(agent_id); } -void LLAvatarNameCache::fetch(const LLUUID& agent_id) -{ - // re-request, even if request is already pending - sAskQueue.insert(agent_id); -} - void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_name) { // *TODO: update timestamp if zero? @@ -788,26 +791,35 @@ void LLAvatarNameCache::insert(const LLUUID& agent_id, const LLAvatarName& av_na F64 LLAvatarNameCache::nameExpirationFromHeaders(AIHTTPReceivedHeaders const& headers) { - F64 expires; - expirationFromCacheControl(headers, &expires); - return expires; + F64 expires = 0.0; + if (expirationFromCacheControl(headers, &expires)) + { + return expires; + } + else + { + // With no expiration info, default to an hour + const F64 DEFAULT_EXPIRES = 60.0 * 60.0; + F64 now = LLFrameTimer::getTotalSeconds(); + return now + DEFAULT_EXPIRES; + } } bool LLAvatarNameCache::expirationFromCacheControl(AIHTTPReceivedHeaders const& headers, F64* expires) { bool fromCacheControl = false; - S32 max_age = 3600; // With no expiration info, default to an hour. F64 now = LLFrameTimer::getTotalSeconds(); // Allow the header to override the default std::string cache_control; if (headers.getFirstValue("cache-control", cache_control)) { + S32 max_age = 0; if (max_age_from_cache_control(cache_control, &max_age)) { + *expires = now + (F64)max_age; fromCacheControl = true; } } - *expires = now + (F64)max_age; LL_DEBUGS("AvNameCache") << ( fromCacheControl ? "expires based on cache control " : "default expiration " ) << "in " << *expires - now << " seconds" diff --git a/indra/llmessage/llavatarnamecache.h b/indra/llmessage/llavatarnamecache.h index 75f613e74..18f192c65 100644 --- a/indra/llmessage/llavatarnamecache.h +++ b/indra/llmessage/llavatarnamecache.h @@ -71,10 +71,11 @@ namespace LLAvatarNameCache void (const LLUUID& agent_id, const LLAvatarName& av_name)> callback_signal_t; typedef callback_signal_t::slot_type callback_slot_t; + typedef boost::signals2::connection callback_connection_t; // Fetches name information and calls callback. // If name information is in cache, callback will be called immediately. - void get(const LLUUID& agent_id, callback_slot_t slot); + callback_connection_t get(const LLUUID& agent_id, callback_slot_t slot); // Allow display names to be explicitly disabled for testing. void setUseDisplayNames(bool use); @@ -90,10 +91,6 @@ namespace LLAvatarNameCache /// Provide some fallback for agents that return errors void handleAgentError(const LLUUID& agent_id); - // Force a re-fetch of the most recent data, but keep the current - // data in cache - void fetch(const LLUUID& agent_id); - void insert(const LLUUID& agent_id, const LLAvatarName& av_name); // Compute name expiration time from HTTP Cache-Control header, diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 99f6b49f9..6d6d1e251 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -37,17 +37,20 @@ #include "llagent.h" #include "llbutton.h" +#include "llcachename.h" #include "llfocusmgr.h" #include "llfoldervieweventlistener.h" #include "llinventorypanel.h" #include "llinventorymodel.h" #include "llinventoryfunctions.h" +#include "llavatarnamecache.h" // IDEVO #include "lllineeditor.h" #include "llscrolllistctrl.h" #include "lltextbox.h" #include "lluictrlfactory.h" #include "llviewercontrol.h" #include "llworld.h" +#include "llviewerregion.h" // [RLVa:KB] #include "rlvhandler.h" @@ -60,45 +63,36 @@ const std::string FLOATER_TITLE = "Choose Resident"; // static LLFloaterAvatarPicker* LLFloaterAvatarPicker::sInstance = NULL; +static std::map sAvatarNameMap; - -LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(callback_t callback, - void* userdata, +LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(select_callback_t callback, BOOL allow_multiple, BOOL closeOnSelect) { // TODO: This class should not be a singleton as it's used in multiple places // and therefore can't be used simultaneously. -MG - if (!sInstance) + + LLFloaterAvatarPicker* floater = sInstance ? sInstance : new LLFloaterAvatarPicker(); + floater->open(); /* Flawfinder: ignore */ + if(!sInstance) { - sInstance = new LLFloaterAvatarPicker(); - sInstance->mCallback = callback; - sInstance->mCallbackUserdata = userdata; - sInstance->mCloseOnSelect = FALSE; - - sInstance->open(); /* Flawfinder: ignore */ - sInstance->center(); - sInstance->setAllowMultiple(allow_multiple); - } - else - { - sInstance->open(); /*Flawfinder: ignore*/ - sInstance->mCallback = callback; - sInstance->mCallbackUserdata = userdata; - sInstance->setAllowMultiple(allow_multiple); + sInstance = floater; + floater->center(); } - sInstance->mNearMeListComplete = FALSE; - sInstance->mCloseOnSelect = closeOnSelect; - return sInstance; + floater->mSelectionCallback = callback; + floater->setAllowMultiple(allow_multiple); + floater->mNearMeListComplete = FALSE; + floater->mCloseOnSelect = closeOnSelect; + return floater; } // Default constructor LLFloaterAvatarPicker::LLFloaterAvatarPicker() : LLFloater(std::string("avatarpicker"), FLOATER_RECT, FLOATER_TITLE, TRUE, MIN_WIDTH, MIN_HEIGHT), - mResultsReturned(FALSE), - mCallback(NULL), - mCallbackUserdata(NULL) + mNumResultsReturned(0), + mNearMeListComplete(FALSE), + mCloseOnSelect(FALSE) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_avatar_picker.xml", NULL); } @@ -111,16 +105,16 @@ BOOL LLFloaterAvatarPicker::postBuild() childSetAction("Find", boost::bind(&LLFloaterAvatarPicker::onBtnFind, this)); getChildView("Find")->setEnabled(FALSE); childSetAction("Refresh", boost::bind(&LLFloaterAvatarPicker::onBtnRefresh, this)); - getChild("near_me_range")->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onRangeAdjust, _1, this)); + getChild("near_me_range")->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onRangeAdjust, this)); LLScrollListCtrl* searchresults = getChild("SearchResults"); searchresults->setDoubleClickCallback( boost::bind(&LLFloaterAvatarPicker::onBtnSelect, this)); - searchresults->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onList, _1, this)); + searchresults->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onList, this)); getChildView("SearchResults")->setEnabled(FALSE); LLScrollListCtrl* nearme = getChild("NearMe"); nearme->setDoubleClickCallback(boost::bind(&LLFloaterAvatarPicker::onBtnSelect, this)); - nearme->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onList, _1, this)); + nearme->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onList, this)); childSetAction("Select", boost::bind(&LLFloaterAvatarPicker::onBtnSelect, this)); getChildView("Select")->setEnabled(FALSE); @@ -135,16 +129,17 @@ BOOL LLFloaterAvatarPicker::postBuild() search_panel->setDefaultBtn("Find"); } - getChild("SearchResults")->addCommentText(getString("no_results")); + getChild("SearchResults")->setCommentText(getString("no_results")); LLInventoryPanel* inventory_panel = getChild("InventoryPanel"); inventory_panel->setFilterTypes(0x1 << LLInventoryType::IT_CALLINGCARD); inventory_panel->setFollowsAll(); inventory_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); inventory_panel->openDefaultFolderForType(LLAssetType::AT_CALLINGCARD); - inventory_panel->setSelectCallback(boost::bind(&LLFloaterAvatarPicker::onCallingCardSelectionChange, _1, _2, (void*)this)); + inventory_panel->setSelectCallback(boost::bind(&LLFloaterAvatarPicker::onCallingCardSelectionChange, this, _1, _2)); - getChild("ResidentChooserTabs")->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onTabChanged,this)); + getChild("ResidentChooserTabs")->setCommitCallback( + boost::bind(&LLFloaterAvatarPicker::onTabChanged,this)); setAllowMultiple(FALSE); @@ -169,7 +164,7 @@ void LLFloaterAvatarPicker::onBtnFind() find(); } -static void getSelectedAvatarData(const LLScrollListCtrl* from, std::vector& avatar_names, std::vector& avatar_ids) +static void getSelectedAvatarData(const LLScrollListCtrl* from, uuid_vec_t& avatar_ids, std::vector& avatar_names) { std::vector items = from->getAllSelected(); for (std::vector::iterator iter = items.begin(); iter != items.end(); ++iter) @@ -177,105 +172,141 @@ static void getSelectedAvatarData(const LLScrollListCtrl* from, std::vectorgetUUID().notNull()) { - avatar_names.push_back(item->getColumn(0)->getValue().asString()); avatar_ids.push_back(item->getUUID()); + + std::map::iterator iter = sAvatarNameMap.find(item->getUUID()); + if (iter != sAvatarNameMap.end()) + { + avatar_names.push_back(iter->second); + } + else + { + // the only case where it isn't in the name map is friends + // but it should be in the name cache + LLAvatarName av_name; + LLAvatarNameCache::get(item->getUUID(), &av_name); + avatar_names.push_back(av_name); + } } } } -void LLFloaterAvatarPicker::onBtnSelect(void* userdata) +void LLFloaterAvatarPicker::onBtnSelect() { - LLFloaterAvatarPicker* self = (LLFloaterAvatarPicker*)userdata; - if(self->mCallback) + // If select btn not enabled then do not callback + if (!visibleItemsSelected()) + return; + + if(mSelectionCallback) { - LLPanel* active_panel = self->childGetVisibleTab("ResidentChooserTabs"); - - if(active_panel == self->getChild("CallingCardsPanel")) + std::vector avatar_names; + std::vector avatar_ids; + std::string active_panel_name; + LLScrollListCtrl* list = NULL; + LLPanel* active_panel = childGetVisibleTab("ResidentChooserTabs"); + if(active_panel) { - self->mCallback(self->mSelectedInventoryAvatarNames, self->mSelectedInventoryAvatarIDs, self->mCallbackUserdata); + active_panel_name = active_panel->getName(); } - else if(active_panel == self->getChild("SearchPanel")) + if(active_panel_name == "CallingCardsPanel") { - std::vector avatar_names; - std::vector avatar_ids; - getSelectedAvatarData(self->getChild("SearchResults"), avatar_names, avatar_ids); - self->mCallback(avatar_names, avatar_ids, self->mCallbackUserdata); + avatar_ids = mSelectedInventoryAvatarIDs; + for(std::vector::size_type i = 0; i < avatar_ids.size(); ++i) + { + std::map::iterator iter = sAvatarNameMap.find(avatar_ids[i]); + LLAvatarName av_name; + if (iter != sAvatarNameMap.end()) + { + avatar_names.push_back(iter->second); + } + else if(LLAvatarNameCache::get(avatar_ids[i], &av_name)) + { + avatar_names.push_back(av_name); + } + else + { + std::string name = gCacheName->buildLegacyName(mSelectedInventoryAvatarNames[i]); + std::string::size_type pos = name.find(' '); + av_name.mLegacyFirstName = name.substr(pos); + av_name.mLegacyLastName = pos!=std::string::npos ? name.substr(pos+1) : "Resident"; + av_name.mDisplayName = name; + av_name.mUsername = ""; + avatar_names.push_back(av_name); + } + } } - else if(active_panel == self->getChild("NearMePanel")) + else if(active_panel_name == "SearchPanel") { - std::vector avatar_names; - std::vector avatar_ids; - getSelectedAvatarData(self->getChild("NearMe"), avatar_names, avatar_ids); - self->mCallback(avatar_names, avatar_ids, self->mCallbackUserdata); + list = getChild("SearchResults"); } - else if(active_panel == self->getChild("KeyPanel")) + else if(active_panel_name == "NearMePanel") { - LLUUID specified = self->getChild("EditUUID")->getValue().asUUID(); + list = getChild("NearMe"); + } + else if(active_panel_name == "KeyPanel") + { + LLUUID specified = getChild("EditUUID")->getValue().asUUID(); if(specified.isNull()) return; - std::vector avatar_names; - std::vector avatar_ids; avatar_ids.push_back(specified); - avatar_names.push_back(specified.asString()); - self->mCallback(avatar_names, avatar_ids, self->mCallbackUserdata); + + std::map::iterator iter = sAvatarNameMap.find(specified); + if (iter != sAvatarNameMap.end()) + { + avatar_names.push_back(iter->second); + } + else + { + LLAvatarName av_name; + LLAvatarNameCache::get(specified, &av_name); + avatar_names.push_back(av_name); + } + } + + if(list) + { + getSelectedAvatarData(list, avatar_ids, avatar_names); + } + if(!avatar_names.empty() && !avatar_ids.empty()) + { + mSelectionCallback(avatar_ids, avatar_names); } } - self->getChild("InventoryPanel")->setSelection(LLUUID::null, FALSE); - self->getChild("SearchResults")->deselectAllItems(TRUE); - self->getChild("NearMe")->deselectAllItems(TRUE); - if(self->mCloseOnSelect) + getChild("InventoryPanel")->setSelection(LLUUID::null, FALSE); + getChild("SearchResults")->deselectAllItems(TRUE); + getChild("NearMe")->deselectAllItems(TRUE); + if(mCloseOnSelect) { - self->mCloseOnSelect = FALSE; - self->close(); + mCloseOnSelect = FALSE; + close(); } } -void LLFloaterAvatarPicker::onBtnRefresh(void* userdata) +void LLFloaterAvatarPicker::onBtnRefresh() { - LLFloaterAvatarPicker* self = (LLFloaterAvatarPicker*)userdata; - if (!self) - { - return; - } - - self->getChild("NearMe")->deleteAllItems(); - self->getChild("NearMe")->addCommentText(self->getString("searching")); - self->mNearMeListComplete = FALSE; + getChild("NearMe")->deleteAllItems(); + getChild("NearMe")->setCommentText(getString("searching")); + mNearMeListComplete = FALSE; } -void LLFloaterAvatarPicker::onBtnClose(void* userdata) +void LLFloaterAvatarPicker::onBtnClose() { - LLFloaterAvatarPicker* self = (LLFloaterAvatarPicker*)userdata; - if(self) self->close(); + close(); } -void LLFloaterAvatarPicker::onRangeAdjust(LLUICtrl* source, void* data) +void LLFloaterAvatarPicker::onRangeAdjust() { - LLFloaterAvatarPicker::onBtnRefresh(data); + onBtnRefresh(); } -void LLFloaterAvatarPicker::onList(LLUICtrl* ctrl, void* userdata) +void LLFloaterAvatarPicker::onList() { - LLFloaterAvatarPicker* self = (LLFloaterAvatarPicker*)userdata; - if (self) - { - self->childSetEnabled("Select", self->visibleItemsSelected()); - } -} - -// static callback for inventory picker (select from calling cards) -void LLFloaterAvatarPicker::onCallingCardSelectionChange(const std::deque &items, BOOL user_action, void* data) -{ - LLFloaterAvatarPicker* self = (LLFloaterAvatarPicker*)data; - if (self) - { - self->doCallingCardSelectionChange( items, user_action, data ); - } + getChildView("Select")->setEnabled(visibleItemsSelected()); } // Callback for inventory picker (select from calling cards) -void LLFloaterAvatarPicker::doCallingCardSelectionChange(const std::deque &items, BOOL user_action, void* data) +void LLFloaterAvatarPicker::onCallingCardSelectionChange(const std::deque &items, BOOL user_action) { bool panel_active = (childGetVisibleTab("ResidentChooserTabs") == getChild("CallingCardsPanel")); @@ -315,7 +346,7 @@ void LLFloaterAvatarPicker::populateNearMe() LLScrollListCtrl* near_me_scroller = getChild("NearMe"); near_me_scroller->deleteAllItems(); - std::vector avatar_ids; + uuid_vec_t avatar_ids; LLWorld::getInstance()->getAvatars(&avatar_ids, NULL, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); for(U32 i=0; igetFullName(av, fullname)) + LLAvatarName av_name; + + if (!LLAvatarNameCache::get(av, &av_name)) { + element["columns"][0]["column"] = "name"; element["columns"][0]["value"] = LLCacheName::getDefaultName(); all_loaded = FALSE; } else { - element["columns"][0]["value"] = fullname; + element["columns"][0]["column"] = "name"; + element["columns"][0]["value"] = av_name.mDisplayName; + element["columns"][1]["column"] = "username"; + element["columns"][1]["value"] = av_name.mUsername; + + sAvatarNameMap[av] = av_name; } near_me_scroller->addElement(element); empty = FALSE; @@ -339,16 +377,16 @@ void LLFloaterAvatarPicker::populateNearMe() if (empty) { - childDisable("NearMe"); - childDisable("Select"); - near_me_scroller->addCommentText(getString("no_one_near")); + getChildView("NearMe")->setEnabled(FALSE); + getChildView("Select")->setEnabled(FALSE); + near_me_scroller->setCommentText(getString("no_one_near")); } else { - childEnable("NearMe"); - childEnable("Select"); + getChildView("NearMe")->setEnabled(TRUE); + getChildView("Select")->setEnabled(TRUE); near_me_scroller->selectFirstItem(); - onList(near_me_scroller, this); + onList(); near_me_scroller->setFocus(TRUE); } @@ -401,38 +439,103 @@ BOOL LLFloaterAvatarPicker::visibleItemsSelected() const } else if(active_panel == getChild("CallingCardsPanel")) { - return mSelectedInventoryAvatarIDs.size() > 0; + return !mSelectedInventoryAvatarIDs.empty(); } else if(active_panel == getChild("NearMePanel")) { return getChild("NearMe")->getFirstSelectedIndex() >= 0; } + else if(active_panel == getChild("KeyPanel")) + { + LLUUID specified = getChild("EditUUID")->getValue().asUUID(); + return !specified.isNull(); + } return FALSE; } +extern AIHTTPTimeoutPolicy avatarPickerResponder_timeout; +class LLAvatarPickerResponder : public LLHTTPClient::ResponderWithCompleted +{ +public: + LLUUID mQueryID; + + LLAvatarPickerResponder(const LLUUID& id) : mQueryID(id) { } + + /*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content) + { + //std::ostringstream ss; + //LLSDSerialize::toPrettyXML(content, ss); + //llinfos << ss.str() << llendl; + + // in case of invalid characters, the avatar picker returns a 400 + // just set it to process so it displays 'not found' + if ((200 <= status && status < 300) || status == 400) + { + LLFloaterAvatarPicker* floater = LLFloaterAvatarPicker::sInstance; + if (floater) + { + floater->processResponse(mQueryID, content); + } + } + else + { + llinfos << "avatar picker failed " << status + << " reason " << reason << llendl; + + } + } + + const AIHTTPTimeoutPolicy &getHTTPTimeoutPolicy(void) const { return avatarPickerResponder_timeout; } +}; + void LLFloaterAvatarPicker::find() { + //clear our stored LLAvatarNames + sAvatarNameMap.clear(); + const std::string& text = childGetValue("Edit").asString(); mQueryID.generate(); - LLMessageSystem* msg = gMessageSystem; + std::string url; + url.reserve(128); // avoid a memory allocation or two - msg->newMessage("AvatarPickerRequest"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->addUUID("QueryID", mQueryID); // not used right now - msg->nextBlock("Data"); - msg->addString("Name", text); - - gAgent.sendReliableMessage(); + 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()) + { + // capability urls don't end in '/', but we need one to parse + // query parameters correctly + if (url.size() > 0 && url[url.size()-1] != '/') + { + url += "/"; + } + url += "?page_size=100&names="; + url += LLURI::escape(text); + llinfos << "avatar picker " << url << llendl; + LLHTTPClient::get(url, new LLAvatarPickerResponder(mQueryID)); + } + else + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("AvatarPickerRequest"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->addUUID("QueryID", mQueryID); // not used right now + msg->nextBlock("Data"); + msg->addString("Name", text); + gAgent.sendReliableMessage(); + } getChild("SearchResults")->deleteAllItems(); - getChild("SearchResults")->addCommentText(getString("searching")); + getChild("SearchResults")->setCommentText(getString("searching")); childSetEnabled("Select", FALSE); - mResultsReturned = FALSE; + mNumResultsReturned = 0; } void LLFloaterAvatarPicker::setAllowMultiple(BOOL allow_multiple) @@ -458,21 +561,21 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void* if (agent_id != gAgent.getID()) return; // Dialog already closed - LLFloaterAvatarPicker *self = sInstance; - if (!self) return; + LLFloaterAvatarPicker *floater = sInstance; - // these are not results from our last request - if (query_id != self->mQueryID) + // floater is closed or these are not results from our last request + if (NULL == floater || query_id != floater->mQueryID) { return; } - LLScrollListCtrl* search_results = self->getChild("SearchResults"); + LLScrollListCtrl* search_results = floater->getChild("SearchResults"); // clear "Searching" label on first results - search_results->deleteAllItems(); - - self->mResultsReturned = TRUE; + if (floater->mNumResultsReturned++ == 0) + { + search_results->deleteAllItems(); + } BOOL found_one = FALSE; S32 num_new_rows = msg->getNumberOfBlocks("Data"); @@ -486,16 +589,24 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void* if (avatar_id.isNull()) { LLStringUtil::format_map_t map; - map["[TEXT]"] = self->childGetText("Edit"); - avatar_name = self->getString("not_found", map); + map["[TEXT]"] = floater->childGetText("Edit"); + avatar_name = floater->getString("not_found", map); search_results->setEnabled(FALSE); - self->childDisable("Select"); + floater->getChildView("Select")->setEnabled(FALSE); } else { - avatar_name = first_name + " " + last_name; + 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 @@ -506,13 +617,64 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void* if (found_one) { - self->childEnable("Select"); + floater->getChildView("Select")->setEnabled(TRUE); search_results->selectFirstItem(); - self->onList(search_results, self); + floater->onList(); search_results->setFocus(TRUE); } } +void LLFloaterAvatarPicker::processResponse(const LLUUID& query_id, const LLSD& content) +{ + // Check for out-of-date query + if (query_id != mQueryID) return; + + LLScrollListCtrl* search_results = getChild("SearchResults"); + + LLSD agents = content["agents"]; + if (agents.size() == 0) + { + LLStringUtil::format_map_t map; + map["[TEXT]"] = childGetText("Edit"); + LLSD item; + item["id"] = LLUUID::null; + item["columns"][0]["column"] = "name"; + item["columns"][0]["value"] = getString("not_found", map); + search_results->addElement(item); + search_results->setEnabled(false); + getChildView("Select")->setEnabled(false); + return; + } + + // clear "Searching" label on first results + search_results->deleteAllItems(); + + LLSD item; + LLSD::array_const_iterator it = agents.beginArray(); + 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); + + // add the avatar name to our list + LLAvatarName avatar_name; + avatar_name.fromLLSD(row); + sAvatarNameMap[row["id"].asUUID()] = avatar_name; + } + + getChildView("Select")->setEnabled(true); + search_results->setEnabled(true); + search_results->selectFirstItem(); + onList(); + search_results->setFocus(TRUE); +} + //static void LLFloaterAvatarPicker::editKeystroke(LLLineEditor* caller, void* user_data) { @@ -532,13 +694,13 @@ BOOL LLFloaterAvatarPicker::handleKeyHere(KEY key, MASK mask) { if (key == KEY_RETURN && mask == MASK_NONE) { - if (childHasFocus("Edit")) + if (getChild("Edit")->hasFocus()) { - onBtnFind(this); + onBtnFind(); } else { - onBtnSelect(this); + onBtnSelect(); } return TRUE; } diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h index 467aa6f68..2fc8543a8 100644 --- a/indra/newview/llfloateravatarpicker.h +++ b/indra/newview/llfloateravatarpicker.h @@ -37,35 +37,40 @@ #include +class LLAvatarName; +class LLScrollListCtrl; class LLFloaterAvatarPicker : public LLFloater { public: - // Call this to select an avatar. + typedef boost::signals2::signal validate_signal_t; + typedef validate_signal_t::slot_type validate_callback_t; + // The callback function will be called with an avatar name and UUID. - typedef void(*callback_t)(const std::vector&, const std::vector&, void*); - static LLFloaterAvatarPicker* show(callback_t callback, - void* userdata, + typedef boost::function&)> select_callback_t; + // Call this to select an avatar. + static LLFloaterAvatarPicker* show(select_callback_t callback, BOOL allow_multiple = FALSE, BOOL closeOnSelect = FALSE); virtual BOOL postBuild(); static void processAvatarPickerReply(class LLMessageSystem* msg, void**); + void processResponse(const LLUUID& query_id, const LLSD& content); + static LLFloaterAvatarPicker* sInstance; private: static void editKeystroke(class LLLineEditor* caller, void* user_data); void onBtnFind(); - static void onBtnSelect(void* userdata); - static void onBtnRefresh(void* userdata); - static void onRangeAdjust(LLUICtrl* source, void* data); - static void onBtnClose(void* userdata); - static void onList(class LLUICtrl* ctrl, void* userdata); + void onBtnSelect(); + void onBtnRefresh(); + void onRangeAdjust(); + void onBtnClose(); + void onList(); void onTabChanged(); - void doCallingCardSelectionChange(const std::deque &items, BOOL user_action, void* data); - static void onCallingCardSelectionChange(const std::deque &items, BOOL user_action, void* data); + void onCallingCardSelectionChange(const std::deque &items, BOOL user_action); void populateNearMe(); BOOL visibleItemsSelected() const; // Returns true if any items in the current tab are selected. @@ -79,14 +84,11 @@ private: std::vector mSelectedInventoryAvatarIDs; std::vector mSelectedInventoryAvatarNames; LLUUID mQueryID; - BOOL mResultsReturned; + int mNumResultsReturned; BOOL mNearMeListComplete; BOOL mCloseOnSelect; - void (*mCallback)(const std::vector& name, const std::vector& id, void* userdata); - void* mCallbackUserdata; - - static LLFloaterAvatarPicker* sInstance; + select_callback_t mSelectionCallback; // do not call these directly LLFloaterAvatarPicker(); diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp index ba047ae41..e51e84af0 100644 --- a/indra/newview/llfloatergodtools.cpp +++ b/indra/newview/llfloatergodtools.cpp @@ -46,6 +46,7 @@ #include "llagent.h" #include "llalertdialog.h" +#include "llavatarnamecache.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" @@ -1264,7 +1265,7 @@ void LLPanelObjectTools::onClickSet(void* data) { LLPanelObjectTools* panelp = (LLPanelObjectTools*) data; // grandparent is a floater, which can have a dependent - gFloaterView->getParentFloater(panelp)->addDependentFloater(LLFloaterAvatarPicker::show(callbackAvatarID, data)); + gFloaterView->getParentFloater(panelp)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLPanelObjectTools::callbackAvatarID, panelp, _1, _2))); } void LLPanelObjectTools::onClickSetBySelection(void* data) @@ -1288,14 +1289,12 @@ void LLPanelObjectTools::onClickSetBySelection(void* data) panelp->childSetValue("target_avatar_name", name); } -// static -void LLPanelObjectTools::callbackAvatarID(const std::vector& names, const std::vector& ids, void* data) +void LLPanelObjectTools::callbackAvatarID(const uuid_vec_t& ids, const std::vector& names) { - LLPanelObjectTools* object_tools = (LLPanelObjectTools*) data; if (ids.empty() || names.empty()) return; - object_tools->mTargetAvatar = ids[0]; - object_tools->childSetValue("target_avatar_name", names[0]); - object_tools->refresh(); + mTargetAvatar = ids[0]; + childSetValue("target_avatar_name", names[0].getCompleteName()); + refresh(); } // static diff --git a/indra/newview/llfloatergodtools.h b/indra/newview/llfloatergodtools.h index 3c36f256f..1c68a7175 100644 --- a/indra/newview/llfloatergodtools.h +++ b/indra/newview/llfloatergodtools.h @@ -41,6 +41,7 @@ #include "llpanel.h" #include +class LLAvatarName; class LLButton; class LLCheckBoxCtrl; class LLComboBox; @@ -237,7 +238,7 @@ public: static void onChangeAnything(LLUICtrl* ctrl, void* data); static void onApplyChanges(void* data); static void onClickSet(void* data); - static void callbackAvatarID(const std::vector& names, const std::vector& ids, void* data); + void callbackAvatarID(const uuid_vec_t& ids, const std::vector& names); static void onClickDeletePublicOwnedBy(void* data); static void onClickDeleteAllScriptedOwnedBy(void* data); static void onClickDeleteAllOwnedBy(void* data); diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 398151373..054d8b1f3 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -37,6 +37,7 @@ #include "llfloaterland.h" +#include "llavatarnamecache.h" #include "llcachename.h" #include "llfocusmgr.h" #include "llnotificationsutil.h" @@ -653,20 +654,26 @@ void LLPanelLandGeneral::refresh() S32 area; S32 claim_price; S32 rent_price; - F32 dwell; + F32 dwell = DWELL_NAN; LLViewerParcelMgr::getInstance()->getDisplayInfo(&area, &claim_price, &rent_price, &for_sale, &dwell); - // Area LLUIString price = getString("area_size_text"); price.setArg("[AREA]", llformat("%d",area)); mTextPriceLabel->setText(getString("area_text")); mTextPrice->setText(price.getString()); - mTextDwell->setText(llformat("%.0f", dwell)); + if (dwell == DWELL_NAN) + { + mTextDwell->setText(LLTrans::getString("LoadingData")); + } + else + { + mTextDwell->setText(llformat("%.0f", dwell)); + } if (for_sale) { @@ -2814,23 +2821,21 @@ void LLPanelLandAccess::onClickAddAccess(void* data) LLPanelLandAccess* panelp = (LLPanelLandAccess*)data; if (panelp) { - gFloaterView->getParentFloater(panelp)->addDependentFloater(LLFloaterAvatarPicker::show(callbackAvatarCBAccess, data) ); + gFloaterView->getParentFloater(panelp)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLPanelLandAccess::callbackAvatarCBAccess, panelp, _1))); } } -// static -void LLPanelLandAccess::callbackAvatarCBAccess(const std::vector& names, const std::vector& ids, void* userdata) +void LLPanelLandAccess::callbackAvatarCBAccess(const uuid_vec_t& ids) { - LLPanelLandAccess* panelp = (LLPanelLandAccess*)userdata; - if (!names.empty() && !ids.empty()) + if (!ids.empty()) { LLUUID id = ids[0]; - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (parcel) { parcel->addToAccessList(id, 0); LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(AL_ACCESS); - panelp->refresh(); + refresh(); } } } @@ -2862,22 +2867,20 @@ void LLPanelLandAccess::onClickRemoveAccess(void* data) void LLPanelLandAccess::onClickAddBanned(void* data) { LLPanelLandAccess* panelp = (LLPanelLandAccess*)data; - gFloaterView->getParentFloater(panelp)->addDependentFloater(LLFloaterAvatarPicker::show(callbackAvatarCBBanned, data) ); + gFloaterView->getParentFloater(panelp)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLPanelLandAccess::callbackAvatarCBBanned, panelp, _1))); } -// static -void LLPanelLandAccess::callbackAvatarCBBanned(const std::vector& names, const std::vector& ids, void* userdata) +void LLPanelLandAccess::callbackAvatarCBBanned(const uuid_vec_t& ids) { - LLPanelLandAccess* panelp = (LLPanelLandAccess*)userdata; - if (!names.empty() && !ids.empty()) + if (!ids.empty()) { LLUUID id = ids[0]; - LLParcel* parcel = panelp->mParcel->getParcel(); + LLParcel* parcel = mParcel->getParcel(); if (parcel) { parcel->addToBanList(id, 0); LLViewerParcelMgr::getInstance()->sendParcelAccessListUpdate(AL_BAN); - panelp->refresh(); + refresh(); } } } diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h index f578c68d2..d7c0cfeef 100644 --- a/indra/newview/llfloaterland.h +++ b/indra/newview/llfloaterland.h @@ -383,10 +383,10 @@ public: static void onCommitPublicAccess(LLUICtrl* ctrl, void *userdata); static void onCommitAny(LLUICtrl* ctrl, void *userdata); static void onClickAddAccess(void*); - static void callbackAvatarCBAccess(const std::vector& names, const std::vector& ids, void* userdata); + void callbackAvatarCBAccess(const uuid_vec_t& ids); static void onClickRemoveAccess(void*); static void onClickAddBanned(void*); - static void callbackAvatarCBBanned(const std::vector& names, const std::vector& ids, void* userdata); + void callbackAvatarCBBanned(const uuid_vec_t& ids); static void onClickRemoveBanned(void*); virtual BOOL postBuild(); diff --git a/indra/newview/llfloatermute.cpp b/indra/newview/llfloatermute.cpp index 8e071dcde..aebb4009a 100644 --- a/indra/newview/llfloatermute.cpp +++ b/indra/newview/llfloatermute.cpp @@ -43,6 +43,7 @@ // project include #include "llagent.h" +#include "llavatarnamecache.h" #include "llfloateravatarpicker.h" #include "llbutton.h" #include "lllineeditor.h" @@ -314,22 +315,20 @@ void LLFloaterMute::onClickPick(void *data) LLFloaterMute* floaterp = (LLFloaterMute*)data; const BOOL allow_multiple = FALSE; const BOOL close_on_select = TRUE; - LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(onPickUser, data, allow_multiple, close_on_select); + LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLFloaterMute::onPickUser, floaterp, _1, _2), allow_multiple, close_on_select); floaterp->addDependentFloater(picker); } //----------------------------------------------------------------------------- // onPickUser() //----------------------------------------------------------------------------- -void LLFloaterMute::onPickUser(const std::vector& names, const std::vector& ids, void* user_data) +void LLFloaterMute::onPickUser(const uuid_vec_t& ids, const std::vector& names) { - LLFloaterMute* floaterp = (LLFloaterMute*)user_data; - if (!floaterp) return; if (names.empty() || ids.empty()) return; - LLMute mute(ids[0], names[0], LLMute::AGENT); + LLMute mute(ids[0], names[0].getLegacyName(), LLMute::AGENT); LLMuteList::getInstance()->add(mute); - floaterp->updateButtons(); + updateButtons(); } diff --git a/indra/newview/llfloatermute.h b/indra/newview/llfloatermute.h index 93f1bb2c1..9034bf670 100644 --- a/indra/newview/llfloatermute.h +++ b/indra/newview/llfloatermute.h @@ -37,6 +37,7 @@ #include "llmutelist.h" #include +class LLAvatarName; class LLButton; class LLLineEditor; class LLMessageSystem; @@ -68,7 +69,7 @@ private: static void onClickRemove(void *data); static void onClickPick(void *data); static void onSelectName(LLUICtrl* caller, void *data); - static void onPickUser(const std::vector& names, const std::vector& ids, void* user_data); + void onPickUser(const uuid_vec_t& ids, const std::vector& names); static void onClickMuteByName(void*); static void callbackMuteByName(const std::string& text, void*); diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index f9a4d3908..bc6dbbde0 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -258,7 +258,8 @@ void LLFloaterRegionInfo::requestRegionInfo() void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**) { static LLDispatcher dispatch; - if(!findInstance()) + LLFloaterRegionInfo* floater = findInstance(); + if(!floater) { return; } @@ -268,7 +269,7 @@ void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**) LLPanelEstateInfo::initDispatch(dispatch); } - LLTabContainer* tab = findInstance()->getChild("region_panels"); + LLTabContainer* tab = floater->getChild("region_panels"); LLPanelEstateInfo* panel = (LLPanelEstateInfo*)tab->getChild("Estate"); // unpack the message @@ -285,8 +286,7 @@ void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**) //dispatch the message dispatch.dispatch(request, invoice, strings); - LLViewerRegion* region = gAgent.getRegion(); - panel->updateControls(region); + panel->updateControls(gAgent.getRegion()); } @@ -296,12 +296,18 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) LLPanel* panel; llinfos << "LLFloaterRegionInfo::processRegionInfo" << llendl; - if(!findInstance()) + LLFloaterRegionInfo* floater = findInstance(); + if(!floater) { return; } + // We need to re-request environment setting here, + // otherwise after we apply (send) updated region settings we won't get them back, + // so our environment won't be updated. + // This is also the way to know about externally changed region environment. + LLEnvManagerNew::instance().requestRegionSettings(); - LLTabContainer* tab = findInstance()->getChild("region_panels"); + LLTabContainer* tab = floater->getChild("region_panels"); LLViewerRegion* region = gAgent.getRegion(); BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); @@ -389,7 +395,7 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) panel->childSetEnabled("sun_hour_slider", allow_modify && !use_estate_sun); panel->setCtrlsEnabled(allow_modify); - getInstance()->refreshFromRegion( gAgent.getRegion() ); + floater->refreshFromRegion( gAgent.getRegion() ); } // static @@ -414,6 +420,11 @@ LLPanelEstateCovenant* LLFloaterRegionInfo::getPanelCovenant() void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region) { + if (!region) + { + return; + } + // call refresh from region on all panels std::for_each( mInfoPanels.begin(), @@ -632,18 +643,18 @@ void LLPanelRegionGeneralInfo::onClickKick(void* userdata) // this depends on the grandparent view being a floater // in order to set up floater dependency LLFloater* parent_floater = gFloaterView->getParentFloater(panelp); - LLFloater* child_floater = LLFloaterAvatarPicker::show(onKickCommit, userdata, FALSE, TRUE); - parent_floater->addDependentFloater(child_floater); + LLFloater* child_floater = LLFloaterAvatarPicker::show(boost::bind(&LLPanelRegionGeneralInfo::onKickCommit, panelp, _1), FALSE, TRUE); + if (child_floater) + { + parent_floater->addDependentFloater(child_floater); + } } -// static -void LLPanelRegionGeneralInfo::onKickCommit(const std::vector& names, const std::vector& ids, void* userdata) +void LLPanelRegionGeneralInfo::onKickCommit(const uuid_vec_t& ids) { - if (names.empty() || ids.empty()) return; + if (ids.empty()) return; if(ids[0].notNull()) { - LLPanelRegionGeneralInfo* self = (LLPanelRegionGeneralInfo*)userdata; - if(!self) return; strings_t strings; // [0] = our agent id // [1] = target agent id @@ -655,7 +666,7 @@ void LLPanelRegionGeneralInfo::onKickCommit(const std::vector& name strings.push_back(strings_t::value_type(buffer)); LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - self->sendEstateOwnerMessage(gMessageSystem, "teleporthomeuser", invoice, strings); + sendEstateOwnerMessage(gMessageSystem, "teleporthomeuser", invoice, strings); } } @@ -886,17 +897,15 @@ BOOL LLPanelRegionDebugInfo::sendUpdate() void LLPanelRegionDebugInfo::onClickChooseAvatar(void* data) { - LLFloaterAvatarPicker::show(callbackAvatarID, data, FALSE, TRUE); + LLFloaterAvatarPicker::show(boost::bind(&LLPanelRegionDebugInfo::callbackAvatarID, (LLPanelRegionDebugInfo*)data, _1, _2), FALSE, TRUE); } -// static -void LLPanelRegionDebugInfo::callbackAvatarID(const std::vector& names, const std::vector& ids, void* data) +void LLPanelRegionDebugInfo::callbackAvatarID(const uuid_vec_t& ids, const std::vector& names) { - LLPanelRegionDebugInfo* self = (LLPanelRegionDebugInfo*) data; if (ids.empty() || names.empty()) return; - self->mTargetAvatar = ids[0]; - self->childSetValue("target_avatar_name", LLSD(names[0])); - self->refreshFromRegion( gAgent.getRegion() ); + mTargetAvatar = ids[0]; + childSetValue("target_avatar_name", LLSD(names[0].getCompleteName())); + refreshFromRegion( gAgent.getRegion() ); } // static @@ -1615,35 +1624,35 @@ void LLPanelEstateInfo::onClickKickUser(void *user_data) // this depends on the grandparent view being a floater // in order to set up floater dependency LLFloater* parent_floater = gFloaterView->getParentFloater(panelp); - LLFloater* child_floater = LLFloaterAvatarPicker::show(LLPanelEstateInfo::onKickUserCommit, user_data, FALSE, TRUE); + LLFloater* child_floater = LLFloaterAvatarPicker::show(boost::bind(&LLPanelEstateInfo::onKickUserCommit, panelp, _1, _2), FALSE, TRUE); + if (child_floater) + { + parent_floater->addDependentFloater(child_floater); + } parent_floater->addDependentFloater(child_floater); } -void LLPanelEstateInfo::onKickUserCommit(const std::vector& names, const std::vector& ids, void* userdata) +void LLPanelEstateInfo::onKickUserCommit(const uuid_vec_t& ids, const std::vector& names) { if (names.empty() || ids.empty()) return; //check to make sure there is one valid user and id - if( (ids[0].isNull()) || - (names[0].length() == 0) ) + if( ids[0].isNull() ) { return; } - LLPanelEstateInfo* self = (LLPanelEstateInfo*)userdata; - if(!self) return; - //keep track of what user they want to kick and other misc info LLKickFromEstateInfo *kick_info = new LLKickFromEstateInfo(); - kick_info->mEstatePanelp = self; + kick_info->mEstatePanelp = this; kick_info->mAgentID = ids[0]; //Bring up a confirmation dialog LLSD args; - args["EVIL_USER"] = names[0]; + args["EVIL_USER"] = names[0].getCompleteName(); LLSD payload; payload["agent_id"] = ids[0]; - LLNotificationsUtil::add("EstateKickUser", args, payload, boost::bind(&LLPanelEstateInfo::kickUserConfirm, self, _1, _2)); + LLNotificationsUtil::add("EstateKickUser", args, payload, boost::bind(&LLPanelEstateInfo::kickUserConfirm, this, _1, _2)); } @@ -1808,14 +1817,13 @@ bool LLPanelEstateInfo::accessAddCore2(const LLSD& notification, const LLSD& res LLEstateAccessChangeInfo* change_info = new LLEstateAccessChangeInfo(notification["payload"]); // avatar picker yes multi-select, yes close-on-select - LLFloaterAvatarPicker::show(accessAddCore3, (void*)change_info, TRUE, TRUE); + LLFloaterAvatarPicker::show(boost::bind(&LLPanelEstateInfo::accessAddCore3, _1, change_info), TRUE, TRUE); return false; } // static -void LLPanelEstateInfo::accessAddCore3(const std::vector& names, const std::vector& ids, void* data) +void LLPanelEstateInfo::accessAddCore3(const uuid_vec_t& ids, LLEstateAccessChangeInfo* change_info) { - LLEstateAccessChangeInfo* change_info = (LLEstateAccessChangeInfo*)data; if (!change_info) return; if (ids.empty()) { @@ -2063,7 +2071,6 @@ void LLPanelEstateInfo::updateControls(LLViewerRegion* region) BOOL owner = (region && (region->getOwner() == gAgent.getID())); BOOL manager = (region && region->isEstateManager()); setCtrlsEnabled(god || owner || manager); - childDisable("apply_btn"); childSetEnabled("add_allowed_avatar_btn", god || owner || manager); childSetEnabled("remove_allowed_avatar_btn", god || owner || manager); @@ -2313,13 +2320,20 @@ void LLPanelEstateInfo::getEstateOwner() class LLEstateChangeInfoResponder : public LLHTTPClient::ResponderWithResult { public: - LLEstateChangeInfoResponder(void* userdata) : mpPanel((LLPanelEstateInfo*)userdata) {}; + LLEstateChangeInfoResponder(LLPanelEstateInfo* panel) + { + mpPanel = panel->getHandle(); + } // if we get a normal response, handle it here virtual void result(const LLSD& content) { + LL_INFOS("Windlight") << "Successfully committed estate info" << llendl; + // refresh the panel from the database - mpPanel->refresh(); + LLPanelEstateInfo* panel = dynamic_cast(mpPanel.get()); + if (panel) + panel->refresh(); } // if we get an error response @@ -2332,7 +2346,7 @@ public: virtual AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return estateChangeInfoResponder_timeout; } private: - LLPanelEstateInfo* mpPanel; + LLHandle mpPanel; }; // tries to send estate info using a cap; returns true if it succeeded @@ -2370,7 +2384,7 @@ bool LLPanelEstateInfo::commitEstateInfoCaps() body["owner_abuse_email"] = childGetValue("abuse_email_address").asString(); // we use a responder so that we can re-get the data after committing to the database - LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder((void*)this)); + LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder(this)); return true; } diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index c5ec3b7d6..8a3d77075 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -38,6 +38,8 @@ #include "llfloater.h" #include "llpanel.h" +class LLAvatarName; +struct LLEstateAccessChangeInfo; class LLLineEditor; class LLMessageSystem; class LLPanelRegionInfo; @@ -164,7 +166,7 @@ protected: virtual BOOL sendUpdate(); static void onClickKick(void* userdata); - static void onKickCommit(const std::vector& names, const std::vector& ids, void* userdata); + void onKickCommit(const uuid_vec_t& ids); static void onClickKickAll(void* userdata); bool onKickAllCommit(const LLSD& notification, const LLSD& response); static void onClickMessage(void* userdata); @@ -189,7 +191,7 @@ protected: virtual BOOL sendUpdate(); static void onClickChooseAvatar(void*); - static void callbackAvatarID(const std::vector& names, const std::vector& ids, void* data); + void callbackAvatarID(const uuid_vec_t& ids, const std::vector& names); static void onClickReturn(void *); bool callbackReturn(const LLSD& notification, const LLSD& response); static void onClickTopColliders(void*); @@ -282,7 +284,7 @@ public: // Core methods for all above add/remove button clicks static void accessAddCore(U32 operation_flag, const std::string& dialog_name); static bool accessAddCore2(const LLSD& notification, const LLSD& response); - static void accessAddCore3(const std::vector& names, const std::vector& ids, void* data); + static void accessAddCore3(const uuid_vec_t& ids, LLEstateAccessChangeInfo* change_info); static void accessRemoveCore(U32 operation_flag, const std::string& dialog_name, const std::string& list_ctrl_name); static bool accessRemoveCore2(const LLSD& notification, const LLSD& response); @@ -294,7 +296,7 @@ public: // Send the actual EstateOwnerRequest "estateaccessdelta" message static void sendEstateAccessDelta(U32 flags, const LLUUID& agent_id); - static void onKickUserCommit(const std::vector& names, const std::vector& ids, void* userdata); + void onKickUserCommit(const uuid_vec_t& ids, const std::vector& names); static void onClickMessageEstate(void* data); bool onMessageCommit(const LLSD& notification, const LLSD& response); diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 9952eadd3..06497b028 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -378,24 +378,21 @@ void LLFloaterReporter::onClickSelectAbuser(void *userdata) { LLFloaterReporter *self = (LLFloaterReporter *)userdata; - gFloaterView->getParentFloater(self)->addDependentFloater(LLFloaterAvatarPicker::show(callbackAvatarID, userdata, FALSE, TRUE )); + gFloaterView->getParentFloater(self)->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLFloaterReporter::callbackAvatarID, self, _1, _2), FALSE, TRUE )); } -// static -void LLFloaterReporter::callbackAvatarID(const std::vector& names, const std::vector& ids, void* data) +void LLFloaterReporter::callbackAvatarID(const uuid_vec_t& ids, const std::vector& names) { - LLFloaterReporter* self = (LLFloaterReporter*) data; - if (ids.empty() || names.empty()) return; // this should never be called in a bug report but here for safety. - if ( self->mReportType != BUG_REPORT ) + if ( mReportType != BUG_REPORT ) { - self->childSetText("abuser_name_edit", names[0] ); + childSetText("abuser_name_edit", names[0].getCompleteName() ); - self->mAbuserID = ids[0]; + mAbuserID = ids[0]; - self->refresh(); + refresh(); }; } diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h index 5f53142e4..e4d13e906 100644 --- a/indra/newview/llfloaterreporter.h +++ b/indra/newview/llfloaterreporter.h @@ -38,6 +38,7 @@ #include "lluuid.h" #include "v3math.h" +class LLAvatarName; class LLMessageSystem; class LLViewerTexture; class LLInventoryItem; @@ -126,7 +127,7 @@ private: void setPosBox(const LLVector3d &pos); void enableControls(BOOL own_avatar); void getObjectInfo(const LLUUID& object_id); - static void callbackAvatarID(const std::vector& names, const std::vector& ids, void* data); + void callbackAvatarID(const uuid_vec_t& ids, const std::vector& names); private: EReportType mReportType; diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp index dfb82dada..1b50f3ead 100644 --- a/indra/newview/llfloatersellland.cpp +++ b/indra/newview/llfloatersellland.cpp @@ -33,6 +33,7 @@ #include "llfloatersellland.h" +#include "llavatarnamecache.h" #include "llfloateravatarpicker.h" #include "llfloater.h" #include "llfloaterland.h" @@ -88,7 +89,7 @@ private: static void doShowObjects(void *userdata); static bool callbackHighlightTransferable(const LLSD& notification, const LLSD& response); - static void callbackAvatarPick(const std::vector& names, const std::vector& ids, void* data); + void callbackAvatarPick(const uuid_vec_t& ids, const std::vector& names); public: virtual BOOL postBuild(); @@ -413,25 +414,23 @@ void LLFloaterSellLandUI::doSelectAgent(void *userdata) { LLFloaterSellLandUI* floaterp = (LLFloaterSellLandUI*)userdata; // grandparent is a floater, in order to set up dependency - floaterp->addDependentFloater(LLFloaterAvatarPicker::show(callbackAvatarPick, floaterp, FALSE, TRUE)); + floaterp->addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLFloaterSellLandUI::callbackAvatarPick, floaterp, _1, _2), FALSE, TRUE)); } -// static -void LLFloaterSellLandUI::callbackAvatarPick(const std::vector& names, const std::vector& ids, void* data) +void LLFloaterSellLandUI::callbackAvatarPick(const uuid_vec_t& ids, const std::vector& names) { - LLFloaterSellLandUI* floaterp = (LLFloaterSellLandUI*)data; - LLParcel* parcel = floaterp->mParcelSelection->getParcel(); + LLParcel* parcel = mParcelSelection->getParcel(); if (names.empty() || ids.empty()) return; LLUUID id = ids[0]; parcel->setAuthorizedBuyerID(id); - floaterp->mAuthorizedBuyer = ids[0]; + mAuthorizedBuyer = ids[0]; - floaterp->childSetText("sell_to_agent", names[0]); + childSetText("sell_to_agent", names[0].getCompleteName()); - floaterp->refreshUI(); + refreshUI(); } // static diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp index f84da5d10..c9e765d7a 100644 --- a/indra/newview/llpanelgroupinvite.cpp +++ b/indra/newview/llpanelgroupinvite.cpp @@ -34,8 +34,10 @@ #include "llpanelgroupinvite.h" #include "llagent.h" +#include "llavatarnamecache.h" #include "llfloateravatarpicker.h" #include "llbutton.h" +#include "llcallingcard.h" #include "llcombobox.h" #include "llgroupmgr.h" #include "llnamelistctrl.h" @@ -54,7 +56,7 @@ public: ~impl(); void addUsers(const std::vector& names, - const std::vector& agent_ids); + const uuid_vec_t& agent_ids); void submitInvitations(); void addRoleNames(LLGroupMgrGroupData* gdatap); void handleRemove(); @@ -65,9 +67,13 @@ public: static void callbackClickAdd(void* userdata); static void callbackClickRemove(void* userdata); static void callbackSelect(LLUICtrl* ctrl, void* userdata); - static void callbackAddUsers(const std::vector& names, - const std::vector& agent_ids, + static void callbackAddUsers(const uuid_vec_t& agent_ids, void* user_data); + + static void onAvatarNameCache(const LLUUID& agent_id, + const LLAvatarName& av_name, + void* user_data); + bool inviteOwnerCallback(const LLSD& notification, const LLSD& response); public: @@ -80,6 +86,8 @@ public: LLButton *mRemoveButton; LLTextBox *mGroupName; std::string mOwnerWarning; + std::string mAlreadyInGroup; + std::string mTooManySelected; bool mConfirmedOwnerInvite; void (*mCloseCallback)(void* data); @@ -107,7 +115,7 @@ LLPanelGroupInvite::impl::~impl() } void LLPanelGroupInvite::impl::addUsers(const std::vector& names, - const std::vector& agent_ids) + const uuid_vec_t& agent_ids) { std::string name; LLUUID id; @@ -168,16 +176,40 @@ void LLPanelGroupInvite::impl::submitInvitations() } } + bool already_in_group = false; //loop over the users std::vector items = mInvitees->getAllData(); for (std::vector::iterator iter = items.begin(); iter != items.end(); ++iter) { LLScrollListItem* item = *iter; + if(gdatap->mMembers.find(item->getUUID()) != gdatap->mMembers.end()) + { + already_in_group = true; + continue; + } role_member_pairs[item->getUUID()] = role_id; } + + const S32 MAX_GROUP_INVITES = 100; // Max invites per request. 100 to match server cap. + if (role_member_pairs.size() > MAX_GROUP_INVITES) + { + // Fail! + LLSD msg; + msg["MESSAGE"] = mTooManySelected; + LLNotificationsUtil::add("GenericAlert", msg); + (*mCloseCallback)(mCloseCallbackUserData); + return; + } LLGroupMgr::getInstance()->sendGroupMemberInvites(mGroupID, role_member_pairs); + + if(already_in_group) + { + LLSD msg; + msg["MESSAGE"] = mAlreadyInGroup; + LLNotificationsUtil::add("GenericAlert", msg); + } //then close (*mCloseCallback)(mCloseCallbackUserData); @@ -185,7 +217,7 @@ void LLPanelGroupInvite::impl::submitInvitations() bool LLPanelGroupInvite::impl::inviteOwnerCallback(const LLSD& notification, const LLSD& response) { - S32 option = LLNotification::getSelectedOption(notification, response); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); switch(option) { @@ -274,12 +306,12 @@ void LLPanelGroupInvite::impl::callbackClickAdd(void* userdata) //Soon the avatar picker will be embedded into this panel //instead of being it's own separate floater. But that is next week. //This will do for now. -jwolk May 10, 2006 - LLFloater* parentp; - - parentp = gFloaterView->getParentFloater(panelp); - parentp->addDependentFloater(LLFloaterAvatarPicker::show(callbackAddUsers, - panelp->mImplementation, - TRUE)); + LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show( + boost::bind(impl::callbackAddUsers, _1, panelp->mImplementation), TRUE); + if (picker) + { + gFloaterView->getParentFloater(panelp)->addDependentFloater(picker); + } } } @@ -343,26 +375,43 @@ void LLPanelGroupInvite::impl::callbackClickOK(void* userdata) if ( selfp ) selfp->submitInvitations(); } + + //static -void LLPanelGroupInvite::impl::callbackAddUsers(const std::vector& names, - const std::vector& ids, - void* user_data) +void LLPanelGroupInvite::impl::callbackAddUsers(const uuid_vec_t& agent_ids, void* user_data) +{ + std::vector names; + for (S32 i = 0; i < (S32)agent_ids.size(); i++) + { + LLAvatarNameCache::get(agent_ids[i], + boost::bind(&LLPanelGroupInvite::impl::onAvatarNameCache, _1, _2, user_data)); + } + +} + +void LLPanelGroupInvite::impl::onAvatarNameCache(const LLUUID& agent_id, + const LLAvatarName& av_name, + void* user_data) { impl* selfp = (impl*) user_data; - if ( selfp) selfp->addUsers(names, ids); + if (selfp) + { + std::vector names; + uuid_vec_t agent_ids; + agent_ids.push_back(agent_id); + names.push_back(av_name.getCompleteName()); + + selfp->addUsers(names, agent_ids); + } } LLPanelGroupInvite::LLPanelGroupInvite(const std::string& name, const LLUUID& group_id) - : LLPanel(name) + : LLPanel(name), + mImplementation(new impl(group_id)), + mPendingUpdate(FALSE) { - mImplementation = new impl(group_id); - mPendingUpdate = FALSE; - mStoreSelected = LLUUID::null; - - std::string panel_def_file; - // Pass on construction of this panel to the control factory. LLUICtrlFactory::getInstance()->buildPanel(this, "panel_group_invite.xml", &getFactoryMap()); } @@ -388,18 +437,72 @@ void LLPanelGroupInvite::clear() mImplementation->mOKButton->setEnabled(FALSE); } -void LLPanelGroupInvite::addUsers(std::vector& agent_ids) +void LLPanelGroupInvite::addUsers(uuid_vec_t& agent_ids) { std::vector names; for (S32 i = 0; i < (S32)agent_ids.size(); i++) { - std::string name; - if(gCacheName->getFullName(agent_ids[i], name)) - names.push_back(name); + std::string fullname; + LLUUID agent_id = agent_ids[i]; + LLViewerObject* dest = gObjectList.findObject(agent_id); + if(dest && dest->isAvatar()) + { + LLNameValue* nvfirst = dest->getNVPair("FirstName"); + LLNameValue* nvlast = dest->getNVPair("LastName"); + if(nvfirst && nvlast) + { + fullname = LLCacheName::buildFullName( + nvfirst->getString(), nvlast->getString()); + + } + if (!fullname.empty()) + { + names.push_back(fullname); + } + else + { + llwarns << "llPanelGroupInvite: Selected avatar has no name: " << dest->getID() << llendl; + names.push_back("(Unknown)"); + } + } + else + { + //looks like user try to invite offline friend + //for offline avatar_id gObjectList.findObject() will return null + //so we need to do this additional search in avatar tracker, see EXT-4732 + if (LLAvatarTracker::instance().isBuddy(agent_id)) + { + LLAvatarName av_name; + if (!LLAvatarNameCache::get(agent_id, &av_name)) + { + // actually it should happen, just in case + LLAvatarNameCache::get(LLUUID(agent_id), boost::bind( + &LLPanelGroupInvite::addUserCallback, this, _1, _2)); + // for this special case! + //when there is no cached name we should remove resident from agent_ids list to avoid breaking of sequence + // removed id will be added in callback + agent_ids.erase(agent_ids.begin() + i); + } + else + { + names.push_back(av_name.getLegacyName()); + } + } + } } mImplementation->addUsers(names, agent_ids); } +void LLPanelGroupInvite::addUserCallback(const LLUUID& id, const LLAvatarName& av_name) +{ + std::vector names; + uuid_vec_t agent_ids; + agent_ids.push_back(id); + names.push_back(av_name.getLegacyName()); + + mImplementation->addUsers(names, agent_ids); +} + void LLPanelGroupInvite::draw() { LLPanel::draw(); @@ -500,9 +603,8 @@ BOOL LLPanelGroupInvite::postBuild() getChild("invitee_list", recurse); if ( mImplementation->mInvitees ) { - mImplementation->mInvitees->setCallbackUserData(mImplementation); mImplementation->mInvitees->setCommitOnSelectionChange(TRUE); - mImplementation->mInvitees->setCommitCallback(impl::callbackSelect); + mImplementation->mInvitees->setCommitCallback(impl::callbackSelect, mImplementation); } LLButton* button = getChild("add_button", recurse); @@ -510,14 +612,14 @@ BOOL LLPanelGroupInvite::postBuild() { // default to opening avatarpicker automatically // (*impl::callbackClickAdd)((void*)this); - button->setClickedCallback(boost::bind(&impl::callbackClickAdd, this)); + button->setClickedCallback(impl::callbackClickAdd, this); } mImplementation->mRemoveButton = getChild("remove_button", recurse); if ( mImplementation->mRemoveButton ) { - mImplementation->mRemoveButton->setClickedCallback(boost::bind(&impl::callbackClickRemove, mImplementation)); + mImplementation->mRemoveButton->setClickedCallback(impl::callbackClickRemove, mImplementation); mImplementation->mRemoveButton->setEnabled(FALSE); } @@ -525,17 +627,19 @@ BOOL LLPanelGroupInvite::postBuild() getChild("ok_button", recurse); if ( mImplementation->mOKButton ) { - mImplementation->mOKButton->setClickedCallback(boost::bind(&impl::callbackClickOK, mImplementation)); + mImplementation->mOKButton->setClickedCallback(impl::callbackClickOK, mImplementation); mImplementation->mOKButton->setEnabled(FALSE); } button = getChild("cancel_button", recurse); if ( button ) { - button->setClickedCallback(boost::bind(&impl::callbackClickCancel,mImplementation)); + button->setClickedCallback(impl::callbackClickCancel, mImplementation); } mImplementation->mOwnerWarning = getString("confirm_invite_owner_str"); + mImplementation->mAlreadyInGroup = getString("already_in_group"); + mImplementation->mTooManySelected = getString("invite_selection_too_large"); update(); diff --git a/indra/newview/llpanelgroupinvite.h b/indra/newview/llpanelgroupinvite.h index 9117b83e7..b296e3dd4 100644 --- a/indra/newview/llpanelgroupinvite.h +++ b/indra/newview/llpanelgroupinvite.h @@ -35,6 +35,7 @@ #include "llpanel.h" #include "lluuid.h" +class LLAvatarName; class LLPanelGroupInvite : public LLPanel { @@ -42,7 +43,11 @@ public: LLPanelGroupInvite(const std::string& name, const LLUUID& group_id); ~LLPanelGroupInvite(); - void addUsers(std::vector& agent_ids); + void addUsers(uuid_vec_t& agent_ids); + /** + * this callback is being used to add a user whose fullname isn't been loaded before invoking of addUsers(). + */ + void addUserCallback(const LLUUID& id, const LLAvatarName& av_name); void clear(); void update(); diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 9ed016d71..9c18486cc 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -120,7 +120,7 @@ LLViewerParcelMgr::LLViewerParcelMgr() mRequestResult(0), mWestSouth(), mEastNorth(), - mSelectedDwell(0.f), + mSelectedDwell(DWELL_NAN), mAgentParcelSequenceID(-1), mHoverRequestResult(0), mHoverWestSouth(), @@ -244,7 +244,7 @@ void LLViewerParcelMgr::getDisplayInfo(S32* area_out, S32* claim_out, S32 price = 0; S32 rent = 0; BOOL for_sale = FALSE; - F32 dwell = 0.f; + F32 dwell = DWELL_NAN; if (mSelected) { @@ -590,7 +590,7 @@ void LLViewerParcelMgr::deselectLand() mCurrentParcel->mBanList.clear(); //mCurrentParcel->mRenterList.reset(); - mSelectedDwell = 0.f; + mSelectedDwell = DWELL_NAN; // invalidate parcel selection so that existing users of this selection can clean up mCurrentParcelSelection->setParcel(NULL); @@ -1679,7 +1679,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use parcel_mgr.sendParcelAccessListRequest(AL_ACCESS | AL_BAN); // Request dwell for this land, if it's not public land. - parcel_mgr.mSelectedDwell = 0.f; + parcel_mgr.mSelectedDwell = DWELL_NAN; if (0 != local_id) { parcel_mgr.sendParcelDwellRequest(); diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 49571f80a..5ae44e2d0 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -46,6 +46,8 @@ class LLParcel; class LLViewerTexture; class LLViewerRegion; +const F32 DWELL_NAN = -1.0f; // A dwell having this value will be displayed as Loading... + // Constants for sendLandOwner //const U32 NO_NEIGHBOR_JOIN = 0x0; //const U32 ALL_NEIGHBOR_JOIN = U32( NORTH_MASK diff --git a/indra/newview/skins/default/xui/en-us/panel_group_invite.xml b/indra/newview/skins/default/xui/en-us/panel_group_invite.xml index 74d71f497..7d24eff4a 100644 --- a/indra/newview/skins/default/xui/en-us/panel_group_invite.xml +++ b/indra/newview/skins/default/xui/en-us/panel_group_invite.xml @@ -32,6 +32,12 @@ Resident Chooser' to start. Are you sure you want to invite new owner(s)? This action is permanent! + + Some Residents you chose are already in the group, and so were not sent an invitation. + + + Group Invitations not sent: too many Residents selected. Group Invitations are limited to 100 per request. +