/** * @file llfloaterchatmentionpicker.cpp * * $LicenseInfo:firstyear=2025&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2025, 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 "llfloaterchatmentionpicker.h" #include "llavatarlist.h" #include "llfloaterimcontainer.h" #include "llchatmentionhelper.h" #include "llparticipantlist.h" LLUUID LLFloaterChatMentionPicker::sSessionID(LLUUID::null); LLFloaterChatMentionPicker::LLFloaterChatMentionPicker(const LLSD& key) : LLFloater(key), mAvatarList(NULL) { // This floater should hover on top of our dependent (with the dependent having the focus) setFocusStealsFrontmost(false); setBackgroundVisible(false); setAutoFocus(false); } bool LLFloaterChatMentionPicker::postBuild() { mAvatarList = getChild("avatar_list"); mAvatarList->setShowCompleteName(true, true); mAvatarList->setFocusOnItemClicked(false); mAvatarList->setItemClickedCallback([this](LLUICtrl* ctrl, S32 x, S32 y, MASK mask) { if (LLAvatarListItem* item = dynamic_cast(ctrl)) { selectResident(item->getAvatarId()); } }); mAvatarList->setRefreshCompleteCallback([this](LLUICtrl* ctrl, const LLSD& param) { if (mAvatarList->numSelected() == 0) { mAvatarList->selectFirstItem(); } }); return LLFloater::postBuild(); } void LLFloaterChatMentionPicker::onOpen(const LLSD& key) { buildAvatarList(); mAvatarList->setNameFilter(key.has("av_name") ? key["av_name"].asString() : ""); gFloaterView->adjustToFitScreen(this, false); } uuid_vec_t LLFloaterChatMentionPicker::getParticipantIds() { LLParticipantList* item = dynamic_cast(LLFloaterIMContainer::getInstance()->getSessionModel(sSessionID)); if (!item) { LL_WARNS() << "Participant list is missing" << LL_ENDL; return {}; } uuid_vec_t avatar_ids; LLFolderViewModelItemCommon::child_list_t::const_iterator current_participant_model = item->getChildrenBegin(); LLFolderViewModelItemCommon::child_list_t::const_iterator end_participant_model = item->getChildrenEnd(); while (current_participant_model != end_participant_model) { LLConversationItem* participant_model = dynamic_cast(*current_participant_model); if (participant_model) { avatar_ids.push_back(participant_model->getUUID()); } current_participant_model++; } return avatar_ids; } void LLFloaterChatMentionPicker::buildAvatarList() { uuid_vec_t& avatar_ids = mAvatarList->getIDs(); avatar_ids = getParticipantIds(); updateAvatarList(avatar_ids); mAvatarList->setDirty(); } void LLFloaterChatMentionPicker::selectResident(const LLUUID& id) { if (id.isNull()) return; setValue(stringize("secondlife:///app/agent/", id.asString(), "/mention ")); onCommit(); LLChatMentionHelper::instance().hideHelper(); } void LLFloaterChatMentionPicker::onClose(bool app_quitting) { if (!app_quitting) { LLChatMentionHelper::instance().hideHelper(); } } bool LLFloaterChatMentionPicker::handleKey(KEY key, MASK mask, bool called_from_parent) { if (mask == MASK_NONE) { switch (key) { case KEY_UP: case KEY_DOWN: return mAvatarList->handleKey(key, mask, called_from_parent); case KEY_RETURN: case KEY_TAB: selectResident(mAvatarList->getSelectedUUID()); return true; case KEY_ESCAPE: LLChatMentionHelper::instance().hideHelper(); return true; case KEY_LEFT: case KEY_RIGHT: return true; default: break; } } return LLFloater::handleKey(key, mask, called_from_parent); } void LLFloaterChatMentionPicker::goneFromFront() { LLChatMentionHelper::instance().hideHelper(); } void LLFloaterChatMentionPicker::updateSessionID(LLUUID session_id) { sSessionID = session_id; LLParticipantList* item = dynamic_cast(LLFloaterIMContainer::getInstance()->getSessionModel(sSessionID)); if (!item) { LL_WARNS() << "Participant list is missing" << LL_ENDL; return; } uuid_vec_t avatar_ids = getParticipantIds(); updateAvatarList(avatar_ids); } void LLFloaterChatMentionPicker::updateAvatarList(uuid_vec_t& avatar_ids) { std::vector av_names; for (auto& id : avatar_ids) { LLAvatarName av_name; LLAvatarNameCache::get(id, &av_name); av_names.push_back(utf8str_tolower(av_name.getAccountName())); av_names.push_back(utf8str_tolower(av_name.getDisplayName())); } LLChatMentionHelper::instance().updateAvatarList(av_names); }