Files
SingularityViewer/indra/newview/llpanelavatar.cpp
2019-10-09 17:43:26 -04:00

1618 lines
52 KiB
C++

/**
* @file llpanelavatar.cpp
* @brief LLPanelAvatar and related class implementations
*
* $LicenseInfo:firstyear=2004&license=viewergpl$
*
* Copyright (c) 2004-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llpanelavatar.h"
#include "llavatarconstants.h"
#include "llavatarnamecache.h"
#include "llbutton.h"
#include "llcheckboxctrl.h"
#include "llclassifiedflags.h"
#include "lltextbox.h"
#include "lltexteditor.h"
#include "lltexturectrl.h"
#include "llwindow.h"
#include "llagent.h"
#include "llavataractions.h"
#include "llavatarpropertiesprocessor.h"
#include "llcallingcard.h"
#include "lldroptarget.h"
#include "llfloatergroupinfo.h"
#include "llfloatermute.h"
#include "llfloateravatarinfo.h"
#include "llgroupactions.h"
#include "lllineeditor.h"
#include "llnameeditor.h"
#include "llnotificationsutil.h"
#include "llpanelclassified.h"
#include "llpanelpick.h"
#include "llpreviewtexture.h"
#include "llpluginclassmedia.h"
#include "llscrolllistctrl.h"
#include "llscrolllistitem.h"
#include "lltabcontainer.h"
#include "lluictrlfactory.h"
#include "llviewerwindow.h"
#include "llweb.h"
#include <iosfwd>
#include <boost/date_time.hpp>
#include "hippogridmanager.h" // Include Gridmanager for OpenSim Support in profiles, provides ability for the helpbutton to redirect to GRID Websites Help page
// [RLVa:KB]
#include "rlvhandler.h"
// [/RLVa:KB]
// Statics
std::list<LLPanelAvatar*> LLPanelAvatar::sAllPanels;
BOOL LLPanelAvatar::sAllowFirstLife = FALSE;
BOOL is_agent_mappable(const LLUUID& agent_id);
//-----------------------------------------------------------------------------
// LLPanelAvatarTab()
//-----------------------------------------------------------------------------
LLPanelAvatarTab::LLPanelAvatarTab(const std::string& name, const LLRect &rect,
LLPanelAvatar* panel_avatar)
: LLPanel(name, rect),
mPanelAvatar(panel_avatar),
mDataRequested(false)
{
//Register with parent so it can relay agentid to tabs, since the id is set AFTER creation.
panel_avatar->mAvatarPanelList.push_back(this);
}
void LLPanelAvatarTab::setAvatarID(const LLUUID& avatar_id)
{
if (mAvatarID != avatar_id)
{
if (mAvatarID.notNull())
LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarID, this);
mAvatarID = avatar_id;
if (mAvatarID.notNull())
{
LLAvatarPropertiesProcessor::getInstance()->addObserver(mAvatarID, this);
if (LLUICtrl* ctrl = findChild<LLUICtrl>("Mute"))
ctrl->setValue(LLMuteList::instance().isMuted(mAvatarID));
}
}
}
// virtual
LLPanelAvatarTab::~LLPanelAvatarTab()
{
if (mAvatarID.notNull())
LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarID, this);
}
// virtual
void LLPanelAvatarTab::draw()
{
refresh();
LLPanel::draw();
}
//-----------------------------------------------------------------------------
// LLPanelAvatarSecondLife()
//-----------------------------------------------------------------------------
LLPanelAvatarSecondLife::LLPanelAvatarSecondLife(const std::string& name,
const LLRect &rect,
LLPanelAvatar* panel_avatar )
: LLPanelAvatarTab(name, rect, panel_avatar),
mPartnerID()
{
LLMuteList::instance().addObserver(this);
}
LLPanelAvatarSecondLife::~LLPanelAvatarSecondLife()
{
mCacheConnection.disconnect();
LLMuteList::instance().removeObserver(this);
}
void LLPanelAvatarSecondLife::refresh()
{
}
void LLPanelAvatarSecondLife::updatePartnerName(const LLAvatarName& name)
{
mCacheConnection.disconnect();
childSetTextArg("partner_edit", "[NAME]", name.getNSName());
}
//-----------------------------------------------------------------------------
// clearControls()
// Empty the data out of the controls, since we have to wait for new
// data off the network.
//-----------------------------------------------------------------------------
void LLPanelAvatarSecondLife::clearControls()
{
getChild<LLTextureCtrl>("img")->setImageAssetID(LLUUID::null);
childSetValue("about", LLStringUtil::null);
childSetValue("born", LLStringUtil::null);
childSetValue("acct", LLStringUtil::null);
childSetTextArg("partner_edit", "[NAME]", LLStringUtil::null);
mPartnerID = LLUUID::null;
if (LLUICtrl* ctrl = getChild<LLUICtrl>("partner_info"))
ctrl->setEnabled(mPartnerID.notNull());
getChild<LLScrollListCtrl>("groups")->deleteAllItems();
}
// virtual
void LLPanelAvatarSecondLife::processProperties(void* data, EAvatarProcessorType type)
{
if(type == APT_PROPERTIES)
{
const LLAvatarData* pAvatarData = static_cast<const LLAvatarData*>( data );
if (pAvatarData && (mAvatarID == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null))
{
LLStringUtil::format_map_t args;
args["[ACCTTYPE]"] = LLAvatarPropertiesProcessor::accountType(pAvatarData);
args["[PAYMENTINFO]"] = LLAvatarPropertiesProcessor::paymentInfo(pAvatarData);
args["[AGEVERIFICATION]"] = LLStringUtil::null;
{
const auto account_info = getString("CaptionTextAcctInfo", args);
auto acct = getChild<LLUICtrl>("acct");
acct->setValue(account_info);
acct->setToolTip(account_info);
}
getChild<LLTextureCtrl>("img")->setImageAssetID(pAvatarData->image_id);
// Show avatar age in days.
{
using namespace boost::gregorian;
int year, month, day;
const auto& born = pAvatarData->born_on;
if (!born.empty() && sscanf(born.c_str(),"%d/%d/%d", &month, &day, &year) == 3 // Make sure input is valid
&& month > 0 && month <= 12 && day > 0 && day <= 31 && year >= 1400) // Don't use numbers that gregorian will choke on
{
date birthday(year, month, day), today(day_clock::local_day());
std::ostringstream born_on;
born_on << pAvatarData->born_on << " (" << today - birthday << ')';
childSetValue("born", born_on.str());
}
else childSetValue("born", born);
}
bool allow_publish = (pAvatarData->flags & AVATAR_ALLOW_PUBLISH);
childSetValue("allow_publish", allow_publish);
mPartnerID = pAvatarData->partner_id;
if (mPartnerID.notNull())
{
mCacheConnection.disconnect();
mCacheConnection = LLAvatarNameCache::get(mPartnerID, boost::bind(&LLPanelAvatarSecondLife::updatePartnerName, this, _2));
childSetEnabled("partner_info", TRUE);
}
}
}
else if (type == APT_GROUPS)
{
const LLAvatarGroups* pAvatarGroups = static_cast<const LLAvatarGroups*>(data);
if (pAvatarGroups && pAvatarGroups->avatar_id == mAvatarID && pAvatarGroups->avatar_id.notNull())
{
LLScrollListCtrl* group_list = getChild<LLScrollListCtrl>("groups");
if (!pAvatarGroups->group_list.size())
{
group_list->setCommentText(getString("None"));
}
for(LLAvatarGroups::group_list_t::const_iterator it = pAvatarGroups->group_list.begin();
it != pAvatarGroups->group_list.end(); ++it)
{
// Is this really necessary? Remove existing entry if it exists.
// TODO: clear the whole list when a request for data is made
S32 index = group_list->getItemIndex(it->group_id);
if (index >= 0)
group_list->deleteSingleItem(index);
LLScrollListItem::Params row;
row.value(it->group_id);
std::string font_style("NORMAL"); // Set normal color if not found or if group is visible in profile
if (pAvatarGroups->avatar_id == pAvatarGroups->agent_id) // own avatar
for (std::vector<LLGroupData>::iterator i = gAgent.mGroups.begin(); i != gAgent.mGroups.end(); ++i) // Search for this group in the agent's groups list
if (i->mID == it->group_id)
{
if (i->mListInProfile)
font_style = "BOLD";
break;
}
if (it->group_id == gAgent.getGroupID())
font_style.append("|ITALIC");
row.columns.add(LLScrollListCell::Params().value(it->group_id.notNull() ? it->group_name : "").font("SANSSERIF_SMALL").font_style(font_style));
group_list->addRow(row,ADD_SORTED);
}
}
}
}
void LLPanelAvatarSecondLife::onChangeDetailed(const LLMute& mute)
{
if (mute.mID != mAvatarID) return;
getChild<LLUICtrl>("Mute")->setValue(LLMuteList::instance().hasMute(mute));
}
//-----------------------------------------------------------------------------
// enableControls()
//-----------------------------------------------------------------------------
void LLPanelAvatarSecondLife::enableControls(BOOL self)
{
childSetEnabled("img", self);
childSetEnabled("about", self);
if (self) // We can't give inventory to self
{
if (LLDropTarget* drop_target = findChild<LLDropTarget>("drop_target_rect"))
removeChild(drop_target);
if (LLTextBox* text_box = findChild<LLTextBox>("Give item:"))
removeChild(text_box);
}
childSetVisible("allow_publish", self);
childSetEnabled("allow_publish", self);
childSetVisible("?", self);
childSetEnabled("?", self);
}
// virtual
void LLPanelAvatarFirstLife::processProperties(void* data, EAvatarProcessorType type)
{
if (type == APT_PROPERTIES)
{
const LLAvatarData* pAvatarData = static_cast<const LLAvatarData*>(data);
if (pAvatarData && (mAvatarID == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null))
{
// Teens don't get these
getChild<LLTextEditor>("about")->setText(pAvatarData->fl_about_text, false);
getChild<LLTextureCtrl>("img")->setImageAssetID(pAvatarData->fl_image_id);
}
}
}
void LLPanelAvatarSecondLife::onDoubleClickGroup()
{
if (LLScrollListItem* item = getChild<LLScrollListCtrl>("groups")->getFirstSelected())
LLGroupActions::show(item->getUUID());
}
// static - Not anymore :P
bool LLPanelAvatarSecondLife::onClickPartnerHelpLoadURL(const LLSD& notification, const LLSD& response)
{
if (!LLNotification::getSelectedOption(notification, response))
{
const auto& grid = *gHippoGridManager->getConnectedGrid();
const std::string url = grid.isSecondLife() ? "http://secondlife.com/partner" : grid.getPartnerUrl();
if (!url.empty()) LLWeb::loadURL(url);
}
return false;
}
//-----------------------------------------------------------------------------
// LLPanelAvatarFirstLife()
//-----------------------------------------------------------------------------
LLPanelAvatarFirstLife::LLPanelAvatarFirstLife(const std::string& name,
const LLRect &rect,
LLPanelAvatar* panel_avatar )
: LLPanelAvatarTab(name, rect, panel_avatar)
{
}
void LLPanelAvatarFirstLife::enableControls(BOOL self)
{
childSetEnabled("img", self);
childSetEnabled("about", self);
}
//-----------------------------------------------------------------------------
// postBuild
//-----------------------------------------------------------------------------
void show_picture(const LLUUID& id, const std::string& name);
static std::string profile_picture_title(const std::string& str) { return "Profile Picture: " + str; }
static void show_partner_help() { LLNotificationsUtil::add("ClickPartnerHelpAvatar", LLSD(), LLSD(), boost::bind(LLPanelAvatarSecondLife::onClickPartnerHelpLoadURL, _1, _2)); }
void show_log_browser(const LLUUID& id)
{
void show_log_browser(const std::string& name, const std::string& id);
LLAvatarName av_name;
LLAvatarNameCache::get(id, &av_name);
show_log_browser(av_name.getLegacyName(), id.asString());
}
BOOL LLPanelAvatarSecondLife::postBuild()
{
childSetEnabled("born", FALSE);
childSetEnabled("partner_edit", FALSE);
getChild<LLUICtrl>("partner_help")->setCommitCallback(boost::bind(show_partner_help));
if (LLUICtrl* ctrl = getChild<LLUICtrl>("partner_info"))
{
ctrl->setCommitCallback(boost::bind(LLAvatarActions::showProfile, boost::ref(mPartnerID), false));
ctrl->setEnabled(mPartnerID.notNull());
}
childSetAction("?", boost::bind(LLNotificationsUtil::add, "ClickPublishHelpAvatar"));
LLPanelAvatar* pa = getPanelAvatar();
enableControls(pa->getAvatarID() == gAgentID);
childSetVisible("About:",LLPanelAvatar::sAllowFirstLife);
childSetVisible("(500 chars)",LLPanelAvatar::sAllowFirstLife);
childSetVisible("about",LLPanelAvatar::sAllowFirstLife);
childSetVisible("allow_publish",LLPanelAvatar::sAllowFirstLife);
childSetVisible("?",LLPanelAvatar::sAllowFirstLife);
childSetVisible("online_yes",FALSE);
getChild<LLUICtrl>("Find on Map")->setCommitCallback(boost::bind(LLAvatarActions::showOnMap, boost::bind(&LLPanelAvatar::getAvatarID, pa)));
getChild<LLUICtrl>("Instant Message...")->setCommitCallback(boost::bind(LLAvatarActions::startIM, boost::bind(&LLPanelAvatar::getAvatarID, pa)));
getChild<LLUICtrl>("GroupInvite_Button")->setCommitCallback(boost::bind(static_cast<void(*)(const LLUUID&)>(LLAvatarActions::inviteToGroup), boost::bind(&LLPanelAvatar::getAvatarID, pa)));
getChild<LLUICtrl>("Add Friend...")->setCommitCallback(boost::bind(LLAvatarActions::requestFriendshipDialog, boost::bind(&LLPanelAvatar::getAvatarID, pa)));
getChild<LLUICtrl>("Log")->setCommitCallback(boost::bind(show_log_browser, boost::bind(&LLPanelAvatar::getAvatarID, pa)));
getChild<LLUICtrl>("Pay...")->setCommitCallback(boost::bind(LLAvatarActions::pay, boost::bind(&LLPanelAvatar::getAvatarID, pa)));
if (LLUICtrl* ctrl = findChild<LLUICtrl>("Mute"))
{
ctrl->setCommitCallback(boost::bind(LLAvatarActions::toggleBlock, boost::bind(&LLPanelAvatar::getAvatarID, pa)));
ctrl->setValue(LLMuteList::instance().isMuted(mAvatarID));
}
getChild<LLUICtrl>("Offer Teleport...")->setCommitCallback(boost::bind(static_cast<void(*)(const LLUUID&)>(LLAvatarActions::offerTeleport), boost::bind(&LLPanelAvatar::getAvatarID, pa)));
getChild<LLScrollListCtrl>("groups")->setDoubleClickCallback(boost::bind(&LLPanelAvatarSecondLife::onDoubleClickGroup,this));
LLTextureCtrl* ctrl = getChild<LLTextureCtrl>("img");
ctrl->setFallbackImageName("default_profile_picture.j2c");
auto show_pic = [&]
{
show_picture(getChild<LLTextureCtrl>("img")->getImageAssetID(), profile_picture_title(getChildView("dnname")->getValue()));
};
auto show_pic_if_not_self = [=] { if (!ctrl->canChange()) show_pic(); };
ctrl->setMouseUpCallback(std::bind(show_pic_if_not_self));
getChild<LLUICtrl>("bigimg")->setCommitCallback(std::bind(show_pic));
return TRUE;
}
BOOL LLPanelAvatarFirstLife::postBuild()
{
enableControls(getPanelAvatar()->getAvatarID() == gAgentID);
LLTextureCtrl* ctrl = getChild<LLTextureCtrl>("img");
ctrl->setFallbackImageName("default_profile_picture.j2c");
auto show_pic = [&]
{
show_picture(getChild<LLTextureCtrl>("img")->getImageAssetID(), "First Life Picture");
};
auto show_pic_if_not_self = [=] { if (!ctrl->canChange()) show_pic(); };
ctrl->setMouseUpCallback(std::bind(show_pic_if_not_self));
getChild<LLUICtrl>("flbigimg")->setCommitCallback(std::bind(show_pic));
return TRUE;
}
BOOL LLPanelAvatarNotes::postBuild()
{
LLTextEditor* te(getChild<LLTextEditor>("notes edit"));
te->setCommitCallback(boost::bind(&LLPanelAvatar::sendAvatarNotesUpdate, getPanelAvatar()));
te->setCommitOnFocusLost(true);
return TRUE;
}
BOOL LLPanelAvatarWeb::postBuild()
{
LLLineEditor* url_edit = getChild<LLLineEditor>("url_edit");
LLUICtrl* loadctrl = getChild<LLUICtrl>("load");
url_edit->setKeystrokeCallback(boost::bind(&LLView::setEnabled, loadctrl, boost::bind(&std::string::length, boost::bind(&LLLineEditor::getText, _1))));
url_edit->setCommitCallback(boost::bind(&LLPanelAvatarWeb::load, this, boost::bind(&LLSD::asString, _2)));
loadctrl->setCommitCallback(boost::bind(&LLPanelAvatarWeb::onCommitLoad, this, _2));
getChild<LLUICtrl>("web_profile_help")->setCommitCallback(boost::bind(LLNotificationsUtil::add, "ClickWebProfileHelpAvatar"));
mWebBrowser = getChild<LLMediaCtrl>("profile_html");
mWebBrowser->addObserver(this);
return TRUE;
}
// virtual
void LLPanelAvatarWeb::processProperties(void* data, EAvatarProcessorType type)
{
if(type == APT_PROPERTIES)
{
const LLAvatarData* pAvatarData = static_cast<const LLAvatarData*>( data );
if (pAvatarData && (mAvatarID == pAvatarData->avatar_id) && (pAvatarData->avatar_id.notNull()))
{
setWebURL(pAvatarData->profile_url);
}
}
}
BOOL LLPanelAvatarClassified::postBuild()
{
getChild<LLUICtrl>("New...")->setCommitCallback(boost::bind(&LLPanelAvatarClassified::onClickNew, this));
getChild<LLUICtrl>("Delete...")->setCommitCallback(boost::bind(&LLPanelAvatarClassified::onClickDelete, this));
// *HACK: Don't allow making new classifieds from inside the directory.
// The logic for save/don't save when closing is too hairy, and the
// directory is conceptually read-only. JC
for (LLView* view = this; !mInDirectory && view; view = view->getParent())
if (view->getName() == "directory")
mInDirectory = true;
return TRUE;
}
BOOL LLPanelAvatarPicks::postBuild()
{
getChild<LLUICtrl>("New...")->setCommitCallback(boost::bind(&LLPanelAvatarPicks::onClickNew, this));
getChild<LLUICtrl>("Delete...")->setCommitCallback(boost::bind(&LLPanelAvatarPicks::onClickDelete, this));
//For pick import and export - RK
getChild<LLUICtrl>("Import...")->setCommitCallback(boost::bind(&LLPanelAvatarPicks::onClickImport, this));
getChild<LLUICtrl>("Export...")->setCommitCallback(boost::bind(&LLPanelAvatarPicks::onClickExport, this));
return TRUE;
}
BOOL LLPanelAvatarAdvanced::postBuild()
{
for(size_t ii = 0; ii < LL_ARRAY_SIZE(mWantToCheck); ++ii)
mWantToCheck[ii] = NULL;
for(size_t ii = 0; ii < LL_ARRAY_SIZE(mSkillsCheck); ++ii)
mSkillsCheck[ii] = NULL;
mWantToCount = (8>LL_ARRAY_SIZE(mWantToCheck))?LL_ARRAY_SIZE(mWantToCheck):8;
for(S32 tt=0; tt < mWantToCount; ++tt)
{
std::string ctlname = llformat("chk%d", tt);
mWantToCheck[tt] = getChild<LLCheckBoxCtrl>(ctlname);
}
mSkillsCount = (6>LL_ARRAY_SIZE(mSkillsCheck))?LL_ARRAY_SIZE(mSkillsCheck):6;
for(S32 tt=0; tt < mSkillsCount; ++tt)
{
//Find the Skills checkboxes and save off thier controls
std::string ctlname = llformat("schk%d",tt);
mSkillsCheck[tt] = getChild<LLCheckBoxCtrl>(ctlname);
}
mWantToEdit = getChild<LLLineEditor>("want_to_edit");
mSkillsEdit = getChild<LLLineEditor>("skills_edit");
childSetVisible("skills_edit",LLPanelAvatar::sAllowFirstLife);
childSetVisible("want_to_edit",LLPanelAvatar::sAllowFirstLife);
return TRUE;
}
// virtual
void LLPanelAvatarAdvanced::processProperties(void* data, EAvatarProcessorType type)
{
if(type == APT_INTERESTS)
{
const LLAvatarInterestsInfo* i_info = static_cast<LLAvatarInterestsInfo*>(data);
if(i_info && i_info->avatar_id == mAvatarID && i_info->avatar_id.notNull())
{
setWantSkills(i_info->want_to_mask,i_info->want_to_text,i_info->skills_mask,i_info->skills_text,i_info->languages_text);
}
}
}
//-----------------------------------------------------------------------------
// LLPanelAvatarWeb
//-----------------------------------------------------------------------------
LLPanelAvatarWeb::LLPanelAvatarWeb(const std::string& name, const LLRect& rect,
LLPanelAvatar* panel_avatar)
: LLPanelAvatarTab(name, rect, panel_avatar),
mWebBrowser(NULL)
{
}
LLPanelAvatarWeb::~LLPanelAvatarWeb()
{
// stop observing browser events
if ( mWebBrowser )
{
mWebBrowser->remObserver( this );
}
}
void LLPanelAvatarWeb::refresh()
{
if (!mNavigateTo.empty())
{
LL_INFOS() << "Loading " << mNavigateTo << LL_ENDL;
mWebBrowser->navigateTo(mNavigateTo);
mNavigateTo = "";
}
}
void LLPanelAvatarWeb::enableControls(BOOL self)
{
childSetEnabled("url_edit",self);
childSetVisible("status_text",!self && !mHome.empty());
childSetText("status_text", LLStringUtil::null);
}
void LLPanelAvatarWeb::setWebURL(std::string url)
{
bool changed_url = (mHome != url);
mHome = url;
childSetText("url_edit", mHome);
childSetEnabled("load", mHome.length() > 0);
if (!mHome.empty() && gSavedSettings.getBOOL("AutoLoadWebProfiles"))
{
if (changed_url)
{
load(mHome);
}
childSetVisible("status_text", getPanelAvatar()->getAvatarID() != gAgentID);
}
else
{
childSetVisible("profile_html", false);
childSetVisible("status_text", false);
}
}
void LLPanelAvatarWeb::load(const std::string& url)
{
bool have_url = (!url.empty());
childSetVisible("profile_html", have_url);
childSetVisible("status_text", have_url);
childSetText("status_text", LLStringUtil::null);
if (have_url)
{
mNavigateTo = url;
}
}
void LLPanelAvatarWeb::onCommitLoad(const LLSD& value)
{
const std::string& valstr(value.asString());
if (valstr.empty()) // load url string into browser panel
{
load(childGetText("url_edit"));
}
else if (valstr == "open") // open in user's external browser
{
const std::string& urlstr(childGetText("url_edit"));
if (!urlstr.empty()) LLWeb::loadURLExternal(urlstr);
}
else if (valstr == "home") // reload profile owner's home page
{
if (!mHome.empty()) load(mHome);
}
}
void LLPanelAvatarWeb::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event)
{
switch(event)
{
case MEDIA_EVENT_STATUS_TEXT_CHANGED:
childSetText("status_text", self->getStatusText());
break;
case MEDIA_EVENT_LOCATION_CHANGED:
childSetText("url_edit", self->getLocation());
break;
default:
// Having a default case makes the compiler happy.
break;
}
}
//-----------------------------------------------------------------------------
// LLPanelAvatarAdvanced
//-----------------------------------------------------------------------------
LLPanelAvatarAdvanced::LLPanelAvatarAdvanced(const std::string& name,
const LLRect& rect,
LLPanelAvatar* panel_avatar)
: LLPanelAvatarTab(name, rect, panel_avatar),
mWantToCount(0),
mSkillsCount(0),
mWantToEdit( NULL ),
mSkillsEdit( NULL )
{
}
void LLPanelAvatarAdvanced::enableControls(BOOL self)
{
for(S32 t(0); t < mWantToCount; ++t)
if (mWantToCheck[t])
mWantToCheck[t]->setEnabled(self);
for(S32 t(0); t < mSkillsCount; ++t)
if (mSkillsCheck[t])
mSkillsCheck[t]->setEnabled(self);
if (mWantToEdit)
mWantToEdit->setEnabled(self);
if (mSkillsEdit)
mSkillsEdit->setEnabled(self);
childSetEnabled("languages_edit", self);
}
void LLPanelAvatarAdvanced::setWantSkills(U32 want_to_mask, const std::string& want_to_text,
U32 skills_mask, const std::string& skills_text,
const std::string& languages_text)
{
for(S32 i = 0; i < mWantToCount; ++i)
{
mWantToCheck[i]->set(want_to_mask & 1<<i);
}
for(S32 i = 0; i < mSkillsCount; ++i)
{
mSkillsCheck[i]->set(skills_mask & 1<<i);
}
if (mWantToEdit && mSkillsEdit)
{
mWantToEdit->setText(want_to_text);
mSkillsEdit->setText(skills_text);
}
childSetText("languages_edit",languages_text);
}
void LLPanelAvatarAdvanced::getWantSkills(U32* want_to_mask, std::string& want_to_text,
U32* skills_mask, std::string& skills_text,
std::string& languages_text)
{
if (want_to_mask)
{
*want_to_mask = 0;
for(S32 t = 0; t < mWantToCount; ++t)
if (mWantToCheck[t]->get())
*want_to_mask |= 1<<t;
}
if (skills_mask)
{
*skills_mask = 0;
for(S32 t = 0; t < mSkillsCount; ++t)
if(mSkillsCheck[t]->get())
*skills_mask |= 1<<t;
}
if (mWantToEdit)
want_to_text = mWantToEdit->getText();
if (mSkillsEdit)
skills_text = mSkillsEdit->getText();
languages_text = childGetText("languages_edit");
}
//-----------------------------------------------------------------------------
// LLPanelAvatarNotes()
//-----------------------------------------------------------------------------
LLPanelAvatarNotes::LLPanelAvatarNotes(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar)
: LLPanelAvatarTab(name, rect, panel_avatar)
{
}
void LLPanelAvatarNotes::refresh()
{
if (!isDataRequested())
{
LLAvatarPropertiesProcessor::getInstance()->sendAvatarNotesRequest(mAvatarID);
setDataRequested(true);
}
}
void LLPanelAvatarNotes::clearControls()
{
LLView* view(getChildView("notes edit"));
view->setValue(getString("Loading"));
view->setEnabled(false);
}
//-----------------------------------------------------------------------------
// LLPanelAvatarClassified()
//-----------------------------------------------------------------------------
LLPanelAvatarClassified::LLPanelAvatarClassified(const std::string& name, const LLRect& rect,
LLPanelAvatar* panel_avatar)
: LLPanelAvatarTab(name, rect, panel_avatar)
, mInDirectory(false)
{
}
void LLPanelAvatarClassified::refresh()
{
if (!isDataRequested())
{
LLAvatarPropertiesProcessor::getInstance()->sendAvatarClassifiedsRequest(mAvatarID);
setDataRequested(true);
}
}
BOOL LLPanelAvatarClassified::canClose()
{
LLTabContainer* tabs = getChild<LLTabContainer>("classified tab");
for (S32 i = 0; i < tabs->getTabCount(); i++)
{
LLPanelClassifiedInfo* panel = (LLPanelClassifiedInfo*)tabs->getPanelByIndex(i);
if (!panel->canClose())
{
return FALSE;
}
}
return TRUE;
}
BOOL LLPanelAvatarClassified::titleIsValid()
{
if (LLTabContainer* tabs = getChild<LLTabContainer>("classified tab"))
if (LLPanelClassifiedInfo* panel = (LLPanelClassifiedInfo*)tabs->getCurrentPanel())
if (!panel->titleIsValid())
return FALSE;
return TRUE;
}
void LLPanelAvatarClassified::apply()
{
LLTabContainer* tabs = getChild<LLTabContainer>("classified tab");
for (S32 i = 0; i < tabs->getTabCount(); i++)
{
LLPanelClassifiedInfo* panel = (LLPanelClassifiedInfo*)tabs->getPanelByIndex(i);
panel->apply();
}
}
void LLPanelAvatarClassified::deleteClassifiedPanels()
{
getChild<LLTabContainer>("classified tab")->deleteAllTabs();
childSetVisible("New...", false);
childSetVisible("Delete...", false);
childSetVisible("loading_text", true);
}
// virtual
void LLPanelAvatarClassified::processProperties(void* data, EAvatarProcessorType type)
{
if (type == APT_CLASSIFIEDS)
{
LLAvatarClassifieds* c_info = static_cast<LLAvatarClassifieds*>(data);
if (c_info && mAvatarID == c_info->target_id)
{
LLTabContainer* tabs = getChild<LLTabContainer>("classified tab");
for(LLAvatarClassifieds::classifieds_list_t::iterator it = c_info->classifieds_list.begin();
it != c_info->classifieds_list.end(); ++it)
{
LLPanelClassifiedInfo* panel_classified = new LLPanelClassifiedInfo(false, false);
panel_classified->setClassifiedID(it->classified_id);
// This will request data from the server when the pick is first drawn.
panel_classified->markForServerRequest();
// The button should automatically truncate long names for us
tabs->addTabPanel(panel_classified, it->name);
}
// Make sure somebody is highlighted. This works even if there
// are no tabs in the container.
tabs->selectFirstTab();
bool self = gAgentID == mAvatarID;
S32 tab_count = tabs->getTabCount();
bool allow_new = tab_count < MAX_CLASSIFIEDS
// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
&& !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC);
// [/RLVa:KB]
LLView* view(getChildView("New..."));
view->setEnabled(self && !mInDirectory && allow_new);
view->setVisible(!mInDirectory);
view = getChildView("Delete...");
view->setEnabled(self && !mInDirectory && tab_count);
view->setVisible(!mInDirectory);
view = getChildView("loading_text");
view->setVisible(false);
}
}
}
// Create a new classified panel. It will automatically handle generating
// its own id when it's time to save.
// static
void LLPanelAvatarClassified::onClickNew()
{
// [RLVa:KB] - Version: 1.23.4 | Checked: 2009-07-04 (RLVa-1.0.0a)
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) return;
// [/RLVa:KB]
LLNotificationsUtil::add("AddClassified", LLSD(), LLSD(), boost::bind(&LLPanelAvatarClassified::callbackNew, this, _1, _2));
}
bool LLPanelAvatarClassified::callbackNew(const LLSD& notification, const LLSD& response)
{
if (LLNotification::getSelectedOption(notification, response))
return false;
LLPanelClassifiedInfo* panel_classified = new LLPanelClassifiedInfo(false, false);
panel_classified->initNewClassified();
LLTabContainer* tabs = getChild<LLTabContainer>("classified tab");
tabs->addTabPanel(panel_classified, panel_classified->getClassifiedName());
tabs->selectLastTab();
bool allow_new = tabs->getTabCount() < MAX_CLASSIFIEDS
// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
&& !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC);
// [/RLVa:KB]
childSetEnabled("New...", allow_new);
childSetEnabled("Delete...", true);
return true;
}
// static
void LLPanelAvatarClassified::onClickDelete()
{
LLTabContainer* tabs = getChild<LLTabContainer>("classified tab");
LLPanelClassifiedInfo* panel_classified = (LLPanelClassifiedInfo*)tabs->getCurrentPanel();
if (!panel_classified) return;
LLSD args;
args["NAME"] = panel_classified->getClassifiedName();
LLNotificationsUtil::add("DeleteClassified", args, LLSD(), boost::bind(&LLPanelAvatarClassified::callbackDelete, this, _1, _2));
}
bool LLPanelAvatarClassified::callbackDelete(const LLSD& notification, const LLSD& response)
{
if (LLNotification::getSelectedOption(notification, response))
return false;
LLTabContainer* tabs = getChild<LLTabContainer>("classified tab");
LLPanelClassifiedInfo* panel_classified = (LLPanelClassifiedInfo*)tabs->getCurrentPanel();
if (!panel_classified) return false;
LLAvatarPropertiesProcessor::getInstance()->sendClassifiedDelete(panel_classified->getClassifiedID());
tabs->removeTabPanel(panel_classified);
delete panel_classified;
panel_classified = NULL;
childSetEnabled("New...", !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
childSetEnabled("Delete...", tabs->getTabCount());
return true;
}
//-----------------------------------------------------------------------------
// LLPanelAvatarPicks()
//-----------------------------------------------------------------------------
LLPanelAvatarPicks::LLPanelAvatarPicks(const std::string& name,
const LLRect& rect,
LLPanelAvatar* panel_avatar)
: LLPanelAvatarTab(name, rect, panel_avatar)
{
}
void LLPanelAvatarPicks::refresh()
{
if (!isDataRequested())
{
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(mAvatarID);
setDataRequested(true);
}
}
void LLPanelAvatarPicks::deletePickPanels()
{
getChild<LLTabContainer>("picks tab")->deleteAllTabs();
childSetVisible("New...", false);
childSetVisible("Delete...", false);
childSetVisible("loading_text", true);
//For pick import and export - RK
childSetVisible("Export...", false);
childSetVisible("Import...", false);
}
// virtual
void LLPanelAvatarPicks::processProperties(void* data, EAvatarProcessorType type)
{
if (type == APT_PICKS)
{
LLAvatarPicks* picks = static_cast<LLAvatarPicks*>(data);
//llassert_always(picks->target_id != gAgent.getID());
//llassert_always(mAvatarID != gAgent.getID());
if (picks && mAvatarID == picks->target_id)
{
LLTabContainer* tabs = getChild<LLTabContainer>("picks tab");
// Clear out all the old panels. We'll replace them with the correct
// number of new panels.
deletePickPanels();
bool self(gAgentID == mAvatarID);
for (LLAvatarPicks::picks_list_t::iterator it = picks->picks_list.begin();
it != picks->picks_list.end(); ++it)
{
LLPanelPick* panel_pick = new LLPanelPick();
panel_pick->setPickID(it->first, mAvatarID);
// This will request data from the server when the pick is first
// drawn.
panel_pick->markForServerRequest();
// The button should automatically truncate long names for us
LL_INFOS() << "Adding tab for " << mAvatarID << " " << (self ? "Self" : "Other") << ": '" << it->second << "'" << LL_ENDL;
tabs->addTabPanel(panel_pick, it->second);
}
// Make sure somebody is highlighted. This works even if there
// are no tabs in the container.
tabs->selectFirstTab();
bool edit(getPanelAvatar()->isEditable());
S32 tab_count = tabs->getTabCount();
LLView* view = getChildView("New...");
view->setEnabled(self && tab_count < MAX_AVATAR_PICKS
// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
&& !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
// [/RLVa:KB]
view->setVisible(self && edit);
view = getChildView("Delete...");
view->setEnabled(self && tab_count);
view->setVisible(self && edit);
//For pick import/export - RK
view = getChildView("Import...");
view->setVisible(self && edit);
view->setEnabled(tab_count < MAX_AVATAR_PICKS);
view = getChildView("Export...");
view->setEnabled(self && tab_count);
view->setVisible(self);
childSetVisible("loading_text", false);
}
}
}
// Create a new pick panel. It will automatically handle generating
// its own id when it's time to save.
void LLPanelAvatarPicks::onClickNew()
{
// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC))
return;
// [/RLVa:KB]
LLPanelPick* panel_pick = new LLPanelPick;
LLTabContainer* tabs = getChild<LLTabContainer>("picks tab");
panel_pick->initNewPick();
tabs->addTabPanel(panel_pick, panel_pick->getPickName());
tabs->selectLastTab();
S32 tab_count = tabs->getTabCount();
getChildView("New...")->setEnabled(tab_count < MAX_AVATAR_PICKS
// [RLVa:KB] - Checked: 2009-07-04 (RLVa-1.0.0a)
&& !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
// [/RLVa:KB]
getChildView("Delete...")->setEnabled(true);
getChildView("Import...")->setEnabled(tab_count < MAX_AVATAR_PICKS);
}
//Pick import and export - RK
void LLPanelAvatarPicks::onClickImport()
{
mPanelPick = new LLPanelPick;
mPanelPick->importNewPick(&LLPanelAvatarPicks::onClickImport_continued, this);
}
// static
void LLPanelAvatarPicks::onClickImport_continued(void* data, bool import)
{
LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data;
LLTabContainer* tabs = self->getChild<LLTabContainer>("picks tab");
if (import && self->mPanelPick)
{
tabs->addTabPanel(self->mPanelPick, self->mPanelPick->getPickName());
tabs->selectLastTab();
self->childSetEnabled("New...", !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
self->childSetEnabled("Delete...", false);
self->childSetEnabled("Import...", tabs->getTabCount() < MAX_AVATAR_PICKS);
}
}
void LLPanelAvatarPicks::onClickExport()
{
LLPanelPick* panel_pick = (LLPanelPick*)getChild<LLTabContainer>("picks tab")->getCurrentPanel();
if (!panel_pick) return;
panel_pick->exportPick();
}
void LLPanelAvatarPicks::onClickDelete()
{
LLPanelPick* panel_pick = (LLPanelPick*)getChild<LLTabContainer>("picks tab")->getCurrentPanel();
if (!panel_pick) return;
LLSD args;
args["PICK"] = panel_pick->getPickName();
LLNotificationsUtil::add("DeleteAvatarPick", args, LLSD(),
boost::bind(&LLPanelAvatarPicks::callbackDelete, this, _1, _2));
}
bool LLPanelAvatarPicks::callbackDelete(const LLSD& notification, const LLSD& response)
{
if (LLNotification::getSelectedOption(notification, response))
return false;
LLTabContainer* tabs = getChild<LLTabContainer>("picks tab");
LLPanelPick* panel_pick = (LLPanelPick*)tabs->getCurrentPanel();
if (!panel_pick) return false;
LLMessageSystem* msg = gMessageSystem;
// If the viewer has a hacked god-mode, then this call will fail.
if (gAgent.isGodlike())
{
msg->newMessage("PickGodDelete");
msg->nextBlock("AgentData");
msg->addUUID("AgentID", gAgentID);
msg->addUUID("SessionID", gAgentSessionID);
msg->nextBlock("Data");
msg->addUUID("PickID", panel_pick->getPickID());
// *HACK: We need to send the pick's creator id to accomplish
// the delete, and we don't use the query id for anything. JC
msg->addUUID( "QueryID", panel_pick->getPickCreatorID() );
gAgent.sendReliableMessage();
}
else
{
LLAvatarPropertiesProcessor::getInstance()->sendPickDelete(panel_pick->getPickID());
}
tabs->removeTabPanel(panel_pick);
delete panel_pick;
panel_pick = NULL;
childSetEnabled("New...", !gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC));
childSetEnabled("Delete...", tabs->getTabCount());
childSetEnabled("Import...", true);
return true;
}
//-----------------------------------------------------------------------------
// LLPanelAvatar
//-----------------------------------------------------------------------------
LLPanelAvatar::LLPanelAvatar(
const std::string& name,
const LLRect &rect,
BOOL allow_edit)
:
LLPanel(name, rect, FALSE),
mPanelSecondLife(NULL),
mPanelAdvanced(NULL),
mPanelClassified(NULL),
mPanelPicks(NULL),
mPanelNotes(NULL),
mPanelFirstLife(NULL),
mPanelWeb(NULL),
mAvatarID(LLUUID::null), // mAvatarID is set with setAvatarID()
mHaveProperties(FALSE),
mHaveStatistics(FALSE),
mHaveNotes(false),
mLastNotes(),
mAllowEdit(allow_edit)
{
sAllPanels.push_back(this);
LLCallbackMap::map_t factory_map;
factory_map["2nd Life"] = LLCallbackMap(createPanelAvatarSecondLife, this);
factory_map["WebProfile"] = LLCallbackMap(createPanelAvatarWeb, this);
factory_map["Interests"] = LLCallbackMap(createPanelAvatarInterests, this);
factory_map["Picks"] = LLCallbackMap(createPanelAvatarPicks, this);
factory_map["Classified"] = LLCallbackMap(createPanelAvatarClassified, this);
factory_map["1st Life"] = LLCallbackMap(createPanelAvatarFirstLife, this);
factory_map["My Notes"] = LLCallbackMap(createPanelAvatarNotes, this);
mCommitCallbackRegistrar.add("Profile.Web", boost::bind(LLAvatarActions::showProfile, boost::bind(&LLPanelAvatar::getAvatarID, this), true));
mCommitCallbackRegistrar.add("Profile.TeleportRequest", boost::bind(LLAvatarActions::teleportRequest, boost::bind(&LLPanelAvatar::getAvatarID, this)));
LLUICtrlFactory::getInstance()->buildPanel(this, "panel_avatar.xml", &factory_map);
selectTab(0);
}
BOOL LLPanelAvatar::postBuild()
{
mTab = getChild<LLTabContainer>("tab");
LLUICtrl* ctrl = getChild<LLUICtrl>("Kick");
ctrl->setCommitCallback(boost::bind(LLAvatarActions::kick, boost::bind(&LLPanelAvatar::getAvatarID, this)));
ctrl->setVisible(false);
ctrl->setEnabled(false);
ctrl = getChild<LLUICtrl>("Freeze");
ctrl->setCommitCallback(boost::bind(LLAvatarActions::freeze, boost::bind(&LLPanelAvatar::getAvatarID, this)));
ctrl->setVisible(false);
ctrl->setEnabled(false);
ctrl = getChild<LLUICtrl>("Unfreeze");
ctrl->setCommitCallback(boost::bind(LLAvatarActions::unfreeze, boost::bind(&LLPanelAvatar::getAvatarID, this)));
ctrl->setVisible(false);
ctrl->setEnabled(false);
ctrl = getChild<LLUICtrl>("csr_btn");
ctrl->setCommitCallback(boost::bind(LLAvatarActions::csr, boost::bind(&LLPanelAvatar::getAvatarID, this)));
ctrl->setVisible(false);
ctrl->setEnabled(false);
getChild<LLUICtrl>("OK")->setCommitCallback(boost::bind(&LLPanelAvatar::onClickOK, this));
getChild<LLUICtrl>("Cancel")->setCommitCallback(boost::bind(&LLPanelAvatar::onClickCancel, this));
getChild<LLUICtrl>("copy_flyout")->setCommitCallback(boost::bind(&LLPanelAvatar::onClickCopy, this, _2));
getChildView("web_profile")->setVisible(!gSavedSettings.getString("WebProfileURL").empty());
if (mTab && !sAllowFirstLife)
{
LLPanel* panel = mTab->getPanelByName("1st Life");
if (panel) mTab->removeTabPanel(panel);
panel = mTab->getPanelByName("WebProfile");
if (panel) mTab->removeTabPanel(panel);
}
//This text never changes. We simply toggle visibility.
ctrl = getChild<LLUICtrl>("online_yes");
ctrl->setVisible(false);
ctrl->setColor(LLColor4::green);
return TRUE;
}
LLPanelAvatar::~LLPanelAvatar()
{
LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarID, this);
sAllPanels.remove(this);
mCacheConnection.disconnect();
}
BOOL LLPanelAvatar::canClose()
{
return !mPanelClassified || mPanelClassified->canClose();
}
void LLPanelAvatar::setOnlineStatus(EOnlineStatus online_status)
{
// Online status NO could be because they are hidden
// If they are a friend, we may know the truth!
if ((ONLINE_STATUS_YES != online_status)
&& mIsFriend
&& LLAvatarTracker::instance().isBuddyOnline(mAvatarID))
{
online_status = ONLINE_STATUS_YES;
}
if(mPanelSecondLife)
mPanelSecondLife->childSetVisible("online_yes", online_status == ONLINE_STATUS_YES);
LLView* offer_tp(getChildView("Offer Teleport..."));
LLView* map_stalk(getChildView("Find on Map"));
// Since setOnlineStatus gets called after setAvatarID
// need to make sure that "Offer Teleport" doesn't get set
// to TRUE again for yourself
if (mAvatarID != gAgentID)
{
offer_tp->setVisible(true);
map_stalk->setVisible(true);
bool prelude(gAgent.inPrelude());
bool godlike(gAgent.isGodlike());
offer_tp->setEnabled(!prelude /*(&& online_status == ONLINE_STATUS_YES)*/);
offer_tp->setToolTip(godlike ? getString("TeleportGod") : prelude ? getString("TeleportPrelude") : getString("TeleportNormal"));
// Note: we don't always know online status, so always allow gods to try to track
map_stalk->setEnabled(godlike || is_agent_mappable(mAvatarID));
map_stalk->setToolTip(!mIsFriend ? getString("ShowOnMapNonFriend") : (ONLINE_STATUS_YES != online_status) ? getString("ShowOnMapFriendOffline") : getString("ShowOnMapFriendOnline"));
}
}
void LLPanelAvatar::onAvatarNameResponse(const LLUUID& agent_id, const LLAvatarName& av_name)
{
mCacheConnection.disconnect();
getChild<LLLineEditor>("dnname")->setText(gSavedSettings.getBOOL("SinguCompleteNameProfiles") ? av_name.getCompleteName() : av_name.getNSName());
}
void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id)
{
if (avatar_id.isNull()) return;
//BOOL avatar_changed = FALSE;
if (avatar_id != mAvatarID)
{
//avatar_changed = TRUE;
if (mAvatarID.notNull())
LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarID, this);
mAvatarID = avatar_id;
}
LLAvatarPropertiesProcessor::getInstance()->addObserver(mAvatarID, this);
// Determine if we have their calling card.
mIsFriend = LLAvatarActions::isFriend(mAvatarID);
// setOnlineStatus uses mIsFriend
setOnlineStatus(ONLINE_STATUS_NO);
bool own_avatar(mAvatarID == gAgentID);
for(std::list<LLPanelAvatarTab*>::iterator it=mAvatarPanelList.begin();it!=mAvatarPanelList.end();++it)
{
(*it)->setAvatarID(avatar_id);
}
if (mPanelSecondLife) mPanelSecondLife->enableControls(own_avatar && mAllowEdit);
if (mPanelWeb) mPanelWeb->enableControls(own_avatar && mAllowEdit);
if (mPanelAdvanced) mPanelAdvanced->enableControls(own_avatar && mAllowEdit);
// Teens don't have this.
if (mPanelFirstLife) mPanelFirstLife->enableControls(own_avatar && mAllowEdit);
if (LLDropTarget* drop_target = findChild<LLDropTarget>("drop_target_rect"))
drop_target->setEntityID(mAvatarID);
mCacheConnection.disconnect();
mCacheConnection = LLAvatarNameCache::get(avatar_id, boost::bind(&LLPanelAvatar::onAvatarNameResponse, this, _1, _2));
if (auto key_edit = getChildView("avatar_key"))
key_edit->setValue(mAvatarID.asString());
// While we're waiting for data off the network, clear out the old data.
if (mPanelSecondLife)
mPanelSecondLife->clearControls();
if (mPanelPicks)
mPanelPicks->deletePickPanels();
if (mPanelPicks)
mPanelPicks->setDataRequested(false);
if (mPanelClassified)
mPanelClassified->deleteClassifiedPanels();
if (mPanelClassified)
mPanelClassified->setDataRequested(false);
if (mPanelNotes)
mPanelNotes->clearControls();
if (mPanelNotes)
mPanelNotes->setDataRequested(false);
mHaveNotes = false;
mLastNotes.clear();
// Request just the first two pages of data. The picks,
// classifieds, and notes will be requested when that panel
// is made visible. JC
sendAvatarPropertiesRequest();
LLView* view(getChildView("OK"));
view->setVisible(own_avatar && mAllowEdit);
view->setEnabled(false); // OK button disabled until properties data arrives
view = getChildView("Cancel");
view->setVisible(own_avatar && mAllowEdit);
view->setEnabled(own_avatar && mAllowEdit);
view = getChildView("Instant Message...");
view->setVisible(!own_avatar);
view->setEnabled(false);
view = getChildView("GroupInvite_Button");
view->setVisible(!own_avatar);
view->setEnabled(false);
view = getChildView("Mute");
view->setVisible(!own_avatar);
view->setEnabled(false);
if (own_avatar)
{
view = getChildView("Offer Teleport...");
view->setVisible(false);
view->setEnabled(false);
view = getChildView("Find on Map");
view->setVisible(false);
view->setEnabled(false);
}
view = getChildView("Add Friend...");
view->setVisible(!own_avatar);
view->setEnabled(!own_avatar && !mIsFriend);
view = getChildView("Pay...");
view->setVisible(!own_avatar);
view->setEnabled(false);
getChildView("Log")->setVisible(!own_avatar);
getChild<LLNameEditor>("avatar_key")->setText(avatar_id.asString());
bool is_god = gAgent.isGodlike();
view = getChildView("Kick");
view->setVisible(is_god);
view->setEnabled(is_god);
view = getChildView("Freeze");
view->setVisible(is_god);
view->setEnabled(is_god);
view = getChildView("Unfreeze");
view->setVisible(is_god);
view->setEnabled(is_god);
view = getChildView("csr_btn");
view->setVisible(is_god);
view->setEnabled(is_god);
}
void LLPanelAvatar::resetGroupList()
{
// only get these updates asynchronously via the group floater, which works on the agent only
if (mAvatarID != gAgentID) return;
if (mPanelSecondLife)
{
LLScrollListCtrl* group_list = mPanelSecondLife->getChild<LLScrollListCtrl>("groups");
if (group_list)
{
const LLUUID selected_id = group_list->getSelectedValue();
const S32 selected_idx = group_list->getFirstSelectedIndex();
const S32 scroll_pos = group_list->getScrollPos();
group_list->deleteAllItems();
S32 count = gAgent.mGroups.size();
for(S32 i = 0; i < count; ++i)
{
LLGroupData group_data = gAgent.mGroups[i];
const LLUUID& id(group_data.mID);
LLScrollListItem::Params row;
row.value(id);
std::string font_style = group_data.mListInProfile ? "BOLD" : "NORMAL";
if (id == gAgent.getGroupID())
font_style.append("|ITALIC");
/* Show group title? DUMMY_POWER for Don Grep
(group_data.mOfficer ? "Officer of " : "Member of ") + group_data.mName;
*/
row.columns.add(LLScrollListCell::Params().value(group_data.mName).font("SANSSERIF_SMALL").font_style(font_style).width(0));
group_list->addRow(row, ADD_SORTED);
}
if (selected_id.notNull())
group_list->selectByValue(selected_id);
if (selected_idx != group_list->getFirstSelectedIndex()) //if index changed then our stored pos is pointless.
group_list->scrollToShowSelected();
else
group_list->setScrollPos(scroll_pos);
}
}
}
void LLPanelAvatar::onClickCopy(const LLSD& val)
{
if (val.isUndefined())
{
LL_INFOS() << "Copy agent id: " << mAvatarID << LL_ENDL;
gViewerWindow->getWindow()->copyTextToClipboard(utf8str_to_wstring(mAvatarID.asString()));
}
else
{
void copy_profile_uri(const LLUUID& id, bool group = false);
copy_profile_uri(mAvatarID);
}
}
void LLPanelAvatar::onClickOK()
{
// JC: Only save the data if we actually got the original
// properties. Otherwise we might save blanks into
// the database.
if (mHaveProperties)
{
sendAvatarPropertiesUpdate();
if (mTab->getCurrentPanel() != mPanelClassified || mPanelClassified->titleIsValid())
{
mPanelClassified->apply();
if (LLFloaterAvatarInfo* infop = LLFloaterAvatarInfo::getInstance(mAvatarID))
infop->close();
}
}
}
void LLPanelAvatar::onClickCancel()
{
if (LLFloaterAvatarInfo* infop = LLFloaterAvatarInfo::getInstance(mAvatarID))
infop->close();
else // We're in the Search directory and are cancelling an edit to our own profile, so reset.
sendAvatarPropertiesRequest();
}
void LLPanelAvatar::sendAvatarPropertiesRequest()
{
LL_DEBUGS() << "LLPanelAvatar::sendAvatarPropertiesRequest()" << LL_ENDL;
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(mAvatarID);
}
void LLPanelAvatar::sendAvatarNotesUpdate()
{
std::string notes = mPanelNotes->childGetValue("notes edit").asString();
if (!mHaveNotes && (notes.empty() || notes == getString("Loading")) || // no notes from server and no user updates
notes == mLastNotes) // Avatar notes unchanged
return;
auto& inst(LLAvatarPropertiesProcessor::instance());
inst.sendNotes(mAvatarID, notes);
inst.sendAvatarNotesRequest(mAvatarID); // Rerequest notes to update anyone that might be listening, also to be sure we match the server.
}
// virtual
void LLPanelAvatar::processProperties(void* data, EAvatarProcessorType type)
{
if (type == APT_PROPERTIES)
{
const LLAvatarData* pAvatarData = static_cast<const LLAvatarData*>( data );
if (pAvatarData && (mAvatarID == pAvatarData->avatar_id) && (pAvatarData->avatar_id.notNull()))
{
childSetEnabled("Instant Message...",TRUE);
childSetEnabled("GroupInvite_Button",TRUE);
childSetEnabled("Pay...",TRUE);
childSetEnabled("Mute",TRUE);
mHaveProperties = TRUE;
enableOKIfReady();
/*tm t;
if (sscanf(born_on.c_str(), "%u/%u/%u", &t.tm_mon, &t.tm_mday, &t.tm_year) == 3 && t.tm_year > 1900)
{
t.tm_year -= 1900;
t.tm_mon--;
t.tm_hour = t.tm_min = t.tm_sec = 0;
timeStructToFormattedString(&t, gSavedSettings.getString("ShortDateFormat"), born_on);
}*/
setOnlineStatus(pAvatarData->flags & AVATAR_ONLINE ? ONLINE_STATUS_YES : ONLINE_STATUS_NO);
getChild<LLTextEditor>("about")->setText(pAvatarData->about_text, false);
}
}
else if (type == APT_NOTES)
{
const LLAvatarNotes* pAvatarNotes = static_cast<const LLAvatarNotes*>( data );
if (pAvatarNotes && (mAvatarID == pAvatarNotes->target_id) && (pAvatarNotes->target_id != LLUUID::null))
{
if (!mHaveNotes) // Only update the UI if we don't already have the notes, we could be editing them now!
{
auto notes = getChildView("notes edit");
notes->setEnabled(true);
notes->setValue(pAvatarNotes->notes);
mHaveNotes = true;
}
mLastNotes = pAvatarNotes->notes;
}
}
}
// Don't enable the OK button until you actually have the data.
// Otherwise you will write blanks back into the database.
void LLPanelAvatar::enableOKIfReady()
{
LLView* OK(getChildView("OK"));
OK->setEnabled(mHaveProperties && OK->getVisible());
}
void LLPanelAvatar::sendAvatarPropertiesUpdate()
{
LL_INFOS() << "Sending avatarinfo update" << LL_ENDL;
LLAvatarData avatar_data;
avatar_data.image_id = mPanelSecondLife->getChild<LLTextureCtrl>("img")->getImageAssetID();
avatar_data.fl_image_id = mPanelFirstLife ? mPanelFirstLife->getChild<LLTextureCtrl>("img")->getImageAssetID() : LLUUID::null;
avatar_data.about_text = mPanelSecondLife->childGetValue("about").asString();
avatar_data.fl_about_text = mPanelFirstLife ? mPanelFirstLife->childGetValue("about").asString() : LLStringUtil::null;
avatar_data.allow_publish = sAllowFirstLife && childGetValue("allow_publish");
avatar_data.profile_url = mPanelWeb->childGetText("url_edit");
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesUpdate(&avatar_data);
LLAvatarInterestsInfo interests_data;
interests_data.want_to_mask = 0x0;
interests_data.skills_mask = 0x0;
mPanelAdvanced->getWantSkills(&interests_data.want_to_mask, interests_data.want_to_text, &interests_data.skills_mask, interests_data.skills_text, interests_data.languages_text);
LLAvatarPropertiesProcessor::getInstance()->sendAvatarInterestsUpdate(&interests_data);
}
void LLPanelAvatar::selectTab(S32 tabnum)
{
if (mTab) mTab->selectTab(tabnum);
}
void LLPanelAvatar::selectTabByName(std::string tab_name)
{
if (!mTab) return;
if (tab_name.empty())
mTab->selectFirstTab();
else
mTab->selectTabByName(tab_name);
}
void* LLPanelAvatar::createPanelAvatarSecondLife(void* data)
{
LLPanelAvatar* self = (LLPanelAvatar*)data;
self->mPanelSecondLife = new LLPanelAvatarSecondLife("2nd Life", LLRect(), self);
return self->mPanelSecondLife;
}
void* LLPanelAvatar::createPanelAvatarWeb(void* data)
{
LLPanelAvatar* self = (LLPanelAvatar*)data;
self->mPanelWeb = new LLPanelAvatarWeb("Web",LLRect(),self);
return self->mPanelWeb;
}
void* LLPanelAvatar::createPanelAvatarInterests(void* data)
{
LLPanelAvatar* self = (LLPanelAvatar*)data;
self->mPanelAdvanced = new LLPanelAvatarAdvanced("Interests", LLRect(), self);
return self->mPanelAdvanced;
}
void* LLPanelAvatar::createPanelAvatarPicks(void* data)
{
LLPanelAvatar* self = (LLPanelAvatar*)data;
self->mPanelPicks = new LLPanelAvatarPicks("Picks", LLRect(), self);
return self->mPanelPicks;
}
void* LLPanelAvatar::createPanelAvatarClassified(void* data)
{
LLPanelAvatar* self = (LLPanelAvatar*)data;
self->mPanelClassified = new LLPanelAvatarClassified("Classified", LLRect(), self);
return self->mPanelClassified;
}
void* LLPanelAvatar::createPanelAvatarFirstLife(void* data)
{
LLPanelAvatar* self = (LLPanelAvatar*)data;
self->mPanelFirstLife = new LLPanelAvatarFirstLife("1st Life", LLRect(), self);
return self->mPanelFirstLife;
}
void* LLPanelAvatar::createPanelAvatarNotes(void* data)
{
LLPanelAvatar* self = (LLPanelAvatar*)data;
self->mPanelNotes = new LLPanelAvatarNotes("My Notes", LLRect(),self);
return self->mPanelNotes;
}