# Conflicts:
#	indra/newview/llpanelprofile.cpp
#	indra/newview/llviewermenu.cpp
#	indra/newview/skins/default/xui/en/panel_edit_profile.xml
#	indra/newview/skins/default/xui/en/panel_profile_secondlife.xml
master
Ansariel 2022-03-19 14:35:42 +01:00
commit f77a134402
12 changed files with 610 additions and 188 deletions

View File

@ -36,6 +36,7 @@
#include "llstartup.h"
// Linden library includes
#include "llavataractions.h" // for getProfileUrl
#include "lldate.h"
#include "lltrans.h"
#include "llui.h" // LLUI::getLanguage()
@ -94,54 +95,115 @@ void LLAvatarPropertiesProcessor::removeObserver(const LLUUID& avatar_id, LLAvat
}
}
void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string method)
void LLAvatarPropertiesProcessor::sendRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method)
{
// this is the startup state when send_complete_agent_movement() message is sent.
// Before this messages won't work so don't bother trying
if (LLStartUp::getStartupState() <= STATE_AGENT_SEND)
{
return;
}
if (avatar_id.isNull())
{
return;
}
// Suppress duplicate requests while waiting for a response from the network
if (isPendingRequest(avatar_id, type))
{
// waiting for a response, don't re-request
return;
}
// indicate we're going to make a request
addPendingRequest(avatar_id, type);
std::vector<std::string> strings;
strings.push_back( avatar_id.asString() );
send_generic_message(method, strings);
// Cap is not ready for global use
//std::string cap = gAgent.getRegionCapability("AgentProfile");
std::string cap;
switch (type)
{
case APT_PROPERTIES:
if (cap.empty())
{
// indicate we're going to make a request
sendAvatarPropertiesRequestMessage(avatar_id);
}
else
{
initAgentProfileCapRequest(avatar_id, cap);
}
break;
case APT_PICKS:
case APT_GROUPS:
case APT_NOTES:
if (cap.empty())
{
// indicate we're going to make a request
sendGenericRequest(avatar_id, type, method);
}
else
{
initAgentProfileCapRequest(avatar_id, cap);
}
break;
default:
sendGenericRequest(avatar_id, type, method);
break;
}
}
void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method)
{
// indicate we're going to make a request
addPendingRequest(avatar_id, type);
std::vector<std::string> strings;
strings.push_back(avatar_id.asString());
send_generic_message(method, strings);
}
void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequestMessage(const LLUUID& avatar_id)
{
addPendingRequest(avatar_id, APT_PROPERTIES);
LLMessageSystem *msg = gMessageSystem;
msg->newMessageFast(_PREHASH_AvatarPropertiesRequest);
msg->nextBlockFast(_PREHASH_AgentData);
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
msg->addUUIDFast(_PREHASH_AvatarID, avatar_id);
gAgent.sendReliableMessage();
}
void LLAvatarPropertiesProcessor::initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url)
{
addPendingRequest(avatar_id, APT_PROPERTIES);
addPendingRequest(avatar_id, APT_PICKS);
addPendingRequest(avatar_id, APT_GROUPS);
addPendingRequest(avatar_id, APT_NOTES);
LLCoros::instance().launch("requestAgentUserInfoCoro",
boost::bind(requestAvatarPropertiesCoro, cap_url, avatar_id));
}
void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id)
{
// this is the startup state when send_complete_agent_movement() message is sent.
// Before this, the AvatarPropertiesRequest message
// won't work so don't bother trying
if (LLStartUp::getStartupState() <= STATE_AGENT_SEND)
{
return;
}
if (isPendingRequest(avatar_id, APT_PROPERTIES))
{
// waiting for a response, don't re-request
return;
}
// indicate we're going to make a request
addPendingRequest(avatar_id, APT_PROPERTIES);
LLMessageSystem *msg = gMessageSystem;
msg->newMessageFast(_PREHASH_AvatarPropertiesRequest);
msg->nextBlockFast( _PREHASH_AgentData);
msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() );
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
msg->addUUIDFast( _PREHASH_AvatarID, avatar_id);
gAgent.sendReliableMessage();
sendRequest(avatar_id, APT_PROPERTIES, "AvatarPropertiesRequest");
}
void LLAvatarPropertiesProcessor::sendAvatarPicksRequest(const LLUUID& avatar_id)
{
sendGenericRequest(avatar_id, APT_PICKS, "avatarpicksrequest");
std::string cap = gAgent.getRegionCapability("AgentProfile");
if (!cap.empty())
{
// AgentProfile capability covers picks
sendAvatarPropertiesRequest(avatar_id);
}
else
{
sendGenericRequest(avatar_id, APT_PICKS, "avatarpicksrequest");
}
}
void LLAvatarPropertiesProcessor::sendAvatarNotesRequest(const LLUUID& avatar_id)
@ -266,6 +328,113 @@ bool LLAvatarPropertiesProcessor::hasPaymentInfoOnFile(const LLAvatarData* avata
return ((avatar_data->flags & AVATAR_TRANSACTED) || (avatar_data->flags & AVATAR_IDENTIFIED));
}
// static
void LLAvatarPropertiesProcessor::requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id)
{
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("requestAvatarPropertiesCoro", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
LLCore::HttpHeaders::ptr_t httpHeaders;
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
httpOpts->setFollowRedirects(true);
std::string finalUrl = cap_url + "/" + agent_id.asString();
LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl, httpOpts, httpHeaders);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
if (!status
|| !result.has("id")
|| agent_id != result["id"].asUUID())
{
LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << agent_id << LL_ENDL;
LLAvatarPropertiesProcessor* self = getInstance();
self->removePendingRequest(agent_id, APT_PROPERTIES);
self->removePendingRequest(agent_id, APT_PICKS);
self->removePendingRequest(agent_id, APT_GROUPS);
self->removePendingRequest(agent_id, APT_NOTES);
return;
}
// Avatar Data
LLAvatarData avatar_data;
std::string birth_date;
avatar_data.agent_id = agent_id;
avatar_data.avatar_id = agent_id;
avatar_data.image_id = result["sl_image_id"].asUUID();
avatar_data.fl_image_id = result["fl_image_id"].asUUID();
avatar_data.partner_id = result["partner_id"].asUUID();
avatar_data.about_text = result["sl_about_text"].asString();
avatar_data.fl_about_text = result["fl_about_text"].asString();
avatar_data.born_on = result["member_since"].asDate();
avatar_data.profile_url = getProfileURL(agent_id.asString());
avatar_data.flags = 0;
avatar_data.caption_index = 0;
LLAvatarPropertiesProcessor* self = getInstance();
// Request processed, no longer pending
self->removePendingRequest(agent_id, APT_PROPERTIES);
self->notifyObservers(agent_id, &avatar_data, APT_PROPERTIES);
// Picks
LLSD picks_array = result["picks"];
LLAvatarPicks avatar_picks;
avatar_picks.agent_id = agent_id; // Not in use?
avatar_picks.target_id = agent_id;
for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it)
{
const LLSD& pick_data = *it;
avatar_picks.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString());
}
// Request processed, no longer pending
self->removePendingRequest(agent_id, APT_PICKS);
self->notifyObservers(agent_id, &avatar_picks, APT_PICKS);
// Groups
LLSD groups_array = result["groups"];
LLAvatarGroups avatar_groups;
avatar_groups.agent_id = agent_id; // Not in use?
avatar_groups.avatar_id = agent_id; // target_id
for (LLSD::array_const_iterator it = groups_array.beginArray(); it != groups_array.endArray(); ++it)
{
const LLSD& group_info = *it;
LLAvatarGroups::LLGroupData group_data;
group_data.group_powers = 0; // Not in use?
group_data.group_title = group_info["name"].asString(); // Missing data, not in use?
group_data.group_id = group_info["id"].asUUID();
group_data.group_name = group_info["name"].asString();
group_data.group_insignia_id = group_info["image_id"].asUUID();
avatar_groups.group_list.push_back(group_data);
}
self->removePendingRequest(agent_id, APT_GROUPS);
self->notifyObservers(agent_id, &avatar_groups, APT_GROUPS);
// Notes
LLAvatarNotes avatar_notes;
avatar_notes.agent_id = agent_id;
avatar_notes.target_id = agent_id;
avatar_notes.notes = result["notes"].asString();
// Request processed, no longer pending
self->removePendingRequest(agent_id, APT_NOTES);
self->notifyObservers(agent_id, &avatar_notes, APT_NOTES);
}
void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* msg, void**)
{
LLAvatarData avatar_data;
@ -404,7 +573,7 @@ void LLAvatarPropertiesProcessor::processAvatarNotesReply(LLMessageSystem* msg,
void LLAvatarPropertiesProcessor::processAvatarPicksReply(LLMessageSystem* msg, void**)
{
LLAvatarPicks avatar_picks;
msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_picks.target_id);
msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_picks.agent_id);
msg->getUUID(_PREHASH_AgentData, _PREHASH_TargetID, avatar_picks.target_id);
S32 block_count = msg->getNumberOfBlocks(_PREHASH_Data);

View File

@ -248,6 +248,8 @@ public:
static bool hasPaymentInfoOnFile(const LLAvatarData* avatar_data);
static void requestAvatarPropertiesCoro(std::string cap_url, LLUUID agent_id);
static void processAvatarPropertiesReply(LLMessageSystem* msg, void**);
static void processAvatarInterestsReply(LLMessageSystem* msg, void**);
@ -266,7 +268,10 @@ public:
protected:
void sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string method);
void sendRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method);
void sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string &method);
void sendAvatarPropertiesRequestMessage(const LLUUID& avatar_id);
void initAgentProfileCapRequest(const LLUUID& avatar_id, const std::string& cap_url);
void notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type);

