diff options
Diffstat (limited to 'indra/newview/llfloateravatarpicker.cpp')
-rw-r--r-- | indra/newview/llfloateravatarpicker.cpp | 1628 |
1 files changed, 814 insertions, 814 deletions
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index 22dc17e217..6087e6c0ee 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -1,814 +1,814 @@ -/**
- * @file llfloateravatarpicker.cpp
- *
- * $LicenseInfo:firstyear=2003&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 "llfloateravatarpicker.h"
-
-// Viewer includes
-#include "llagent.h"
-#include "llcallingcard.h"
-#include "llfocusmgr.h"
-#include "llfloaterreg.h"
-#include "llimview.h" // for gIMMgr
-#include "lltooldraganddrop.h" // for LLToolDragAndDrop
-#include "llviewercontrol.h"
-#include "llviewerregion.h" // getCapability()
-#include "llworld.h"
-
-// Linden libraries
-#include "llavatarnamecache.h" // IDEVO
-#include "llbutton.h"
-#include "llcachename.h"
-#include "lllineeditor.h"
-#include "llscrolllistctrl.h"
-#include "llscrolllistitem.h"
-#include "llscrolllistcell.h"
-#include "lltabcontainer.h"
-#include "lluictrlfactory.h"
-#include "llfocusmgr.h"
-#include "lldraghandle.h"
-#include "message.h"
-#include "llcorehttputil.h"
-
-//#include "llsdserialize.h"
-
-static const U32 AVATAR_PICKER_SEARCH_TIMEOUT = 180U;
-
-//put it back as a member once the legacy path is out?
-static std::map<LLUUID, LLAvatarName> sAvatarNameMap;
-
-LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(select_callback_t callback,
- bool allow_multiple,
- 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 =
- LLFloaterReg::showTypedInstance<LLFloaterAvatarPicker>("avatar_picker", LLSD(name));
- if (!floater)
- {
- LL_WARNS() << "Cannot instantiate avatar picker" << LL_ENDL;
- return NULL;
- }
-
- floater->mSelectionCallback = callback;
- floater->setAllowMultiple(allow_multiple);
- floater->mNearMeListComplete = false;
- floater->mCloseOnSelect = closeOnSelect;
- floater->mExcludeAgentFromSearchResults = skip_agent;
-
- if (!closeOnSelect)
- {
- // Use Select/Close
- std::string select_string = floater->getString("Select");
- std::string close_string = floater->getString("Close");
- floater->getChild<LLButton>("ok_btn")->setLabel(select_string);
- floater->getChild<LLButton>("cancel_btn")->setLabel(close_string);
- }
-
- if(frustumOrigin)
- {
- floater->mFrustumOrigin = frustumOrigin->getHandle();
- }
-
- return floater;
-}
-
-// Default constructor
-LLFloaterAvatarPicker::LLFloaterAvatarPicker(const LLSD& key)
- : LLFloater(key),
- mNumResultsReturned(0),
- mNearMeListComplete(false),
- mCloseOnSelect(false),
- mExcludeAgentFromSearchResults(false),
- mContextConeOpacity (0.f),
- mContextConeInAlpha(CONTEXT_CONE_IN_ALPHA),
- mContextConeOutAlpha(CONTEXT_CONE_OUT_ALPHA),
- mContextConeFadeTime(CONTEXT_CONE_FADE_TIME)
-{
- mCommitCallbackRegistrar.add("Refresh.FriendList", boost::bind(&LLFloaterAvatarPicker::populateFriend, this));
-}
-
-bool LLFloaterAvatarPicker::postBuild()
-{
- getChild<LLLineEditor>("Edit")->setKeystrokeCallback( boost::bind(&LLFloaterAvatarPicker::editKeystroke, this, _1, _2),NULL);
-
- childSetAction("Find", boost::bind(&LLFloaterAvatarPicker::onBtnFind, this));
- getChildView("Find")->setEnabled(false);
- childSetAction("Refresh", boost::bind(&LLFloaterAvatarPicker::onBtnRefresh, this));
- getChild<LLUICtrl>("near_me_range")->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onRangeAdjust, this));
-
- LLScrollListCtrl* searchresults = getChild<LLScrollListCtrl>("SearchResults");
- searchresults->setDoubleClickCallback( boost::bind(&LLFloaterAvatarPicker::onBtnSelect, this));
- searchresults->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onList, this));
- getChildView("SearchResults")->setEnabled(false);
-
- LLScrollListCtrl* nearme = getChild<LLScrollListCtrl>("NearMe");
- nearme->setDoubleClickCallback(boost::bind(&LLFloaterAvatarPicker::onBtnSelect, this));
- nearme->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onList, this));
-
- LLScrollListCtrl* friends = getChild<LLScrollListCtrl>("Friends");
- friends->setDoubleClickCallback(boost::bind(&LLFloaterAvatarPicker::onBtnSelect, this));
- getChild<LLUICtrl>("Friends")->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onList, this));
-
- childSetAction("ok_btn", boost::bind(&LLFloaterAvatarPicker::onBtnSelect, this));
- getChildView("ok_btn")->setEnabled(false);
- childSetAction("cancel_btn", boost::bind(&LLFloaterAvatarPicker::onBtnClose, this));
-
- getChild<LLUICtrl>("Edit")->setFocus(true);
-
- LLPanel* search_panel = getChild<LLPanel>("SearchPanel");
- if (search_panel)
- {
- // Start searching when Return is pressed in the line editor.
- search_panel->setDefaultBtn("Find");
- }
-
- getChild<LLScrollListCtrl>("SearchResults")->setCommentText(getString("no_results"));
-
- getChild<LLTabContainer>("ResidentChooserTabs")->setCommitCallback(
- boost::bind(&LLFloaterAvatarPicker::onTabChanged, this));
-
- setAllowMultiple(false);
-
- center();
-
- populateFriend();
-
- return true;
-}
-
-void LLFloaterAvatarPicker::setOkBtnEnableCb(validate_callback_t cb)
-{
- mOkButtonValidateSignal.connect(cb);
-}
-
-void LLFloaterAvatarPicker::onTabChanged()
-{
- getChildView("ok_btn")->setEnabled(isSelectBtnEnabled());
-}
-
-// Destroys the object
-LLFloaterAvatarPicker::~LLFloaterAvatarPicker()
-{
- gFocusMgr.releaseFocusIfNeeded( this );
-}
-
-void LLFloaterAvatarPicker::onBtnFind()
-{
- find();
-}
-
-static void getSelectedAvatarData(const LLScrollListCtrl* from, uuid_vec_t& avatar_ids, std::vector<LLAvatarName>& avatar_names)
-{
- std::vector<LLScrollListItem*> items = from->getAllSelected();
- for (std::vector<LLScrollListItem*>::iterator iter = items.begin(); iter != items.end(); ++iter)
- {
- LLScrollListItem* item = *iter;
- if (item->getUUID().notNull())
- {
- avatar_ids.push_back(item->getUUID());
-
- std::map<LLUUID, LLAvatarName>::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()
-{
-
- // If select btn not enabled then do not callback
- if (!isSelectBtnEnabled())
- return;
-
- if(mSelectionCallback)
- {
- std::string acvtive_panel_name;
- LLScrollListCtrl* list = NULL;
- LLPanel* active_panel = getChild<LLTabContainer>("ResidentChooserTabs")->getCurrentPanel();
- if(active_panel)
- {
- acvtive_panel_name = active_panel->getName();
- }
- if(acvtive_panel_name == "SearchPanel")
- {
- list = getChild<LLScrollListCtrl>("SearchResults");
- }
- else if(acvtive_panel_name == "NearMePanel")
- {
- list = getChild<LLScrollListCtrl>("NearMe");
- }
- else if (acvtive_panel_name == "FriendsPanel")
- {
- list = getChild<LLScrollListCtrl>("Friends");
- }
-
- if(list)
- {
- uuid_vec_t avatar_ids;
- std::vector<LLAvatarName> avatar_names;
- getSelectedAvatarData(list, avatar_ids, avatar_names);
- mSelectionCallback(avatar_ids, avatar_names);
- }
- }
- getChild<LLScrollListCtrl>("SearchResults")->deselectAllItems(true);
- getChild<LLScrollListCtrl>("NearMe")->deselectAllItems(true);
- getChild<LLScrollListCtrl>("Friends")->deselectAllItems(true);
- if(mCloseOnSelect)
- {
- mCloseOnSelect = false;
- closeFloater();
- }
-}
-
-void LLFloaterAvatarPicker::onBtnRefresh()
-{
- getChild<LLScrollListCtrl>("NearMe")->deleteAllItems();
- getChild<LLScrollListCtrl>("NearMe")->setCommentText(getString("searching"));
- mNearMeListComplete = false;
-}
-
-void LLFloaterAvatarPicker::onBtnClose()
-{
- closeFloater();
-}
-
-void LLFloaterAvatarPicker::onRangeAdjust()
-{
- onBtnRefresh();
-}
-
-void LLFloaterAvatarPicker::onList()
-{
- getChildView("ok_btn")->setEnabled(isSelectBtnEnabled());
-}
-
-void LLFloaterAvatarPicker::populateNearMe()
-{
- bool all_loaded = true;
- bool empty = true;
- LLScrollListCtrl* near_me_scroller = getChild<LLScrollListCtrl>("NearMe");
- near_me_scroller->deleteAllItems();
-
- uuid_vec_t avatar_ids;
- LLWorld::getInstance()->getAvatars(&avatar_ids, NULL, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange"));
- for(U32 i=0; i<avatar_ids.size(); i++)
- {
- LLUUID& av = avatar_ids[i];
- if(mExcludeAgentFromSearchResults && (av == gAgent.getID())) continue;
- LLSD element;
- element["id"] = av; // value
- 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]["column"] = "name";
- element["columns"][0]["value"] = av_name.getDisplayName();
- element["columns"][1]["column"] = "username";
- element["columns"][1]["value"] = av_name.getUserName();
-
- sAvatarNameMap[av] = av_name;
- }
- near_me_scroller->addElement(element);
- empty = false;
- }
-
- if (empty)
- {
- getChildView("NearMe")->setEnabled(false);
- getChildView("ok_btn")->setEnabled(false);
- near_me_scroller->setCommentText(getString("no_one_near"));
- }
- else
- {
- getChildView("NearMe")->setEnabled(true);
- getChildView("ok_btn")->setEnabled(true);
- near_me_scroller->selectFirstItem();
- onList();
- near_me_scroller->setFocus(true);
- }
-
- if (all_loaded)
- {
- mNearMeListComplete = true;
- }
-}
-
-void LLFloaterAvatarPicker::populateFriend()
-{
- LLScrollListCtrl* friends_scroller = getChild<LLScrollListCtrl>("Friends");
- friends_scroller->deleteAllItems();
- LLCollectAllBuddies collector;
- LLAvatarTracker::instance().applyFunctor(collector);
- LLCollectAllBuddies::buddy_map_t::iterator it;
-
- for(it = collector.mOnline.begin(); it!=collector.mOnline.end(); it++)
- {
- friends_scroller->addStringUUIDItem(it->second, it->first);
- }
- for(it = collector.mOffline.begin(); it!=collector.mOffline.end(); it++)
- {
- friends_scroller->addStringUUIDItem(it->second, it->first);
- }
- friends_scroller->sortByColumnIndex(0, true);
-}
-
-void LLFloaterAvatarPicker::drawFrustum()
-{
- static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f);
- drawConeToOwner(mContextConeOpacity, max_opacity, mFrustumOrigin.get(), mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha);
-}
-
-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;
- if (timer.hasExpired())
- {
- timer.setTimerExpirySec(0.33f); // three times per second should be enough.
-
- // simulate list changes.
- onList();
- timer.start();
- }
-
- LLFloater::draw();
- if (!mNearMeListComplete && getChild<LLTabContainer>("ResidentChooserTabs")->getCurrentPanel() == getChild<LLPanel>("NearMePanel"))
- {
- populateNearMe();
- }
-}
-
-bool LLFloaterAvatarPicker::visibleItemsSelected() const
-{
- LLPanel* active_panel = getChild<LLTabContainer>("ResidentChooserTabs")->getCurrentPanel();
-
- if(active_panel == getChild<LLPanel>("SearchPanel"))
- {
- return getChild<LLScrollListCtrl>("SearchResults")->getFirstSelectedIndex() >= 0;
- }
- else if(active_panel == getChild<LLPanel>("NearMePanel"))
- {
- return getChild<LLScrollListCtrl>("NearMe")->getFirstSelectedIndex() >= 0;
- }
- else if(active_panel == getChild<LLPanel>("FriendsPanel"))
- {
- return getChild<LLScrollListCtrl>("Friends")->getFirstSelectedIndex() >= 0;
- }
- return false;
-}
-
-/*static*/
-void LLFloaterAvatarPicker::findCoro(std::string url, LLUUID queryID, std::string name)
-{
- LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
- LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
- httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy));
- LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
- LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
-
- LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL;
-
- httpOpts->setTimeout(AVATAR_PICKER_SEARCH_TIMEOUT);
-
- LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts);
-
- LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
- LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
-
- if (status || (status == LLCore::HttpStatus(HTTP_BAD_REQUEST)))
- {
- result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS);
- }
- else
- {
- result["failure_reason"] = status.toString();
- }
-
- LLFloaterAvatarPicker* floater =
- LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", name);
- if (floater)
- {
- floater->processResponse(queryID, result);
- }
-}
-
-
-void LLFloaterAvatarPicker::find()
-{
- //clear our stored LLAvatarNames
- sAvatarNameMap.clear();
-
- std::string text = getChild<LLUICtrl>("Edit")->getValue().asString();
-
- size_t separator_index = text.find_first_of(" ._");
- if (separator_index != text.npos)
- {
- std::string first = text.substr(0, separator_index);
- std::string last = text.substr(separator_index+1, text.npos);
- LLStringUtil::trim(last);
- if("Resident" == last)
- {
- text = first;
- }
- }
-
- mQueryID.generate();
-
- std::string url;
- url.reserve(128); // avoid a memory allocation or two
-
- LLViewerRegion* region = gAgent.getRegion();
- if(region)
- {
- url = region->getCapability("AvatarPickerSearch");
- // Prefer use of capabilities to search on both SLID and display name
- if (!url.empty())
- {
- // 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=";
- std::replace(text.begin(), text.end(), '.', ' ');
- url += LLURI::escape(text);
- LL_INFOS() << "avatar picker " << url << LL_ENDL;
-
- LLCoros::instance().launch("LLFloaterAvatarPicker::findCoro",
- boost::bind(&LLFloaterAvatarPicker::findCoro, url, mQueryID, getKey().asString()));
- }
- 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<LLScrollListCtrl>("SearchResults")->deleteAllItems();
- getChild<LLScrollListCtrl>("SearchResults")->setCommentText(getString("searching"));
-
- getChildView("ok_btn")->setEnabled(false);
- mNumResultsReturned = 0;
-}
-
-void LLFloaterAvatarPicker::setAllowMultiple(bool allow_multiple)
-{
- getChild<LLScrollListCtrl>("SearchResults")->setAllowMultipleSelection(allow_multiple);
- getChild<LLScrollListCtrl>("NearMe")->setAllowMultipleSelection(allow_multiple);
- getChild<LLScrollListCtrl>("Friends")->setAllowMultipleSelection(allow_multiple);
-}
-
-LLScrollListCtrl* LLFloaterAvatarPicker::getActiveList()
-{
- std::string acvtive_panel_name;
- LLScrollListCtrl* list = NULL;
- LLPanel* active_panel = getChild<LLTabContainer>("ResidentChooserTabs")->getCurrentPanel();
- if(active_panel)
- {
- acvtive_panel_name = active_panel->getName();
- }
- if(acvtive_panel_name == "SearchPanel")
- {
- list = getChild<LLScrollListCtrl>("SearchResults");
- }
- else if(acvtive_panel_name == "NearMePanel")
- {
- list = getChild<LLScrollListCtrl>("NearMe");
- }
- else if (acvtive_panel_name == "FriendsPanel")
- {
- list = getChild<LLScrollListCtrl>("Friends");
- }
- return list;
-}
-
-bool LLFloaterAvatarPicker::handleDragAndDrop(S32 x, S32 y, MASK mask,
- bool drop, EDragAndDropType cargo_type,
- void *cargo_data, EAcceptance *accept,
- std::string& tooltip_msg)
-{
- LLScrollListCtrl* list = getActiveList();
- if(list)
- {
- LLRect rc_list;
- LLRect rc_point(x,y,x,y);
- if (localRectToOtherView(rc_point, &rc_list, list))
- {
- // Keep selected only one item
- list->deselectAllItems(true);
- list->selectItemAt(rc_list.mLeft, rc_list.mBottom, mask);
- LLScrollListItem* selection = list->getFirstSelected();
- if (selection)
- {
- LLUUID session_id = LLUUID::null;
- LLUUID dest_agent_id = selection->getUUID();
- std::string avatar_name = selection->getColumn(0)->getValue().asString();
- if (dest_agent_id.notNull() && dest_agent_id != gAgentID)
- {
- if (drop)
- {
- // Start up IM before give the item
- session_id = gIMMgr->addSession(avatar_name, IM_NOTHING_SPECIAL, dest_agent_id);
- }
- return LLToolDragAndDrop::handleGiveDragAndDrop(dest_agent_id, session_id, drop,
- cargo_type, cargo_data, accept, getName());
- }
- }
- }
- }
- *accept = ACCEPT_NO;
- return true;
-}
-
-
-void LLFloaterAvatarPicker::openFriendsTab()
-{
- LLTabContainer* tab_container = getChild<LLTabContainer>("ResidentChooserTabs");
- if (tab_container == NULL)
- {
- llassert(tab_container != NULL);
- return;
- }
-
- tab_container->selectTabByName("FriendsPanel");
-}
-
-// static
-void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void**)
-{
- LLUUID agent_id;
- LLUUID query_id;
- LLUUID avatar_id;
- std::string first_name;
- std::string last_name;
-
- msg->getUUID("AgentData", "AgentID", agent_id);
- msg->getUUID("AgentData", "QueryID", query_id);
-
- // Not for us
- if (agent_id != gAgent.getID()) return;
-
- LLFloaterAvatarPicker* floater = LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker");
-
- // floater is closed or these are not results from our last request
- if (NULL == floater || query_id != floater->mQueryID)
- {
- return;
- }
-
- LLScrollListCtrl* search_results = floater->getChild<LLScrollListCtrl>("SearchResults");
-
- // clear "Searching" label on first results
- if (floater->mNumResultsReturned++ == 0)
- {
- search_results->deleteAllItems();
- }
-
- bool found_one = false;
- S32 num_new_rows = msg->getNumberOfBlocks("Data");
- for (S32 i = 0; i < num_new_rows; i++)
- {
- 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);
-
- 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<LLUICtrl>("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.fromString(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);
- }
- }
-
- if (found_one)
- {
- floater->getChildView("ok_btn")->setEnabled(true);
- search_results->selectFirstItem();
- 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)
- {
- LLScrollListCtrl* search_results = getChild<LLScrollListCtrl>("SearchResults");
-
- // clear "Searching" label on first results
- search_results->deleteAllItems();
-
- if (content.has("failure_reason"))
- {
- getChild<LLScrollListCtrl>("SearchResults")->setCommentText(content["failure_reason"].asString());
- getChildView("ok_btn")->setEnabled(false);
- }
- else
- {
- LLSD agents = content["agents"];
-
- LLSD item;
- LLSD::array_const_iterator it = agents.beginArray();
- for (; it != agents.endArray(); ++it)
- {
- const LLSD& row = *it;
- 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;
- }
- }
-
- if (search_results->isEmpty())
- {
- std::string name = "'" + getChild<LLUICtrl>("Edit")->getValue().asString() + "'";
- LLSD item;
- item["id"] = LLUUID::null;
- item["columns"][0]["column"] = "name";
- item["columns"][0]["value"] = name;
- item["columns"][1]["column"] = "username";
- item["columns"][1]["value"] = getString("not_found_text");
- search_results->addElement(item);
- search_results->setEnabled(false);
- getChildView("ok_btn")->setEnabled(false);
- }
- else
- {
- getChildView("ok_btn")->setEnabled(true);
- search_results->setEnabled(true);
- search_results->sortByColumnIndex(1, true);
- std::string text = getChild<LLUICtrl>("Edit")->getValue().asString();
- if (!search_results->selectItemByLabel(text, true, 1))
- {
- search_results->selectFirstItem();
- }
- onList();
- search_results->setFocus(true);
- }
- }
- }
-}
-
-void LLFloaterAvatarPicker::editKeystroke(LLLineEditor* caller, void* user_data)
-{
- getChildView("Find")->setEnabled(caller->getText().size() > 0);
-}
-
-// virtual
-bool LLFloaterAvatarPicker::handleKeyHere(KEY key, MASK mask)
-{
- if (key == KEY_RETURN && mask == MASK_NONE)
- {
- if (getChild<LLUICtrl>("Edit")->hasFocus())
- {
- onBtnFind();
- }
- else
- {
- onBtnSelect();
- }
- return true;
- }
- else if (key == KEY_ESCAPE && mask == MASK_NONE)
- {
- closeFloater();
- return true;
- }
-
- return LLFloater::handleKeyHere(key, mask);
-}
-
-bool LLFloaterAvatarPicker::isSelectBtnEnabled()
-{
- bool ret_val = visibleItemsSelected();
-
- if ( ret_val && !isMinimized())
- {
- std::string acvtive_panel_name;
- LLScrollListCtrl* list = NULL;
- LLPanel* active_panel = getChild<LLTabContainer>("ResidentChooserTabs")->getCurrentPanel();
-
- if(active_panel)
- {
- acvtive_panel_name = active_panel->getName();
- }
-
- if(acvtive_panel_name == "SearchPanel")
- {
- list = getChild<LLScrollListCtrl>("SearchResults");
- }
- else if(acvtive_panel_name == "NearMePanel")
- {
- list = getChild<LLScrollListCtrl>("NearMe");
- }
- else if (acvtive_panel_name == "FriendsPanel")
- {
- list = getChild<LLScrollListCtrl>("Friends");
- }
-
- if(list)
- {
- uuid_vec_t avatar_ids;
- std::vector<LLAvatarName> avatar_names;
- getSelectedAvatarData(list, avatar_ids, avatar_names);
- if (avatar_ids.size() >= 1)
- {
- ret_val = mOkButtonValidateSignal.num_slots()?mOkButtonValidateSignal(avatar_ids):true;
- }
- else
- {
- ret_val = false;
- }
- }
- }
-
- return ret_val;
-}
+/** + * @file llfloateravatarpicker.cpp + * + * $LicenseInfo:firstyear=2003&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 "llfloateravatarpicker.h" + +// Viewer includes +#include "llagent.h" +#include "llcallingcard.h" +#include "llfocusmgr.h" +#include "llfloaterreg.h" +#include "llimview.h" // for gIMMgr +#include "lltooldraganddrop.h" // for LLToolDragAndDrop +#include "llviewercontrol.h" +#include "llviewerregion.h" // getCapability() +#include "llworld.h" + +// Linden libraries +#include "llavatarnamecache.h" // IDEVO +#include "llbutton.h" +#include "llcachename.h" +#include "lllineeditor.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "llscrolllistcell.h" +#include "lltabcontainer.h" +#include "lluictrlfactory.h" +#include "llfocusmgr.h" +#include "lldraghandle.h" +#include "message.h" +#include "llcorehttputil.h" + +//#include "llsdserialize.h" + +static const U32 AVATAR_PICKER_SEARCH_TIMEOUT = 180U; + +//put it back as a member once the legacy path is out? +static std::map<LLUUID, LLAvatarName> sAvatarNameMap; + +LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(select_callback_t callback, + bool allow_multiple, + 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 = + LLFloaterReg::showTypedInstance<LLFloaterAvatarPicker>("avatar_picker", LLSD(name)); + if (!floater) + { + LL_WARNS() << "Cannot instantiate avatar picker" << LL_ENDL; + return NULL; + } + + floater->mSelectionCallback = callback; + floater->setAllowMultiple(allow_multiple); + floater->mNearMeListComplete = false; + floater->mCloseOnSelect = closeOnSelect; + floater->mExcludeAgentFromSearchResults = skip_agent; + + if (!closeOnSelect) + { + // Use Select/Close + std::string select_string = floater->getString("Select"); + std::string close_string = floater->getString("Close"); + floater->getChild<LLButton>("ok_btn")->setLabel(select_string); + floater->getChild<LLButton>("cancel_btn")->setLabel(close_string); + } + + if(frustumOrigin) + { + floater->mFrustumOrigin = frustumOrigin->getHandle(); + } + + return floater; +} + +// Default constructor +LLFloaterAvatarPicker::LLFloaterAvatarPicker(const LLSD& key) + : LLFloater(key), + mNumResultsReturned(0), + mNearMeListComplete(false), + mCloseOnSelect(false), + mExcludeAgentFromSearchResults(false), + mContextConeOpacity (0.f), + mContextConeInAlpha(CONTEXT_CONE_IN_ALPHA), + mContextConeOutAlpha(CONTEXT_CONE_OUT_ALPHA), + mContextConeFadeTime(CONTEXT_CONE_FADE_TIME) +{ + mCommitCallbackRegistrar.add("Refresh.FriendList", boost::bind(&LLFloaterAvatarPicker::populateFriend, this)); +} + +bool LLFloaterAvatarPicker::postBuild() +{ + getChild<LLLineEditor>("Edit")->setKeystrokeCallback( boost::bind(&LLFloaterAvatarPicker::editKeystroke, this, _1, _2),NULL); + + childSetAction("Find", boost::bind(&LLFloaterAvatarPicker::onBtnFind, this)); + getChildView("Find")->setEnabled(false); + childSetAction("Refresh", boost::bind(&LLFloaterAvatarPicker::onBtnRefresh, this)); + getChild<LLUICtrl>("near_me_range")->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onRangeAdjust, this)); + + LLScrollListCtrl* searchresults = getChild<LLScrollListCtrl>("SearchResults"); + searchresults->setDoubleClickCallback( boost::bind(&LLFloaterAvatarPicker::onBtnSelect, this)); + searchresults->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onList, this)); + getChildView("SearchResults")->setEnabled(false); + + LLScrollListCtrl* nearme = getChild<LLScrollListCtrl>("NearMe"); + nearme->setDoubleClickCallback(boost::bind(&LLFloaterAvatarPicker::onBtnSelect, this)); + nearme->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onList, this)); + + LLScrollListCtrl* friends = getChild<LLScrollListCtrl>("Friends"); + friends->setDoubleClickCallback(boost::bind(&LLFloaterAvatarPicker::onBtnSelect, this)); + getChild<LLUICtrl>("Friends")->setCommitCallback(boost::bind(&LLFloaterAvatarPicker::onList, this)); + + childSetAction("ok_btn", boost::bind(&LLFloaterAvatarPicker::onBtnSelect, this)); + getChildView("ok_btn")->setEnabled(false); + childSetAction("cancel_btn", boost::bind(&LLFloaterAvatarPicker::onBtnClose, this)); + + getChild<LLUICtrl>("Edit")->setFocus(true); + + LLPanel* search_panel = getChild<LLPanel>("SearchPanel"); + if (search_panel) + { + // Start searching when Return is pressed in the line editor. + search_panel->setDefaultBtn("Find"); + } + + getChild<LLScrollListCtrl>("SearchResults")->setCommentText(getString("no_results")); + + getChild<LLTabContainer>("ResidentChooserTabs")->setCommitCallback( + boost::bind(&LLFloaterAvatarPicker::onTabChanged, this)); + + setAllowMultiple(false); + + center(); + + populateFriend(); + + return true; +} + +void LLFloaterAvatarPicker::setOkBtnEnableCb(validate_callback_t cb) +{ + mOkButtonValidateSignal.connect(cb); +} + +void LLFloaterAvatarPicker::onTabChanged() +{ + getChildView("ok_btn")->setEnabled(isSelectBtnEnabled()); +} + +// Destroys the object +LLFloaterAvatarPicker::~LLFloaterAvatarPicker() +{ + gFocusMgr.releaseFocusIfNeeded( this ); +} + +void LLFloaterAvatarPicker::onBtnFind() +{ + find(); +} + +static void getSelectedAvatarData(const LLScrollListCtrl* from, uuid_vec_t& avatar_ids, std::vector<LLAvatarName>& avatar_names) +{ + std::vector<LLScrollListItem*> items = from->getAllSelected(); + for (std::vector<LLScrollListItem*>::iterator iter = items.begin(); iter != items.end(); ++iter) + { + LLScrollListItem* item = *iter; + if (item->getUUID().notNull()) + { + avatar_ids.push_back(item->getUUID()); + + std::map<LLUUID, LLAvatarName>::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() +{ + + // If select btn not enabled then do not callback + if (!isSelectBtnEnabled()) + return; + + if(mSelectionCallback) + { + std::string acvtive_panel_name; + LLScrollListCtrl* list = NULL; + LLPanel* active_panel = getChild<LLTabContainer>("ResidentChooserTabs")->getCurrentPanel(); + if(active_panel) + { + acvtive_panel_name = active_panel->getName(); + } + if(acvtive_panel_name == "SearchPanel") + { + list = getChild<LLScrollListCtrl>("SearchResults"); + } + else if(acvtive_panel_name == "NearMePanel") + { + list = getChild<LLScrollListCtrl>("NearMe"); + } + else if (acvtive_panel_name == "FriendsPanel") + { + list = getChild<LLScrollListCtrl>("Friends"); + } + + if(list) + { + uuid_vec_t avatar_ids; + std::vector<LLAvatarName> avatar_names; + getSelectedAvatarData(list, avatar_ids, avatar_names); + mSelectionCallback(avatar_ids, avatar_names); + } + } + getChild<LLScrollListCtrl>("SearchResults")->deselectAllItems(true); + getChild<LLScrollListCtrl>("NearMe")->deselectAllItems(true); + getChild<LLScrollListCtrl>("Friends")->deselectAllItems(true); + if(mCloseOnSelect) + { + mCloseOnSelect = false; + closeFloater(); + } +} + +void LLFloaterAvatarPicker::onBtnRefresh() +{ + getChild<LLScrollListCtrl>("NearMe")->deleteAllItems(); + getChild<LLScrollListCtrl>("NearMe")->setCommentText(getString("searching")); + mNearMeListComplete = false; +} + +void LLFloaterAvatarPicker::onBtnClose() +{ + closeFloater(); +} + +void LLFloaterAvatarPicker::onRangeAdjust() +{ + onBtnRefresh(); +} + +void LLFloaterAvatarPicker::onList() +{ + getChildView("ok_btn")->setEnabled(isSelectBtnEnabled()); +} + +void LLFloaterAvatarPicker::populateNearMe() +{ + bool all_loaded = true; + bool empty = true; + LLScrollListCtrl* near_me_scroller = getChild<LLScrollListCtrl>("NearMe"); + near_me_scroller->deleteAllItems(); + + uuid_vec_t avatar_ids; + LLWorld::getInstance()->getAvatars(&avatar_ids, NULL, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); + for(U32 i=0; i<avatar_ids.size(); i++) + { + LLUUID& av = avatar_ids[i]; + if(mExcludeAgentFromSearchResults && (av == gAgent.getID())) continue; + LLSD element; + element["id"] = av; // value + 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]["column"] = "name"; + element["columns"][0]["value"] = av_name.getDisplayName(); + element["columns"][1]["column"] = "username"; + element["columns"][1]["value"] = av_name.getUserName(); + + sAvatarNameMap[av] = av_name; + } + near_me_scroller->addElement(element); + empty = false; + } + + if (empty) + { + getChildView("NearMe")->setEnabled(false); + getChildView("ok_btn")->setEnabled(false); + near_me_scroller->setCommentText(getString("no_one_near")); + } + else + { + getChildView("NearMe")->setEnabled(true); + getChildView("ok_btn")->setEnabled(true); + near_me_scroller->selectFirstItem(); + onList(); + near_me_scroller->setFocus(true); + } + + if (all_loaded) + { + mNearMeListComplete = true; + } +} + +void LLFloaterAvatarPicker::populateFriend() +{ + LLScrollListCtrl* friends_scroller = getChild<LLScrollListCtrl>("Friends"); + friends_scroller->deleteAllItems(); + LLCollectAllBuddies collector; + LLAvatarTracker::instance().applyFunctor(collector); + LLCollectAllBuddies::buddy_map_t::iterator it; + + for(it = collector.mOnline.begin(); it!=collector.mOnline.end(); it++) + { + friends_scroller->addStringUUIDItem(it->second, it->first); + } + for(it = collector.mOffline.begin(); it!=collector.mOffline.end(); it++) + { + friends_scroller->addStringUUIDItem(it->second, it->first); + } + friends_scroller->sortByColumnIndex(0, true); +} + +void LLFloaterAvatarPicker::drawFrustum() +{ + static LLCachedControl<F32> max_opacity(gSavedSettings, "PickerContextOpacity", 0.4f); + drawConeToOwner(mContextConeOpacity, max_opacity, mFrustumOrigin.get(), mContextConeFadeTime, mContextConeInAlpha, mContextConeOutAlpha); +} + +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; + if (timer.hasExpired()) + { + timer.setTimerExpirySec(0.33f); // three times per second should be enough. + + // simulate list changes. + onList(); + timer.start(); + } + + LLFloater::draw(); + if (!mNearMeListComplete && getChild<LLTabContainer>("ResidentChooserTabs")->getCurrentPanel() == getChild<LLPanel>("NearMePanel")) + { + populateNearMe(); + } +} + +bool LLFloaterAvatarPicker::visibleItemsSelected() const +{ + LLPanel* active_panel = getChild<LLTabContainer>("ResidentChooserTabs")->getCurrentPanel(); + + if(active_panel == getChild<LLPanel>("SearchPanel")) + { + return getChild<LLScrollListCtrl>("SearchResults")->getFirstSelectedIndex() >= 0; + } + else if(active_panel == getChild<LLPanel>("NearMePanel")) + { + return getChild<LLScrollListCtrl>("NearMe")->getFirstSelectedIndex() >= 0; + } + else if(active_panel == getChild<LLPanel>("FriendsPanel")) + { + return getChild<LLScrollListCtrl>("Friends")->getFirstSelectedIndex() >= 0; + } + return false; +} + +/*static*/ +void LLFloaterAvatarPicker::findCoro(std::string url, LLUUID queryID, std::string name) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("genericPostCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions); + + LL_INFOS("HttpCoroutineAdapter", "genericPostCoro") << "Generic POST for " << url << LL_ENDL; + + httpOpts->setTimeout(AVATAR_PICKER_SEARCH_TIMEOUT); + + LLSD result = httpAdapter->getAndSuspend(httpRequest, url, httpOpts); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (status || (status == LLCore::HttpStatus(HTTP_BAD_REQUEST))) + { + result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); + } + else + { + result["failure_reason"] = status.toString(); + } + + LLFloaterAvatarPicker* floater = + LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker", name); + if (floater) + { + floater->processResponse(queryID, result); + } +} + + +void LLFloaterAvatarPicker::find() +{ + //clear our stored LLAvatarNames + sAvatarNameMap.clear(); + + std::string text = getChild<LLUICtrl>("Edit")->getValue().asString(); + + size_t separator_index = text.find_first_of(" ._"); + if (separator_index != text.npos) + { + std::string first = text.substr(0, separator_index); + std::string last = text.substr(separator_index+1, text.npos); + LLStringUtil::trim(last); + if("Resident" == last) + { + text = first; + } + } + + mQueryID.generate(); + + std::string url; + url.reserve(128); // avoid a memory allocation or two + + LLViewerRegion* region = gAgent.getRegion(); + if(region) + { + url = region->getCapability("AvatarPickerSearch"); + // Prefer use of capabilities to search on both SLID and display name + if (!url.empty()) + { + // 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="; + std::replace(text.begin(), text.end(), '.', ' '); + url += LLURI::escape(text); + LL_INFOS() << "avatar picker " << url << LL_ENDL; + + LLCoros::instance().launch("LLFloaterAvatarPicker::findCoro", + boost::bind(&LLFloaterAvatarPicker::findCoro, url, mQueryID, getKey().asString())); + } + 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<LLScrollListCtrl>("SearchResults")->deleteAllItems(); + getChild<LLScrollListCtrl>("SearchResults")->setCommentText(getString("searching")); + + getChildView("ok_btn")->setEnabled(false); + mNumResultsReturned = 0; +} + +void LLFloaterAvatarPicker::setAllowMultiple(bool allow_multiple) +{ + getChild<LLScrollListCtrl>("SearchResults")->setAllowMultipleSelection(allow_multiple); + getChild<LLScrollListCtrl>("NearMe")->setAllowMultipleSelection(allow_multiple); + getChild<LLScrollListCtrl>("Friends")->setAllowMultipleSelection(allow_multiple); +} + +LLScrollListCtrl* LLFloaterAvatarPicker::getActiveList() +{ + std::string acvtive_panel_name; + LLScrollListCtrl* list = NULL; + LLPanel* active_panel = getChild<LLTabContainer>("ResidentChooserTabs")->getCurrentPanel(); + if(active_panel) + { + acvtive_panel_name = active_panel->getName(); + } + if(acvtive_panel_name == "SearchPanel") + { + list = getChild<LLScrollListCtrl>("SearchResults"); + } + else if(acvtive_panel_name == "NearMePanel") + { + list = getChild<LLScrollListCtrl>("NearMe"); + } + else if (acvtive_panel_name == "FriendsPanel") + { + list = getChild<LLScrollListCtrl>("Friends"); + } + return list; +} + +bool LLFloaterAvatarPicker::handleDragAndDrop(S32 x, S32 y, MASK mask, + bool drop, EDragAndDropType cargo_type, + void *cargo_data, EAcceptance *accept, + std::string& tooltip_msg) +{ + LLScrollListCtrl* list = getActiveList(); + if(list) + { + LLRect rc_list; + LLRect rc_point(x,y,x,y); + if (localRectToOtherView(rc_point, &rc_list, list)) + { + // Keep selected only one item + list->deselectAllItems(true); + list->selectItemAt(rc_list.mLeft, rc_list.mBottom, mask); + LLScrollListItem* selection = list->getFirstSelected(); + if (selection) + { + LLUUID session_id = LLUUID::null; + LLUUID dest_agent_id = selection->getUUID(); + std::string avatar_name = selection->getColumn(0)->getValue().asString(); + if (dest_agent_id.notNull() && dest_agent_id != gAgentID) + { + if (drop) + { + // Start up IM before give the item + session_id = gIMMgr->addSession(avatar_name, IM_NOTHING_SPECIAL, dest_agent_id); + } + return LLToolDragAndDrop::handleGiveDragAndDrop(dest_agent_id, session_id, drop, + cargo_type, cargo_data, accept, getName()); + } + } + } + } + *accept = ACCEPT_NO; + return true; +} + + +void LLFloaterAvatarPicker::openFriendsTab() +{ + LLTabContainer* tab_container = getChild<LLTabContainer>("ResidentChooserTabs"); + if (tab_container == NULL) + { + llassert(tab_container != NULL); + return; + } + + tab_container->selectTabByName("FriendsPanel"); +} + +// static +void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void**) +{ + LLUUID agent_id; + LLUUID query_id; + LLUUID avatar_id; + std::string first_name; + std::string last_name; + + msg->getUUID("AgentData", "AgentID", agent_id); + msg->getUUID("AgentData", "QueryID", query_id); + + // Not for us + if (agent_id != gAgent.getID()) return; + + LLFloaterAvatarPicker* floater = LLFloaterReg::findTypedInstance<LLFloaterAvatarPicker>("avatar_picker"); + + // floater is closed or these are not results from our last request + if (NULL == floater || query_id != floater->mQueryID) + { + return; + } + + LLScrollListCtrl* search_results = floater->getChild<LLScrollListCtrl>("SearchResults"); + + // clear "Searching" label on first results + if (floater->mNumResultsReturned++ == 0) + { + search_results->deleteAllItems(); + } + + bool found_one = false; + S32 num_new_rows = msg->getNumberOfBlocks("Data"); + for (S32 i = 0; i < num_new_rows; i++) + { + 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); + + 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<LLUICtrl>("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.fromString(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); + } + } + + if (found_one) + { + floater->getChildView("ok_btn")->setEnabled(true); + search_results->selectFirstItem(); + 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) + { + LLScrollListCtrl* search_results = getChild<LLScrollListCtrl>("SearchResults"); + + // clear "Searching" label on first results + search_results->deleteAllItems(); + + if (content.has("failure_reason")) + { + getChild<LLScrollListCtrl>("SearchResults")->setCommentText(content["failure_reason"].asString()); + getChildView("ok_btn")->setEnabled(false); + } + else + { + LLSD agents = content["agents"]; + + LLSD item; + LLSD::array_const_iterator it = agents.beginArray(); + for (; it != agents.endArray(); ++it) + { + const LLSD& row = *it; + 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; + } + } + + if (search_results->isEmpty()) + { + std::string name = "'" + getChild<LLUICtrl>("Edit")->getValue().asString() + "'"; + LLSD item; + item["id"] = LLUUID::null; + item["columns"][0]["column"] = "name"; + item["columns"][0]["value"] = name; + item["columns"][1]["column"] = "username"; + item["columns"][1]["value"] = getString("not_found_text"); + search_results->addElement(item); + search_results->setEnabled(false); + getChildView("ok_btn")->setEnabled(false); + } + else + { + getChildView("ok_btn")->setEnabled(true); + search_results->setEnabled(true); + search_results->sortByColumnIndex(1, true); + std::string text = getChild<LLUICtrl>("Edit")->getValue().asString(); + if (!search_results->selectItemByLabel(text, true, 1)) + { + search_results->selectFirstItem(); + } + onList(); + search_results->setFocus(true); + } + } + } +} + +void LLFloaterAvatarPicker::editKeystroke(LLLineEditor* caller, void* user_data) +{ + getChildView("Find")->setEnabled(caller->getText().size() > 0); +} + +// virtual +bool LLFloaterAvatarPicker::handleKeyHere(KEY key, MASK mask) +{ + if (key == KEY_RETURN && mask == MASK_NONE) + { + if (getChild<LLUICtrl>("Edit")->hasFocus()) + { + onBtnFind(); + } + else + { + onBtnSelect(); + } + return true; + } + else if (key == KEY_ESCAPE && mask == MASK_NONE) + { + closeFloater(); + return true; + } + + return LLFloater::handleKeyHere(key, mask); +} + +bool LLFloaterAvatarPicker::isSelectBtnEnabled() +{ + bool ret_val = visibleItemsSelected(); + + if ( ret_val && !isMinimized()) + { + std::string acvtive_panel_name; + LLScrollListCtrl* list = NULL; + LLPanel* active_panel = getChild<LLTabContainer>("ResidentChooserTabs")->getCurrentPanel(); + + if(active_panel) + { + acvtive_panel_name = active_panel->getName(); + } + + if(acvtive_panel_name == "SearchPanel") + { + list = getChild<LLScrollListCtrl>("SearchResults"); + } + else if(acvtive_panel_name == "NearMePanel") + { + list = getChild<LLScrollListCtrl>("NearMe"); + } + else if (acvtive_panel_name == "FriendsPanel") + { + list = getChild<LLScrollListCtrl>("Friends"); + } + + if(list) + { + uuid_vec_t avatar_ids; + std::vector<LLAvatarName> avatar_names; + getSelectedAvatarData(list, avatar_ids, avatar_names); + if (avatar_ids.size() >= 1) + { + ret_val = mOkButtonValidateSignal.num_slots()?mOkButtonValidateSignal(avatar_ids):true; + } + else + { + ret_val = false; + } + } + } + + return ret_val; +} |