View File

@ -29,6 +29,7 @@
// Common
#include "llavatarnamecache.h"
#include "llsdutil.h"
#include "llslurl.h"
#include "lldateutil.h" //ageFromDate
@ -85,7 +86,206 @@ static const std::string PANEL_PICKS = "panel_profile_picks";
static const std::string PANEL_CLASSIFIEDS = "panel_profile_classifieds";
static const std::string PANEL_FIRSTLIFE = "panel_profile_firstlife";
static const std::string PANEL_NOTES = "panel_profile_notes";
static const std::string PANEL_PROFILE_VIEW = "panel_profile_view";
static const std::string PROFILE_PROPERTIES_CAP = "AgentProfile";
//////////////////////////////////////////////////////////////////////////
void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id)
{
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("request_avatar_properties_coro", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
LLCore::HttpHeaders::ptr_t httpHeaders;
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
httpOpts->setFollowRedirects(true);
std::string finalUrl = cap_url + "/" + agent_id.asString();
LLSD result = httpAdapter->getAndSuspend(httpRequest, finalUrl, httpOpts, httpHeaders);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
if (!status
|| !result.has("id")
|| agent_id != result["id"].asUUID())
{
LL_WARNS("AvatarProperties") << "Failed to get agent information for id " << agent_id << LL_ENDL;
return;
}
LLFloater* floater_profile = LLFloaterReg::findInstance("profile", LLSD().with("id", agent_id));
if (!floater_profile)
{
// floater is dead, so panels are dead as well
return;
}
LLPanel *panel = floater_profile->findChild<LLPanel>(PANEL_PROFILE_VIEW, TRUE);
LLPanelProfile *panel_profile = dynamic_cast<LLPanelProfile*>(panel);
if (!panel_profile)
{
LL_WARNS() << PANEL_PROFILE_VIEW << " not found" << LL_ENDL;
return;
}
// Avatar Data
LLAvatarData *avatar_data = &panel_profile->mAvatarData;
std::string birth_date;
avatar_data->agent_id = agent_id;
avatar_data->avatar_id = agent_id;
avatar_data->image_id = result["sl_image_id"].asUUID();
avatar_data->fl_image_id = result["fl_image_id"].asUUID();
avatar_data->partner_id = result["partner_id"].asUUID();
// Todo: new descriptio size is 65536, check if it actually fits or has scroll
avatar_data->about_text = result["sl_about_text"].asString();
// Todo: new descriptio size is 65536, check if it actually fits or has scroll
avatar_data->fl_about_text = result["fl_about_text"].asString();
avatar_data->born_on = result["member_since"].asDate();
avatar_data->profile_url = getProfileURL(agent_id.asString());
avatar_data->flags = 0;
if (result["online"].asBoolean())
{
avatar_data->flags |= AVATAR_ONLINE;
}
if (result["allow_publish"].asBoolean())
{
avatar_data->flags |= AVATAR_ALLOW_PUBLISH;
}
avatar_data->caption_index = 0;
if (result.has("charter_member")) // won't be present if "caption" is set
{
avatar_data->caption_index = result["charter_member"].asInteger();
}
else if (result.has("caption"))
{
avatar_data->caption_text = result["caption"].asString();
}
panel = floater_profile->findChild<LLPanel>(PANEL_SECONDLIFE, TRUE);
LLPanelProfileSecondLife *panel_sl = dynamic_cast<LLPanelProfileSecondLife*>(panel);
if (panel_sl)
{
panel_sl->processProfileProperties(avatar_data);
}
panel = floater_profile->findChild<LLPanel>(PANEL_WEB, TRUE);
LLPanelProfileWeb *panel_web = dynamic_cast<LLPanelProfileWeb*>(panel);
if (panel_web)
{
panel_web->updateButtons();
}
panel = floater_profile->findChild<LLPanel>(PANEL_FIRSTLIFE, TRUE);
LLPanelProfileFirstLife *panel_first = dynamic_cast<LLPanelProfileFirstLife*>(panel);
if (panel_first)
{
panel_first->mCurrentDescription = avatar_data->fl_about_text;
panel_first->mDescriptionEdit->setValue(panel_first->mCurrentDescription);
panel_first->mPicture->setValue(avatar_data->fl_image_id);
panel_first->updateButtons();
}
// Picks
LLSD picks_array = result["picks"];
LLAvatarPicks avatar_picks;
avatar_picks.agent_id = agent_id; // Not in use?
avatar_picks.target_id = agent_id;
for (LLSD::array_const_iterator it = picks_array.beginArray(); it != picks_array.endArray(); ++it)
{
const LLSD& pick_data = *it;
avatar_picks.picks_list.emplace_back(pick_data["id"].asUUID(), pick_data["name"].asString());
}
panel = floater_profile->findChild<LLPanel>(PANEL_PICKS, TRUE);
LLPanelProfilePicks *panel_picks = dynamic_cast<LLPanelProfilePicks*>(panel);
if (panel_picks)
{
panel_picks->processProperties(&avatar_picks);
}
// Groups
LLSD groups_array = result["groups"];
LLAvatarGroups avatar_groups;
avatar_groups.agent_id = agent_id; // Not in use?
avatar_groups.avatar_id = agent_id; // target_id
for (LLSD::array_const_iterator it = groups_array.beginArray(); it != groups_array.endArray(); ++it)
{
const LLSD& group_info = *it;
LLAvatarGroups::LLGroupData group_data;
group_data.group_powers = 0; // Not in use?
group_data.group_title = group_info["name"].asString(); // Missing data, not in use?
group_data.group_id = group_info["id"].asUUID();
group_data.group_name = group_info["name"].asString();
group_data.group_insignia_id = group_info["image_id"].asUUID();
avatar_groups.group_list.push_back(group_data);
}
if (panel_sl)
{
panel_sl->processGroupProperties(&avatar_groups);
}
// Notes
LLAvatarNotes avatar_notes;
avatar_notes.agent_id = agent_id;
avatar_notes.target_id = agent_id;
avatar_notes.notes = result["notes"].asString();
panel = floater_profile->findChild<LLPanel>(PANEL_NOTES, TRUE);
LLPanelProfileNotes *panel_notes = dynamic_cast<LLPanelProfileNotes*>(panel);
if (panel_notes)
{
panel_notes->processProperties(&avatar_notes);
}
}
//TODO: changes take two minutes to propagate!
// Add some storage that holds updated data for two minutes
// for new instances to reuse the data
// Profile data is only relevant to won avatar, but notes
// are for everybody
void put_avatar_properties_coro(std::string cap_url, LLUUID agent_id, LLSD data)
{
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t
httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("request_avatar_properties_coro", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
LLCore::HttpHeaders::ptr_t httpHeaders;
LLCore::HttpOptions::ptr_t httpOpts(new LLCore::HttpOptions);
httpOpts->setFollowRedirects(true);
std::string finalUrl = cap_url + "/" + agent_id.asString();
LLSD result = httpAdapter->putAndSuspend(httpRequest, finalUrl, data, httpOpts, httpHeaders);
LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS];
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
if (!status)
{
LL_WARNS("AvatarProperties") << "Failed to put agent information for id " << agent_id << LL_ENDL;
return;
}
}
//////////////////////////////////////////////////////////////////////////
// LLProfileHandler
@ -419,11 +619,34 @@ void LLPanelProfileSecondLife::apply(LLAvatarData* data)
{
if (getIsLoaded() && getSelfProfile())
{
data->image_id = mSecondLifePic->getImageAssetID();
data->about_text = mDescriptionEdit->getValue().asString();
data->allow_publish = mShowInSearchCheckbox->getValue();
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesUpdate(data);
// Might be a better idea to accumulate changes in floater
// instead of sending a request per tab
std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
if (!cap_url.empty())
{
LLSD params = LLSDMap();
if (data->image_id != mSecondLifePic->getImageAssetID())
{
params["sl_image_id"] = mSecondLifePic->getImageAssetID();
}
if (data->about_text != mDescriptionEdit->getValue().asString())
{
params["sl_about_text"] = mDescriptionEdit->getValue().asString();
}
if ((bool)data->allow_publish != mShowInSearchCheckbox->getValue().asBoolean())
{
params["allow_publish"] = mShowInSearchCheckbox->getValue().asBoolean();
}
if (!params.emptyMap())
{
LLCoros::instance().launch("putAgentUserInfoCoro",
boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), params));
}
}
else
{
LL_WARNS() << "Failed to update profile data, no cap found" << LL_ENDL;
}
}
}
@ -433,7 +656,17 @@ void LLPanelProfileSecondLife::updateData()
if (!getIsLoading() && avatar_id.notNull() && !(getSelfProfile() && !getEmbedded()))
{
setIsLoading();
LLAvatarPropertiesProcessor::getInstance()->sendAvatarGroupsRequest(avatar_id);
std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
if (!cap_url.empty())
{
LLCoros::instance().launch("requestAgentUserInfoCoro",
boost::bind(request_avatar_properties_coro, cap_url, avatar_id));
}
else
{
LL_WARNS() << "Failed to update profile data, no cap found" << LL_ENDL;
}
}
}
@ -446,15 +679,6 @@ void LLPanelProfileSecondLife::processProperties(void* data, EAvatarProcessorTyp
if(avatar_data && getAvatarId() == avatar_data->avatar_id)
{
processProfileProperties(avatar_data);
updateButtons();
}
}
else if (APT_GROUPS == type)
{
LLAvatarGroups* avatar_groups = static_cast<LLAvatarGroups*>(data);
if(avatar_groups && getAvatarId() == avatar_groups->avatar_id)
{
processGroupProperties(avatar_groups);
}
}
}
@ -498,6 +722,8 @@ void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avat
fillPartnerData(avatar_data);
fillAccountStatus(avatar_data);
updateButtons();
}
void LLPanelProfileSecondLife::processGroupProperties(const LLAvatarGroups* avatar_groups)
@ -1360,6 +1586,14 @@ void LLPanelProfileFirstLife::processProperties(void* data, EAvatarProcessorType
}
}
void LLPanelProfileFirstLife::processProperties(const LLAvatarData* avatar_data)
{
mCurrentDescription = avatar_data->fl_about_text;
mDescriptionEdit->setValue(mCurrentDescription);
mPicture->setValue(avatar_data->fl_image_id);
updateButtons();
}
void LLPanelProfileFirstLife::resetData()
{
mDescriptionEdit->setValue(LLStringUtil::null);
@ -1368,6 +1602,26 @@ void LLPanelProfileFirstLife::resetData()
void LLPanelProfileFirstLife::apply(LLAvatarData* data)
{
std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
if (getIsLoaded() && !cap_url.empty())
{
LLSD params = LLSDMap();
if (data->fl_image_id != mPicture->getImageAssetID())
{
params["fl_image_id"] = mPicture->getImageAssetID();
}
if (data->fl_about_text != mDescriptionEdit->getValue().asString())
{
params["fl_about_text"] = mDescriptionEdit->getValue().asString();
}
if (!params.emptyMap())
{
LLCoros::instance().launch("putAgentUserInfoCoro",
boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), params));
}
}
data->fl_image_id = mPicture->getImageAssetID();
data->fl_about_text = mDescriptionEdit->getValue().asString();
}
@ -1413,7 +1667,13 @@ void LLPanelProfileNotes::updateData()
if (!getIsLoading() && avatar_id.notNull())
{
setIsLoading();
LLAvatarPropertiesProcessor::getInstance()->sendAvatarNotesRequest(avatar_id);
std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
if (!cap_url.empty())
{
LLCoros::instance().launch("requestAgentUserInfoCoro",
boost::bind(request_avatar_properties_coro, cap_url, avatar_id));
}
}
}
@ -1423,7 +1683,6 @@ BOOL LLPanelProfileNotes::postBuild()
mMapRights = getChild<LLCheckBoxCtrl>("map_check");
mEditObjectRights = getChild<LLCheckBoxCtrl>("objects_check");
mNotesEditor = getChild<LLTextEditor>("notes_edit");
mCharacterLimitWarning = getChild<LLTextBox>("character_limit_warning");
mEditObjectRights->setCommitCallback(boost::bind(&LLPanelProfileNotes::onCommitRights, this));
@ -1471,10 +1730,19 @@ void LLPanelProfileNotes::fillRightsData()
void LLPanelProfileNotes::onCommitNotes()
{
std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
if (getIsLoaded())
{
std::string notes = mNotesEditor->getValue().asString();
LLAvatarPropertiesProcessor::getInstance()->sendNotes(getAvatarId(),notes);
if (!cap_url.empty())
{
std::string notes = mNotesEditor->getValue().asString();
LLCoros::instance().launch("putAgentUserInfoCoro",
boost::bind(put_avatar_properties_coro, cap_url, getAvatarId(), LLSD().with("notes", notes)));
}
else
{
LL_WARNS() << "Failed to update notes, no cap found" << LL_ENDL;
}
}
}
@ -1548,27 +1816,6 @@ void LLPanelProfileNotes::applyRights()
LLAvatarPropertiesProcessor::getInstance()->sendFriendRights(getAvatarId(), rights);
}
void LLPanelProfileNotes::updateWarning()
{
mCharacterLimitWarning->setText(std::string());
std::string str = getString("header_symbol_limit");
mCharacterLimitWarning->appendText(str, false, LLStyle::Params().color(LLColor4::yellow));
mCharacterLimitWarning->appendText(" ", false, LLStyle::Params());
LLStringUtil::format_map_t args;
if (!mURLWebProfile.empty())
{
args["[PROFILE_URL]"] = mURLWebProfile;
}
else
{
args["[PROFILE_URL]"] = getProfileURL(getAvatarId().asString());
}
str = getString("body_symbol_limit", args);
mCharacterLimitWarning->appendText(str, false, LLStyle::Params());
}
void LLPanelProfileNotes::processProperties(void* data, EAvatarProcessorType type)
{
if (APT_NOTES == type)
@ -1576,28 +1823,22 @@ void LLPanelProfileNotes::processProperties(void* data, EAvatarProcessorType typ
LLAvatarNotes* avatar_notes = static_cast<LLAvatarNotes*>(data);
if (avatar_notes && getAvatarId() == avatar_notes->target_id)
{
mNotesEditor->setValue(avatar_notes->notes);
// <FS:Ansariel> Don't enable editor in embedded mode since there is no way to save them
//mNotesEditor->setEnabled(TRUE);
mNotesEditor->setEnabled(!getEmbedded());
// </FS:Ansariel>
updateButtons();
if (avatar_notes->notes.size() > 1000)
{
mCharacterLimitWarning->setVisible(TRUE);
updateWarning();
}
else
{
mCharacterLimitWarning->setVisible(FALSE);
}
processProperties(avatar_notes);
LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this);
}
}
}
void LLPanelProfileNotes::processProperties(LLAvatarNotes* avatar_notes)
{
mNotesEditor->setValue(avatar_notes->notes);
// <FS:Ansariel> Don't enable editor in embedded mode since there is no way to save them
//mNotesEditor->setEnabled(TRUE);
mNotesEditor->setEnabled(!getEmbedded());
// </FS:Ansariel>
updateButtons();
}
void LLPanelProfileNotes::resetData()
{
resetLoading();
@ -1605,7 +1846,6 @@ void LLPanelProfileNotes::resetData()
mOnlineStatus->setValue(FALSE);
mMapRights->setValue(FALSE);
mEditObjectRights->setValue(FALSE);
mCharacterLimitWarning->setVisible(FALSE);
mURLWebProfile.clear();
}
@ -1652,11 +1892,6 @@ void LLPanelProfileNotes::onAvatarNameCache(const LLUUID& agent_id, const LLAvat
}
mURLWebProfile = getProfileURL(username, false);
if (mCharacterLimitWarning->getVisible())
{
updateWarning();
}
}
@ -1753,10 +1988,18 @@ void LLPanelProfile::onOpen(const LLSD& key)
void LLPanelProfile::updateData()
{
LLUUID avatar_id = getAvatarId();
// Todo: getIsloading functionality needs to be expanded to
// include 'inited' or 'data_provided' state to not rerequest
if (!getIsLoading() && avatar_id.notNull())
{
setIsLoading();
LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(avatar_id);
std::string cap_url = gAgent.getRegionCapability(PROFILE_PROPERTIES_CAP);
if (!cap_url.empty())
{
LLCoros::instance().launch("requestAgentUserInfoCoro",
boost::bind(request_avatar_properties_coro, cap_url, avatar_id));
}
}
}
@ -1766,11 +2009,9 @@ void LLPanelProfile::apply()
{
//KC - AvatarData is spread over 3 different panels
// collect data from the last 2 and give to the first to save
LLAvatarData data = LLAvatarData();
data.avatar_id = gAgentID;
mPanelFirstlife->apply(&data);
mPanelWeb->apply(&data);
mPanelSecondlife->apply(&data);
mPanelFirstlife->apply(&mAvatarData);
mPanelWeb->apply(&mAvatarData);
mPanelSecondlife->apply(&mAvatarData);
mPanelInterests->apply();
mPanelPicks->apply();

View File

@ -104,6 +104,8 @@ public:
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);
protected:
/**
* Process profile related data received from server.
@ -251,6 +253,8 @@ public:
void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);
protected:
/*virtual*/ void updateButtons();
void onCommitLoad(LLUICtrl* ctrl);
@ -316,6 +320,7 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
void processProperties(const LLAvatarData* avatar_data);
void resetData();
@ -324,6 +329,8 @@ public:
*/
void apply(LLAvatarData* data);
friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);
protected:
/*virtual*/ void updateButtons();
void onDescriptionFocusReceived();
@ -358,6 +365,7 @@ public:
/*virtual*/ BOOL postBuild();
/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
void processProperties(LLAvatarNotes* avatar_notes);
void resetData();
@ -383,13 +391,11 @@ protected:
void enableCheckboxes(bool enable);
void applyRights();
void updateWarning();
LLCheckBoxCtrl* mOnlineStatus;
LLCheckBoxCtrl* mMapRights;
LLCheckBoxCtrl* mEditObjectRights;
LLTextEditor* mNotesEditor;
LLTextBox* mCharacterLimitWarning;
std::string mURLWebProfile;
@ -428,6 +434,10 @@ public:
void showClassified(const LLUUID& classified_id = LLUUID::null, bool edit = false);
LLAvatarData getAvatarData() { return mAvatarData; };
friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);
private:
void onTabChange();
@ -439,6 +449,13 @@ private:
LLPanelProfileFirstLife* mPanelFirstlife;
LLPanelProfileNotes* mPanelNotes;
LLTabContainer* mTabContainer;
// Todo: due to server taking minutes to update this needs a more long term storage
// to reuse recently saved values if user opens floater again
// Storage implementation depends onto how a cap will be implemented, if cap will be
// enought to fully update LLAvatarPropertiesProcessor, then this storage can be
// implemented there.
LLAvatarData mAvatarData;
};
#endif //LL_LLPANELPROFILE_H

View File

@ -258,68 +258,73 @@ void LLPanelProfilePicks::processProperties(void* data, EAvatarProcessorType typ
LLAvatarPicks* avatar_picks = static_cast<LLAvatarPicks*>(data);
if (avatar_picks && getAvatarId() == avatar_picks->target_id)
{
LLUUID selected_id = mPickToSelectOnLoad;
if (mPickToSelectOnLoad.isNull())
{
if (mTabContainer->getTabCount() > 0)
{
LLPanelProfilePick* active_pick_panel = dynamic_cast<LLPanelProfilePick*>(mTabContainer->getCurrentPanel());
if (active_pick_panel)
{
selected_id = active_pick_panel->getPickId();
}
}
}
mTabContainer->deleteAllTabs();
LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin();
for (; avatar_picks->picks_list.end() != it; ++it)
{
LLUUID pick_id = it->first;
std::string pick_name = it->second;
LLPanelProfilePick* pick_panel = LLPanelProfilePick::create();
pick_panel->setPickId(pick_id);
pick_panel->setPickName(pick_name);
pick_panel->setAvatarId(getAvatarId());
mTabContainer->addTabPanel(
LLTabContainer::TabPanelParams().
panel(pick_panel).
select_tab(selected_id == pick_id).
label(pick_name));
if (selected_id == pick_id)
{
mPickToSelectOnLoad = LLUUID::null;
}
}
BOOL no_data = !mTabContainer->getTabCount();
mNoItemsLabel->setVisible(no_data);
if (no_data)
{
if(getSelfProfile())
{
mNoItemsLabel->setValue(LLTrans::getString("NoPicksText"));
}
else
{
mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksText"));
}
}
else if (selected_id.isNull())
{
mTabContainer->selectFirstTab();
}
updateButtons();
processProperties(avatar_picks);
}
}
}
void LLPanelProfilePicks::processProperties(const LLAvatarPicks* avatar_picks)
{
LLUUID selected_id = mPickToSelectOnLoad;
if (mPickToSelectOnLoad.isNull())
{
if (mTabContainer->getTabCount() > 0)
{
LLPanelProfilePick* active_pick_panel = dynamic_cast<LLPanelProfilePick*>(mTabContainer->getCurrentPanel());
if (active_pick_panel)
{
selected_id = active_pick_panel->getPickId();
}
}
}
mTabContainer->deleteAllTabs();
LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin();
for (; avatar_picks->picks_list.end() != it; ++it)
{
LLUUID pick_id = it->first;
std::string pick_name = it->second;
LLPanelProfilePick* pick_panel = LLPanelProfilePick::create();
pick_panel->setPickId(pick_id);
pick_panel->setPickName(pick_name);
pick_panel->setAvatarId(getAvatarId());
mTabContainer->addTabPanel(
LLTabContainer::TabPanelParams().
panel(pick_panel).
select_tab(selected_id == pick_id).
label(pick_name));
if (selected_id == pick_id)
{
mPickToSelectOnLoad = LLUUID::null;
}
}
BOOL no_data = !mTabContainer->getTabCount();
mNoItemsLabel->setVisible(no_data);
if (no_data)
{
if (getSelfProfile())
{
mNoItemsLabel->setValue(LLTrans::getString("NoPicksText"));
}
else
{
mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksText"));
}
}
else if (selected_id.isNull())
{
mTabContainer->selectFirstTab();
}
updateButtons();
}
void LLPanelProfilePicks::resetData()
{
resetLoading();

View File

@ -59,6 +59,7 @@ public:
void selectPick(const LLUUID& pick_id);
/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
void processProperties(const LLAvatarPicks* avatar_picks);
/*virtual*/ void resetData();
@ -74,6 +75,8 @@ public:
*/
/*virtual*/ void updateData();
friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id);
private:
void onClickNewBtn();
void onClickDelete();

View File

@ -7776,7 +7776,7 @@ class LLAvatarTogglePicks : public view_listener_t
{
bool handleEvent(const LLSD& userdata)
{
LLFloater* instance = LLAvatarActions::getProfileFloater(gAgent.getID());
LLFloater * instance = LLAvatarActions::getProfileFloater(gAgent.getID());
if (LLFloater::isMinimized(instance) || (instance && !instance->hasFocus() && !instance->getIsChrome()))
{
instance->setMinimized(FALSE);

View File

@ -3156,6 +3156,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
capabilityNames.append("AcceptFriendship");
capabilityNames.append("AcceptGroupInvite"); // ReadOfflineMsgs recieved messages only!!!
capabilityNames.append("AgentPreferences");
capabilityNames.append("AgentProfile");
capabilityNames.append("AgentState");
capabilityNames.append("AttachmentResources");
capabilityNames.append("AvatarPickerSearch");

View File

@ -252,7 +252,7 @@
layout="topleft"
left="4"
top_pad="-14"
max_length="511"
max_length="65000"
name="sl_description_edit"
right="-4"
word_wrap="true" />
@ -432,7 +432,7 @@
layout="topleft"
left="4"
top_pad="-14"
max_length="511"
max_length="65000"
name="fl_description_edit"
right="-4"
word_wrap="true" />

View File

@ -44,7 +44,7 @@
layout="topleft"
bg_readonly_color="Transparent"
border_visible="true"
max_length="253"
max_length="65000"
parse_urls="true"
word_wrap="true"
/>

View File

@ -9,14 +9,6 @@
follows="all"
layout="topleft"
>
<!--these strings will be combined into one with different styles-->
<string name="header_symbol_limit">
Warning: Your notes contain more than 1000 characters.
</string>
<string name="body_symbol_limit">
Only first 1000 characters are shown here. If you edit your notes and click OK, the extra characters will be lost. To preserve the extra characters, you must edit it [[PROFILE_URL] on the web]
</string>
<loading_indicator
name="progress_indicator"
top="3"
@ -47,20 +39,9 @@ Only first 1000 characters are shown here. If you edit your notes and click OK,
height="311"
follows="all"
layout="topleft"
max_length="1000"
max_length="65530"
word_wrap="true"
/>
<text
layout="topleft"
follows="left|bottom|right"
top_pad="2"
left="6"
right="-6"
height ="28"
name="character_limit_warning"
word_wrap="true">
Placeholder: Your notes contain more than 1000 characters. Only first 1000 characters are shown here. If you edit your notes and click OK, the extra characters will be lost. To preserve the extra characters, you must edit it [https://my.secondlife.com/settings/profile on the web]
</text>
<text
name="status_message2"
value="Allow this avatar to:"

View File

@ -487,7 +487,7 @@
border_visible="false"
font="SansSerifSmall"
h_pad="3"
max_length="510"
max_length="65000"
parse_urls="true"
word_wrap="true"
/>