From 9f9a4cbaaf4e553acfaaf20696735af3488ba797 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 11 Feb 2012 04:07:34 -0600 Subject: [PATCH] Brought over LLAvatarPropertiesProcessor, and updated relevant floaters to utilize it. (Mainly in the avatar properties floaters) --- indra/newview/CMakeLists.txt | 2 + indra/newview/llavatarpropertiesprocessor.cpp | 692 +++++++++++++ indra/newview/llavatarpropertiesprocessor.h | 291 ++++++ indra/newview/llpanelavatar.cpp | 933 +++++++----------- indra/newview/llpanelavatar.h | 53 +- indra/newview/llpanelclassified.cpp | 282 ++---- indra/newview/llpanelclassified.h | 7 +- indra/newview/llpanelpick.cpp | 241 ++--- indra/newview/llpanelpick.h | 7 +- indra/newview/llstartup.cpp | 17 +- indra/newview/llvoavatar.cpp | 5 +- 11 files changed, 1613 insertions(+), 917 deletions(-) create mode 100644 indra/newview/llavatarpropertiesprocessor.cpp create mode 100644 indra/newview/llavatarpropertiesprocessor.h diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 2df854365..7ad78bc0f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -128,6 +128,7 @@ set(viewer_SOURCE_FILES llassetuploadqueue.cpp llattachmentsmgr.cpp llaudiosourcevo.cpp + llavatarpropertiesprocessor.cpp llbox.cpp llbuildnewviewsscheduler.cpp llcallbacklist.cpp @@ -612,6 +613,7 @@ set(viewer_HEADER_FILES llassetuploadqueue.h llattachmentsmgr.h llaudiosourcevo.h + llavatarpropertiesprocessor.h llbox.h llbuildnewviewsscheduler.h llcallbacklist.h diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp new file mode 100644 index 000000000..4d3ce23a4 --- /dev/null +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -0,0 +1,692 @@ +/** + * @file llavatarpropertiesprocessor.cpp + * @brief LLAvatarPropertiesProcessor class implementation + * + * $LicenseInfo:firstyear=2001&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 "llavatarpropertiesprocessor.h" + +// Viewer includes +#include "llagent.h" +#include "llviewergenericmessage.h" + +// Linden library includes +#include "llavatarconstants.h" // AVATAR_TRANSACTED, etc. +#include "lldate.h" +#include "lltrans.h" +#include "llui.h" // LLUI::getLanguage() +#include "message.h" + +LLAvatarPropertiesProcessor::LLAvatarPropertiesProcessor() +{ +} + +LLAvatarPropertiesProcessor::~LLAvatarPropertiesProcessor() +{ +} + +void LLAvatarPropertiesProcessor::addObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer) +{ + // Check if that observer is already in mObservers for that avatar_id + observer_multimap_t::iterator it; + + // IAN BUG this should update the observer's UUID if this is a dupe - sent to PE + it = mObservers.find(avatar_id); + while (it != mObservers.end()) + { + if (it->second == observer) + { + return; + } + else + { + ++it; + } + } + + mObservers.insert(std::pair(avatar_id, observer)); +} + +void LLAvatarPropertiesProcessor::removeObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer) +{ + if (!observer) + { + return; + } + + observer_multimap_t::iterator it; + it = mObservers.find(avatar_id); + while (it != mObservers.end()) + { + if (it->second == observer) + { + mObservers.erase(it); + break; + } + else + { + ++it; + } + } +} + + +void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string method) +{ + // 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 strings; + strings.push_back( avatar_id.asString() ); + send_generic_message(method, strings); +} + +void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id) +{ + 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(); +} + +void LLAvatarPropertiesProcessor::sendAvatarPicksRequest(const LLUUID& avatar_id) +{ + std::string name; + gCacheName->getFullName(avatar_id, name); + llinfos << "Sending avatarpicksrequest for " << avatar_id << " ("<newMessageFast (_PREHASH_AvatarPropertiesUpdate); + msg->nextBlockFast (_PREHASH_AgentData); + msg->addUUIDFast (_PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast (_PREHASH_SessionID, gAgent.getSessionID() ); + msg->nextBlockFast (_PREHASH_PropertiesData); + + msg->addUUIDFast (_PREHASH_ImageID, avatar_props->image_id); + msg->addUUIDFast (_PREHASH_FLImageID, avatar_props->fl_image_id); + msg->addStringFast (_PREHASH_AboutText, avatar_props->about_text); + msg->addStringFast (_PREHASH_FLAboutText, avatar_props->fl_about_text); + + msg->addBOOL(_PREHASH_AllowPublish, avatar_props->allow_publish); + msg->addBOOL(_PREHASH_MaturePublish, mature); + msg->addString(_PREHASH_ProfileURL, avatar_props->profile_url); + + gAgent.sendReliableMessage(); +} + +void LLAvatarPropertiesProcessor::sendAvatarInterestsUpdate(const LLAvatarInterestsInfo* interests_props) +{ + if (!gAgent.isInitialized() || (gAgent.getID() == LLUUID::null)) + { + llwarns << "Sending avatarinfo update DENIED - invalid agent" << llendl; + return; + } + + LLMessageSystem *msg = gMessageSystem; + msg->newMessage(_PREHASH_AvatarInterestsUpdate); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); + msg->nextBlockFast(_PREHASH_PropertiesData); + msg->addU32Fast( _PREHASH_WantToMask, interests_props->want_to_mask); + msg->addStringFast( _PREHASH_WantToText, interests_props->want_to_text); + msg->addU32Fast( _PREHASH_SkillsMask, interests_props->skills_mask); + msg->addStringFast( _PREHASH_SkillsText, interests_props->skills_text); + msg->addString( _PREHASH_LanguagesText, interests_props->languages_text); + gAgent.sendReliableMessage(); +} + +//static +std::string LLAvatarPropertiesProcessor::accountType(const LLAvatarData* avatar_data) +{ + // If you have a special account, like M Linden ("El Jefe!") + // return an untranslated "special" string + if (!avatar_data->caption_text.empty()) + { + return avatar_data->caption_text; + } + const char* const ACCT_TYPE[] = { + "AcctTypeResident", + "AcctTypeTrial", + "AcctTypeCharterMember", + "AcctTypeEmployee" + }; + U8 caption_max = (U8)LL_ARRAY_SIZE(ACCT_TYPE)-1; + U8 caption_index = llclamp(avatar_data->caption_index, (U8)0, caption_max); + return LLTrans::getString(ACCT_TYPE[caption_index]); +} + +//static +std::string LLAvatarPropertiesProcessor::paymentInfo(const LLAvatarData* avatar_data) +{ + // Special accounts like M Linden don't have payment info revealed. + if (!avatar_data->caption_text.empty()) return ""; + + // Linden employees don't have payment info revealed + const S32 LINDEN_EMPLOYEE_INDEX = 3; + if (avatar_data->caption_index == LINDEN_EMPLOYEE_INDEX) return ""; + + BOOL transacted = (avatar_data->flags & AVATAR_TRANSACTED); + BOOL identified = (avatar_data->flags & AVATAR_IDENTIFIED); + // Not currently getting set in dataserver/lldataavatar.cpp for privacy considerations + //BOOL age_verified = (avatar_data->flags & AVATAR_AGEVERIFIED); + + const char* payment_text; + if(transacted) + { + payment_text = "PaymentInfoUsed"; + } + else if (identified) + { + payment_text = "PaymentInfoOnFile"; + } + else + { + payment_text = "NoPaymentInfoOnFile"; + } + return LLTrans::getString(payment_text); +} + +void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* msg, void**) +{ + LLAvatarData avatar_data; + std::string birth_date; + + msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AgentID, avatar_data.agent_id); + msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AvatarID, avatar_data.avatar_id); + msg->getUUIDFast( _PREHASH_PropertiesData, _PREHASH_ImageID, avatar_data.image_id); + msg->getUUIDFast( _PREHASH_PropertiesData, _PREHASH_FLImageID, avatar_data.fl_image_id); + msg->getUUIDFast( _PREHASH_PropertiesData, _PREHASH_PartnerID, avatar_data.partner_id); + msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_AboutText, avatar_data.about_text); + msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_FLAboutText, avatar_data.fl_about_text); + msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_BornOn, birth_date); + msg->getString( _PREHASH_PropertiesData, _PREHASH_ProfileURL, avatar_data.profile_url); + msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_Flags, avatar_data.flags); + + + //LLDateUtil::dateFromPDTString(avatar_data.born_on, birth_date); + avatar_data.born_on = birth_date; + avatar_data.caption_index = 0; + + S32 charter_member_size = 0; + charter_member_size = msg->getSize(_PREHASH_PropertiesData, _PREHASH_CharterMember); + if(1 == charter_member_size) + { + msg->getBinaryData(_PREHASH_PropertiesData, _PREHASH_CharterMember, &avatar_data.caption_index, 1); + } + else if(1 < charter_member_size) + { + msg->getString(_PREHASH_PropertiesData, _PREHASH_CharterMember, avatar_data.caption_text); + } + LLAvatarPropertiesProcessor* self = getInstance(); + // Request processed, no longer pending + self->removePendingRequest(avatar_data.avatar_id, APT_PROPERTIES); + self->notifyObservers(avatar_data.avatar_id,&avatar_data,APT_PROPERTIES); +} + +void LLAvatarPropertiesProcessor::processAvatarInterestsReply(LLMessageSystem* msg, void**) +{ + LLAvatarInterestsInfo avatar_interests; + + msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AgentID, avatar_interests.agent_id); + msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AvatarID, avatar_interests.avatar_id ); + + msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_WantToMask, avatar_interests.want_to_mask ); + msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_WantToText, avatar_interests.want_to_text ); + msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_SkillsMask, avatar_interests.skills_mask ); + msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_SkillsText, avatar_interests.skills_text ); + msg->getString( _PREHASH_PropertiesData, _PREHASH_LanguagesText, avatar_interests.languages_text ); + + LLAvatarPropertiesProcessor* self = getInstance(); + //This message isn't requested.. it just comes as a consequence of AvatarPropertiesRequest. + //self->removePendingRequest(avatar_interests.avatar_id, APT_INTERESTS); + self->notifyObservers(avatar_interests.avatar_id,&avatar_interests,APT_INTERESTS); +} + +void LLAvatarPropertiesProcessor::processAvatarClassifiedsReply(LLMessageSystem* msg, void**) +{ + LLAvatarClassifieds classifieds; + + msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, classifieds.agent_id); + msg->getUUID(_PREHASH_AgentData, _PREHASH_TargetID, classifieds.target_id); + + S32 block_count = msg->getNumberOfBlocks(_PREHASH_Data); + + for(int n = 0; n < block_count; ++n) + { + LLAvatarClassifieds::classified_data data; + + msg->getUUID(_PREHASH_Data, _PREHASH_ClassifiedID, data.classified_id, n); + msg->getString(_PREHASH_Data, _PREHASH_Name, data.name, n); + + classifieds.classifieds_list.push_back(data); + } + + LLAvatarPropertiesProcessor* self = getInstance(); + // Request processed, no longer pending + self->removePendingRequest(classifieds.target_id, APT_CLASSIFIEDS); + self->notifyObservers(classifieds.target_id,&classifieds,APT_CLASSIFIEDS); + //LLPanelAvatarClassified => LLPanelAvatar +} + +void LLAvatarPropertiesProcessor::processClassifiedInfoReply(LLMessageSystem* msg, void**) +{ + LLAvatarClassifiedInfo c_info; + + msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, c_info.agent_id); + + msg->getUUID(_PREHASH_Data, _PREHASH_ClassifiedID, c_info.classified_id); + msg->getUUID(_PREHASH_Data, _PREHASH_CreatorID, c_info.creator_id); + msg->getU32(_PREHASH_Data, _PREHASH_CreationDate, c_info.creation_date); + msg->getU32(_PREHASH_Data, _PREHASH_ExpirationDate, c_info.expiration_date); + msg->getU32(_PREHASH_Data, _PREHASH_Category, c_info.category); + msg->getString(_PREHASH_Data, _PREHASH_Name, c_info.name); + msg->getString(_PREHASH_Data, _PREHASH_Desc, c_info.description); + msg->getUUID(_PREHASH_Data, _PREHASH_ParcelID, c_info.parcel_id); + msg->getU32(_PREHASH_Data, _PREHASH_ParentEstate, c_info.parent_estate); + msg->getUUID(_PREHASH_Data, _PREHASH_SnapshotID, c_info.snapshot_id); + msg->getString(_PREHASH_Data, _PREHASH_SimName, c_info.sim_name); + msg->getVector3d(_PREHASH_Data, _PREHASH_PosGlobal, c_info.pos_global); + msg->getString(_PREHASH_Data, _PREHASH_ParcelName, c_info.parcel_name); + msg->getU8(_PREHASH_Data, _PREHASH_ClassifiedFlags, c_info.flags); + msg->getS32(_PREHASH_Data, _PREHASH_PriceForListing, c_info.price_for_listing); + + LLAvatarPropertiesProcessor* self = getInstance(); + // Request processed, no longer pending + self->removePendingRequest(c_info.creator_id, APT_CLASSIFIED_INFO); + self->notifyObservers(c_info.creator_id, &c_info, APT_CLASSIFIED_INFO); +} + + +void LLAvatarPropertiesProcessor::processAvatarNotesReply(LLMessageSystem* msg, void**) +{ + LLAvatarNotes avatar_notes; + + msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_notes.agent_id); + msg->getUUID(_PREHASH_Data, _PREHASH_TargetID, avatar_notes.target_id); + msg->getString(_PREHASH_Data, _PREHASH_Notes, avatar_notes.notes); + + LLAvatarPropertiesProcessor* self = getInstance(); + // Request processed, no longer pending + self->removePendingRequest(avatar_notes.target_id, APT_NOTES); + self->notifyObservers(avatar_notes.target_id,&avatar_notes,APT_NOTES); + //LLPanelAvatar +} + +void LLAvatarPropertiesProcessor::processAvatarPicksReply(LLMessageSystem* msg, void**) +{ + LLAvatarPicks avatar_picks; + msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_picks.agent_id); + msg->getUUID(_PREHASH_AgentData, _PREHASH_TargetID, avatar_picks.target_id); + + std::string name; + gCacheName->getFullName(avatar_picks.target_id, name); + + llinfos << "Got reply for " << avatar_picks.target_id << ": (" << name << ")" << llendl; + S32 block_count = msg->getNumberOfBlocks(_PREHASH_Data); + for (int block = 0; block < block_count; ++block) + { + LLUUID pick_id; + std::string pick_name; + + msg->getUUID(_PREHASH_Data, _PREHASH_PickID, pick_id, block); + msg->getString(_PREHASH_Data, _PREHASH_PickName, pick_name, block); + + llinfos << "\t" << pick_id << ": " << pick_name << llendl; + avatar_picks.picks_list.push_back(std::make_pair(pick_id,pick_name)); + } + LLAvatarPropertiesProcessor* self = getInstance(); + // Request processed, no longer pending + self->removePendingRequest(avatar_picks.target_id, APT_PICKS); + self->notifyObservers(avatar_picks.target_id,&avatar_picks,APT_PICKS); + //LLPanelAvatar +} + +void LLAvatarPropertiesProcessor::processPickInfoReply(LLMessageSystem* msg, void**) +{ + LLPickData pick_data; + + // Extract the agent id and verify the message is for this + // client. + msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, pick_data.agent_id ); + msg->getUUID(_PREHASH_Data, _PREHASH_PickID, pick_data.pick_id); + msg->getUUID(_PREHASH_Data, _PREHASH_CreatorID, pick_data.creator_id); + + // ** top_pick should be deleted, not being used anymore - angela + msg->getBOOL(_PREHASH_Data, _PREHASH_TopPick, pick_data.top_pick); + msg->getUUID(_PREHASH_Data, _PREHASH_ParcelID, pick_data.parcel_id); + msg->getString(_PREHASH_Data, _PREHASH_Name, pick_data.name); + msg->getString(_PREHASH_Data, _PREHASH_Desc, pick_data.desc); + msg->getUUID(_PREHASH_Data, _PREHASH_SnapshotID, pick_data.snapshot_id); + + msg->getString(_PREHASH_Data, _PREHASH_User, pick_data.user_name); + msg->getString(_PREHASH_Data, _PREHASH_OriginalName, pick_data.original_name); + msg->getString(_PREHASH_Data, _PREHASH_SimName, pick_data.sim_name); + msg->getVector3d(_PREHASH_Data, _PREHASH_PosGlobal, pick_data.pos_global); + + msg->getS32(_PREHASH_Data, _PREHASH_SortOrder, pick_data.sort_order); + msg->getBOOL(_PREHASH_Data, _PREHASH_Enabled, pick_data.enabled); + + LLAvatarPropertiesProcessor* self = getInstance(); + // don't need to remove pending request as we don't track pick info + self->notifyObservers(pick_data.creator_id, &pick_data, APT_PICK_INFO); +} + +void LLAvatarPropertiesProcessor::processAvatarGroupsReply(LLMessageSystem* msg, void**) +{ + LLAvatarGroups avatar_groups; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, avatar_groups.agent_id ); + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_groups.avatar_id ); + + S32 group_count = msg->getNumberOfBlocksFast(_PREHASH_GroupData); + for(S32 i = 0; i < group_count; ++i) + { + LLAvatarGroups::LLGroupData group_data; + + msg->getU64( _PREHASH_GroupData, _PREHASH_GroupPowers, group_data.group_powers, i ); + msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupTitle, group_data.group_title, i ); + msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupID, group_data.group_id, i); + msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupName, group_data.group_name, i ); + msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupInsigniaID, group_data.group_insignia_id, i ); + + avatar_groups.group_list.push_back(group_data); + } + + LLAvatarPropertiesProcessor* self = getInstance(); + self->removePendingRequest(avatar_groups.avatar_id, APT_GROUPS); + self->notifyObservers(avatar_groups.avatar_id,&avatar_groups,APT_GROUPS); +} + +void LLAvatarPropertiesProcessor::notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type) +{ + // Copy the map (because observers may delete themselves when updated?) + LLAvatarPropertiesProcessor::observer_multimap_t observers = mObservers; + + observer_multimap_t::iterator oi = observers.begin(); + observer_multimap_t::iterator end = observers.end(); + for (; oi != end; ++oi) + { + // only notify observers for the same agent, or if the observer + // didn't know the agent ID and passed a NULL id. + const LLUUID &agent_id = oi->first; + if (agent_id == id || agent_id.isNull()) + { + oi->second->processProperties(data,type); + } + } +} + +void LLAvatarPropertiesProcessor::sendFriendRights(const LLUUID& avatar_id, S32 rights) +{ + if(!avatar_id.isNull()) + { + LLMessageSystem* msg = gMessageSystem; + + // setup message header + msg->newMessageFast(_PREHASH_GrantUserRights); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgent.getID()); + msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlockFast(_PREHASH_Rights); + msg->addUUID(_PREHASH_AgentRelated, avatar_id); + msg->addS32(_PREHASH_RelatedRights, rights); + + gAgent.sendReliableMessage(); + } +} + +void LLAvatarPropertiesProcessor::sendNotes(const LLUUID& avatar_id, const std::string notes) +{ + if(!avatar_id.isNull()) + { + LLMessageSystem* msg = gMessageSystem; + + // setup message header + msg->newMessageFast(_PREHASH_AvatarNotesUpdate); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgent.getID()); + msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlockFast(_PREHASH_Data); + msg->addUUID(_PREHASH_TargetID, avatar_id); + msg->addString(_PREHASH_Notes, notes); + + gAgent.sendReliableMessage(); + } +} + + +void LLAvatarPropertiesProcessor::sendPickDelete( const LLUUID& pick_id ) +{ + LLMessageSystem* msg = gMessageSystem; + msg->newMessage(_PREHASH_PickDelete); + msg->nextBlock(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgent.getID()); + msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlock(_PREHASH_Data); + msg->addUUID(_PREHASH_PickID, pick_id); + gAgent.sendReliableMessage(); + + //LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); + //LLAgentPicksInfo::getInstance()->decrementNumberOfPicks(); +} + +void LLAvatarPropertiesProcessor::sendClassifiedDelete(const LLUUID& classified_id) +{ + LLMessageSystem* msg = gMessageSystem; + + msg->newMessage(_PREHASH_ClassifiedDelete); + + msg->nextBlock(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgent.getID()); + msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlock(_PREHASH_Data); + msg->addUUID(_PREHASH_ClassifiedID, classified_id); + + gAgent.sendReliableMessage(); +} + +void LLAvatarPropertiesProcessor::sendPickInfoUpdate(const LLPickData* new_pick) +{ + if (!new_pick) return; + + LLMessageSystem* msg = gMessageSystem; + + msg->newMessage(_PREHASH_PickInfoUpdate); + msg->nextBlock(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgent.getID()); + msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlock(_PREHASH_Data); + msg->addUUID(_PREHASH_PickID, new_pick->pick_id); + msg->addUUID(_PREHASH_CreatorID, new_pick->creator_id); + + //legacy var need to be deleted + msg->addBOOL(_PREHASH_TopPick, FALSE); + + // fills in on simulator if null + msg->addUUID(_PREHASH_ParcelID, new_pick->parcel_id); + msg->addString(_PREHASH_Name, new_pick->name); + msg->addString(_PREHASH_Desc, new_pick->desc); + msg->addUUID(_PREHASH_SnapshotID, new_pick->snapshot_id); + msg->addVector3d(_PREHASH_PosGlobal, new_pick->pos_global); + + // Only top picks have a sort order + msg->addS32(_PREHASH_SortOrder, 0); + + msg->addBOOL(_PREHASH_Enabled, new_pick->enabled); + gAgent.sendReliableMessage(); + + //LLAgentPicksInfo::getInstance()->requestNumberOfPicks(); +} + +void LLAvatarPropertiesProcessor::sendClassifiedInfoUpdate(const LLAvatarClassifiedInfo* c_data) +{ + if(!c_data) + { + return; + } + + LLMessageSystem* msg = gMessageSystem; + + msg->newMessage(_PREHASH_ClassifiedInfoUpdate); + + msg->nextBlock(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgent.getID()); + msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlock(_PREHASH_Data); + msg->addUUID(_PREHASH_ClassifiedID, c_data->classified_id); + msg->addU32(_PREHASH_Category, c_data->category); + msg->addString(_PREHASH_Name, c_data->name); + msg->addString(_PREHASH_Desc, c_data->description); + msg->addUUID(_PREHASH_ParcelID, c_data->parcel_id); + msg->addU32(_PREHASH_ParentEstate, 0); + msg->addUUID(_PREHASH_SnapshotID, c_data->snapshot_id); + msg->addVector3d(_PREHASH_PosGlobal, c_data->pos_global); + msg->addU8(_PREHASH_ClassifiedFlags, c_data->flags); + msg->addS32(_PREHASH_PriceForListing, c_data->price_for_listing); + + gAgent.sendReliableMessage(); +} + +void LLAvatarPropertiesProcessor::sendPickInfoRequest(const LLUUID& creator_id, const LLUUID& pick_id) +{ + // Must ask for a pick based on the creator id because + // the pick database is distributed to the inventory cluster. JC + std::vector request_params; + request_params.push_back(creator_id.asString() ); + request_params.push_back(pick_id.asString() ); + send_generic_message("pickinforequest", request_params); +} + +void LLAvatarPropertiesProcessor::sendClassifiedInfoRequest(const LLUUID& classified_id) +{ + LLMessageSystem* msg = gMessageSystem; + + msg->newMessage(_PREHASH_ClassifiedInfoRequest); + msg->nextBlock(_PREHASH_AgentData); + + msg->addUUID(_PREHASH_AgentID, gAgent.getID()); + msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlock(_PREHASH_Data); + msg->addUUID(_PREHASH_ClassifiedID, classified_id); + + gAgent.sendReliableMessage(); +} + +bool LLAvatarPropertiesProcessor::isPendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type) +{ + timestamp_map_t::key_type key = std::make_pair(avatar_id, type); + timestamp_map_t::iterator it = mRequestTimestamps.find(key); + + // Is this a new request? + if (it == mRequestTimestamps.end()) return false; + + // We found a request, check if it has timed out + U32 now = time(NULL); + const U32 REQUEST_EXPIRE_SECS = 5; + U32 expires = it->second + REQUEST_EXPIRE_SECS; + + // Request is still pending if it hasn't expired yet + // *NOTE: Expired requests will accumulate in this map, but they are rare, + // the data is small, and they will be updated if the same data is + // re-requested + return (now < expires); +} + +void LLAvatarPropertiesProcessor::addPendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type) +{ + timestamp_map_t::key_type key = std::make_pair(avatar_id, type); + U32 now = time(NULL); + // Add or update existing (expired) request + mRequestTimestamps[ key ] = now; +} + +void LLAvatarPropertiesProcessor::removePendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type) +{ + timestamp_map_t::key_type key = std::make_pair(avatar_id, type); + mRequestTimestamps.erase(key); +} diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h new file mode 100644 index 000000000..162fd05c4 --- /dev/null +++ b/indra/newview/llavatarpropertiesprocessor.h @@ -0,0 +1,291 @@ +/** + * @file llavatarpropertiesprocessor.h + * @brief LLAvatatIconCtrl base class + * + * $LicenseInfo:firstyear=2001&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$ + */ + +#ifndef LL_LLAVATARPROPERTIESPROCESSOR_H +#define LL_LLAVATARPROPERTIESPROCESSOR_H + +#include "lluuid.h" +#include "llsingleton.h" +#include "v3dmath.h" // LLVector3d +#include +#include + +/* +*TODO Vadim: This needs some refactoring: +- Remove EAvatarProcessorType in favor of separate observers, derived from a common parent (to get rid of void*). +*/ + +class LLMessageSystem; + +enum EAvatarProcessorType +{ + APT_PROPERTIES, + APT_NOTES, + APT_GROUPS, + APT_PICKS, + APT_PICK_INFO, + APT_TEXTURES, + APT_CLASSIFIEDS, + APT_CLASSIFIED_INFO, + APT_INTERESTS +}; + +struct LLAvatarData +{ + LLUUID agent_id; + LLUUID avatar_id; //target id + LLUUID image_id; + LLUUID fl_image_id; + LLUUID partner_id; + std::string about_text; + std::string fl_about_text; + std::string born_on; + std::string profile_url; + U8 caption_index; + std::string caption_text; + U32 flags; + BOOL allow_publish; +}; + +struct LLAvatarPicks +{ + LLUUID agent_id; + LLUUID target_id; //target id + + typedef std::pair pick_data_t; + typedef std::list< pick_data_t> picks_list_t; + picks_list_t picks_list; +}; + +struct LLPickData +{ + LLUUID agent_id; + LLUUID pick_id; + LLUUID creator_id; + BOOL top_pick; + LLUUID parcel_id; + std::string name; + std::string desc; + LLUUID snapshot_id; + LLVector3d pos_global; + S32 sort_order; + BOOL enabled; + + //used only in read requests + std::string user_name; + std::string original_name; + std::string sim_name; + + //used only in write (update) requests + LLUUID session_id; + +}; + +struct LLAvatarNotes +{ + LLUUID agent_id; + LLUUID target_id; //target id + std::string notes; +}; + +struct LLAvatarGroups +{ + LLUUID agent_id; + LLUUID avatar_id; //target id + BOOL list_in_profile; + + struct LLGroupData; + typedef std::list group_list_t; + + group_list_t group_list; + + struct LLGroupData + { + U64 group_powers; + BOOL accept_notices; + std::string group_title; + LLUUID group_id; + std::string group_name; + LLUUID group_insignia_id; + }; +}; + +struct LLAvatarClassifieds +{ + LLUUID agent_id; + LLUUID target_id; + + struct classified_data; + typedef std::list classifieds_list_t; + + classifieds_list_t classifieds_list; + + struct classified_data + { + LLUUID classified_id; + std::string name; + }; +}; + +struct LLAvatarClassifiedInfo +{ + LLUUID agent_id; + LLUUID classified_id; + LLUUID creator_id; + U32 creation_date; + U32 expiration_date; + U32 category; + std::string name; + std::string description; + LLUUID parcel_id; + U32 parent_estate; + LLUUID snapshot_id; + std::string sim_name; + LLVector3d pos_global; + std::string parcel_name; + U8 flags; + S32 price_for_listing; +}; + +struct LLAvatarInterestsInfo +{ + LLUUID agent_id; + LLUUID avatar_id; //target id + U32 want_to_mask; + std::string want_to_text; + U32 skills_mask; + std::string skills_text; + std::string languages_text; +}; + +class LLAvatarPropertiesObserver +{ +public: + virtual ~LLAvatarPropertiesObserver() {} + virtual void processProperties(void* data, EAvatarProcessorType type) = 0; +}; + +class LLAvatarPropertiesProcessor + : public LLSingleton +{ +public: + + LLAvatarPropertiesProcessor(); + virtual ~LLAvatarPropertiesProcessor(); + + void addObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer); + + void removeObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer); + + // Request various types of avatar data. Duplicate requests will be + // suppressed while waiting for a response from the network. + void sendAvatarPropertiesRequest(const LLUUID& avatar_id); + void sendAvatarPicksRequest(const LLUUID& avatar_id); + void sendAvatarNotesRequest(const LLUUID& avatar_id); + void sendAvatarGroupsRequest(const LLUUID& avatar_id); + void sendAvatarTexturesRequest(const LLUUID& avatar_id); + void sendAvatarClassifiedsRequest(const LLUUID& avatar_id); + + // Duplicate pick info requests are not suppressed. + void sendPickInfoRequest(const LLUUID& creator_id, const LLUUID& pick_id); + + void sendClassifiedInfoRequest(const LLUUID& classified_id); + + void sendAvatarPropertiesUpdate(const LLAvatarData* avatar_props); + void sendAvatarInterestsUpdate(const LLAvatarInterestsInfo* interests_props); + + void sendPickInfoUpdate(const LLPickData* new_pick); + + void sendClassifiedInfoUpdate(const LLAvatarClassifiedInfo* c_data); + + void sendFriendRights(const LLUUID& avatar_id, S32 rights); + + void sendNotes(const LLUUID& avatar_id, const std::string notes); + + void sendPickDelete(const LLUUID& pick_id); + + void sendClassifiedDelete(const LLUUID& classified_id); + + // Returns translated, human readable string for account type, such + // as "Resident" or "Linden Employee". Used for profiles, inspectors. + static std::string accountType(const LLAvatarData* avatar_data); + + // Returns translated, human readable string for payment info, such + // as "Payment Info on File" or "Payment Info Used". + // Used for profiles, inspectors. + static std::string paymentInfo(const LLAvatarData* avatar_data); + + static void processAvatarPropertiesReply(LLMessageSystem* msg, void**); + + static void processAvatarInterestsReply(LLMessageSystem* msg, void**); + + static void processAvatarClassifiedsReply(LLMessageSystem* msg, void**); + + static void processClassifiedInfoReply(LLMessageSystem* msg, void**); + + static void processAvatarGroupsReply(LLMessageSystem* msg, void**); + + static void processAvatarNotesReply(LLMessageSystem* msg, void**); + + static void processAvatarPicksReply(LLMessageSystem* msg, void**); + + static void processPickInfoReply(LLMessageSystem* msg, void**); + +protected: + + void sendGenericRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const std::string method); + + void notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type); + + // Is there a pending, not timed out, request for this avatar's data? + // Use this to suppress duplicate requests for data when a request is + // pending. + bool isPendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type); + + // Call this when a request has been sent + void addPendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type); + + // Call this when the reply to the request is received + void removePendingRequest(const LLUUID& avatar_id, EAvatarProcessorType type); + + typedef void* (*processor_method_t)(LLMessageSystem*); + static processor_method_t getProcessor(EAvatarProcessorType type); + +protected: + + typedef std::multimap observer_multimap_t; + + observer_multimap_t mObservers; + + // Keep track of pending requests for data by avatar id and type. + // Maintain a timestamp for each request so a request that receives no reply + // does not block future requests forever. + // Map avatar_id+request_type -> U32 timestamp in seconds + typedef std::map< std::pair, U32> timestamp_map_t; + timestamp_map_t mRequestTimestamps; +}; + +#endif // LL_LLAVATARPROPERTIESPROCESSOR_H diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 590d6da0a..dd3e21c85 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -176,7 +176,29 @@ LLPanelAvatarTab::LLPanelAvatarTab(const std::string& name, const LLRect &rect, : 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); + } + +} +// virtual +LLPanelAvatarTab::~LLPanelAvatarTab() +{ + if(mAvatarID.notNull()) + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarID, this); +} // virtual void LLPanelAvatarTab::draw() @@ -186,17 +208,6 @@ void LLPanelAvatarTab::draw() LLPanel::draw(); } -void LLPanelAvatarTab::sendAvatarProfileRequestIfNeeded(const std::string& method) -{ - if (!mDataRequested) - { - std::vector strings; - strings.push_back( mPanelAvatar->getAvatarID().asString() ); - send_generic_message(method, strings); - mDataRequested = true; - } -} - //----------------------------------------------------------------------------- // LLPanelAvatarSecondLife() //----------------------------------------------------------------------------- @@ -271,6 +282,161 @@ void LLPanelAvatarSecondLife::clearControls() } +// virtual +void LLPanelAvatarSecondLife::processProperties(void* data, EAvatarProcessorType type) +{ + if(type == APT_PROPERTIES) + { + const LLAvatarData* pAvatarData = static_cast( data ); + if (pAvatarData && (mAvatarID == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null)) + { + LLStringUtil::format_map_t args; + + U8 caption_index = 0; + std::string caption_text = getString("CaptionTextAcctInfo"); + + const char* ACCT_TYPE[] = + { + "AcctTypeResident", + "AcctTypeTrial", + "AcctTypeCharterMember", + "AcctTypeEmployee" + }; + + + caption_index = llclamp(caption_index, (U8)0, (U8)(LL_ARRAY_SIZE(ACCT_TYPE)-1)); + args["[ACCTTYPE]"] = getString(ACCT_TYPE[caption_index]); + + std::string payment_text = " "; + const S32 DEFAULT_CAPTION_LINDEN_INDEX = 3; + if(caption_index != DEFAULT_CAPTION_LINDEN_INDEX) + { + if(pAvatarData->flags & AVATAR_TRANSACTED) + { + payment_text = "PaymentInfoUsed"; + } + else if (pAvatarData->flags & AVATAR_IDENTIFIED) + { + payment_text = "PaymentInfoOnFile"; + } + else + { + payment_text = "NoPaymentInfoOnFile"; + } + args["[PAYMENTINFO]"] = getString(payment_text); + + // Do not display age verification status at this time - Mostly because it /doesn't work/. -HgB + /*bool age_verified = (pAvatarData->flags & AVATAR_AGEVERIFIED); // Not currently getting set in dataserver/lldataavatar.cpp for privacy consideration + std::string age_text = age_verified ? "AgeVerified" : "NotAgeVerified"; + + args["[AGEVERIFICATION]"] = getString(age_text); + */ + args["[AGEVERIFICATION]"] = " "; + } + else + { + args["[PAYMENTINFO]"] = " "; + args["[AGEVERIFICATION]"] = " "; + } + LLStringUtil::format(caption_text, args); + + childSetValue("acct", caption_text); + + getChild("img")->setImageAssetID(pAvatarData->image_id); + + //Chalice - Show avatar age in days. + int year, month, day; + sscanf(pAvatarData->born_on.c_str(),"%d/%d/%d",&month,&day,&year); + time_t now = time(NULL); + struct tm * timeinfo; + timeinfo=localtime(&now); + timeinfo->tm_mon = --month; + timeinfo->tm_year = year - 1900; + timeinfo->tm_mday = day; + time_t birth = mktime(timeinfo); + std::stringstream NumberString; + NumberString << (difftime(now,birth) / (60*60*24)); + std::string born_on = pAvatarData->born_on; + born_on += " ("; + born_on += NumberString.str(); + born_on += ")"; + childSetValue("born", born_on); + + bool allow_publish = (pAvatarData->flags & AVATAR_ALLOW_PUBLISH); + childSetValue("allow_publish", allow_publish); + + setPartnerID(pAvatarData->partner_id); + updatePartnerName(); + } + } + else if(type == APT_GROUPS) + { + const LLAvatarGroups* pAvatarGroups = static_cast( data ); + if(pAvatarGroups && pAvatarGroups->avatar_id == mAvatarID && pAvatarGroups->avatar_id.notNull()) + { + LLScrollListCtrl* group_list = getChild("groups"); +// if(group_list) +// { +// group_list->deleteAllItems(); +// } + if (0 == pAvatarGroups->group_list.size()) + { + group_list->addCommentText(std::string("None")); // *TODO: Translate + } + + 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 + if (group_list) + { + S32 index = group_list->getItemIndex(it->group_id); + if ( index >= 0 ) + { + group_list->deleteSingleItem(index); + } + } + + LLSD row; + row["id"] = it->group_id; + row["columns"][0]["value"] = it->group_id.notNull() ? it->group_name : ""; + row["columns"][0]["font"] = "SANSSERIF_SMALL"; + LLGroupData *group_data = NULL; + + if (pAvatarGroups->avatar_id == pAvatarGroups->agent_id) // own avatar + { + // Search for this group in the agent's groups list + LLDynamicArray::iterator i; + + for (i = gAgent.mGroups.begin(); i != gAgent.mGroups.end(); i++) + { + if (i->mID == it->group_id) + { + group_data = &*i; + break; + } + } + // Set normal color if not found or if group is visible in profile + if (group_data) + { + std::string font_style = group_data->mListInProfile ? "BOLD" : "NORMAL"; + if(group_data->mID == gAgent.getGroupID()) + font_style.append("|ITALIC"); + row["columns"][0]["font-style"] = font_style; + } + else + row["columns"][0]["font-style"] = "NORMAL"; + } + + if (group_list) + { + group_list->addElement(row,ADD_SORTED); + } + } + } + } +} //----------------------------------------------------------------------------- // enableControls() @@ -312,8 +478,21 @@ void LLPanelAvatarFirstLife::onClickImage(void* data) } } +} - +// virtual +void LLPanelAvatarFirstLife::processProperties(void* data, EAvatarProcessorType type) +{ + if(type == APT_PROPERTIES) + { + const LLAvatarData* pAvatarData = static_cast( data ); + if (pAvatarData && (mAvatarID == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null)) + { + // Teens don't get these + childSetValue("about", pAvatarData->fl_about_text); + getChild("img")->setImageAssetID(pAvatarData->fl_image_id); + } + } } // static @@ -519,8 +698,18 @@ BOOL LLPanelAvatarWeb::postBuild(void) return TRUE; } - - +// virtual +void LLPanelAvatarWeb::processProperties(void* data, EAvatarProcessorType type) +{ + if(type == APT_PROPERTIES) + { + const LLAvatarData* pAvatarData = static_cast( data ); + if (pAvatarData && (mAvatarID == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null)) + { + setWebURL(pAvatarData->profile_url); + } + } +} BOOL LLPanelAvatarClassified::postBuild(void) { @@ -569,6 +758,19 @@ BOOL LLPanelAvatarAdvanced::postBuild() return TRUE; } +// virtual +void LLPanelAvatarAdvanced::processProperties(void* data, EAvatarProcessorType type) +{ + if(type == APT_INTERESTS) + { + const LLAvatarInterestsInfo* i_info = static_cast(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 //----------------------------------------------------------------------------- @@ -824,7 +1026,11 @@ LLPanelAvatarNotes::LLPanelAvatarNotes(const std::string& name, const LLRect& re void LLPanelAvatarNotes::refresh() { - sendAvatarProfileRequestIfNeeded("avatarnotesrequest"); + if (!isDataRequested()) + { + LLAvatarPropertiesProcessor::getInstance()->sendAvatarNotesRequest(mAvatarID); + setDataRequested(true); + } } void LLPanelAvatarNotes::clearControls() @@ -887,7 +1093,11 @@ void LLPanelAvatarClassified::refresh() childSetVisible("Delete...", !in_directory); childSetVisible("classified tab",!show_help); - sendAvatarProfileRequestIfNeeded("avatarclassifiedsrequest"); + if (!isDataRequested()) + { + LLAvatarPropertiesProcessor::getInstance()->sendAvatarClassifiedsRequest(mAvatarID); + setDataRequested(true); + } } @@ -947,53 +1157,47 @@ void LLPanelAvatarClassified::deleteClassifiedPanels() childSetVisible("loading_text", true); } - -void LLPanelAvatarClassified::processAvatarClassifiedReply(LLMessageSystem* msg, void**) +// virtual +void LLPanelAvatarClassified::processProperties(void* data, EAvatarProcessorType type) { - S32 block = 0; - S32 block_count = 0; - LLUUID classified_id; - std::string classified_name; - LLPanelClassified* panel_classified = NULL; - - LLTabContainer* tabs = getChild("classified tab"); - - // Don't remove old panels. We need to be able to process multiple - // packets for people who have lots of classifieds. JC - - block_count = msg->getNumberOfBlocksFast(_PREHASH_Data); - for (block = 0; block < block_count; block++) + if(type == APT_CLASSIFIEDS) { - msg->getUUIDFast(_PREHASH_Data, _PREHASH_ClassifiedID, classified_id, block); - msg->getStringFast(_PREHASH_Data, _PREHASH_Name, classified_name, block); - - panel_classified = new LLPanelClassified(false, false); - - panel_classified->setClassifiedID(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 - if(tabs) + LLAvatarClassifieds* c_info = static_cast(data); + if(c_info && mAvatarID == c_info->target_id) { - tabs->addTabPanel(panel_classified, classified_name); + LLTabContainer* tabs = getChild("classified tab"); + + for(LLAvatarClassifieds::classifieds_list_t::iterator it = c_info->classifieds_list.begin(); + it != c_info->classifieds_list.end(); ++it) + { + LLPanelClassified* panel_classified = new LLPanelClassified(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 + if(tabs) + { + tabs->addTabPanel(panel_classified, it->name); + } + } + + // Make sure somebody is highlighted. This works even if there + // are no tabs in the container. + if(tabs) + { + tabs->selectFirstTab(); + } + + childSetVisible("New...", true); + childSetVisible("Delete...", true); + childSetVisible("loading_text", false); } } - - // Make sure somebody is highlighted. This works even if there - // are no tabs in the container. - if(tabs) - { - tabs->selectFirstTab(); - } - - childSetVisible("New...", true); - childSetVisible("Delete...", true); - childSetVisible("loading_text", false); } - // Create a new classified panel. It will automatically handle generating // its own id when it's time to save. // static @@ -1058,20 +1262,12 @@ bool LLPanelAvatarClassified::callbackDelete(const LLSD& notification, const LL { panel_classified = (LLPanelClassified*)tabs->getCurrentPanel(); } - - LLMessageSystem* msg = gMessageSystem; if (!panel_classified) return false; if (0 == option) { - msg->newMessageFast(_PREHASH_ClassifiedDelete); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Data); - msg->addUUIDFast(_PREHASH_ClassifiedID, panel_classified->getClassifiedID()); - gAgent.sendReliableMessage(); + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedDelete(panel_classified->getClassifiedID()); if(tabs) { @@ -1113,7 +1309,11 @@ void LLPanelAvatarPicks::refresh() childSetEnabled("Export...", self && tab_count > 0); childSetVisible("Export...", self && getPanelAvatar()->isEditable()); - sendAvatarProfileRequestIfNeeded("avatarpicksrequest"); + if (!isDataRequested()) + { + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(mAvatarID); + setDataRequested(true); + } } @@ -1135,61 +1335,60 @@ void LLPanelAvatarPicks::deletePickPanels() } -void LLPanelAvatarPicks::processAvatarPicksReply(LLMessageSystem* msg, void**) +// virtual +void LLPanelAvatarPicks::processProperties(void* data, EAvatarProcessorType type) { - S32 block = 0; - S32 block_count = 0; - LLUUID pick_id; - std::string pick_name; - LLPanelPick* panel_pick = NULL; - - LLTabContainer* tabs = getChild("picks tab"); - - // Clear out all the old panels. We'll replace them with the correct - // number of new panels. - deletePickPanels(); - - // The database needs to know for which user to look up picks. - LLUUID avatar_id = getPanelAvatar()->getAvatarID(); - - block_count = msg->getNumberOfBlocks("Data"); - for (block = 0; block < block_count; block++) + if(type == APT_PICKS) { - msg->getUUID("Data", "PickID", pick_id, block); - msg->getString("Data", "PickName", pick_name, block); + LLAvatarPicks* picks = static_cast(data); - panel_pick = new LLPanelPick(FALSE); + //llassert_always(picks->target_id != gAgent.getID()); + //llassert_always(mAvatarID != gAgent.getID()); - panel_pick->setPickID(pick_id, avatar_id); - - // 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 - if(tabs) + if(picks && mAvatarID == picks->target_id) { - tabs->addTabPanel(panel_pick, pick_name); + LLTabContainer* tabs = getChild("picks tab"); + + // Clear out all the old panels. We'll replace them with the correct + // number of new panels. + deletePickPanels(); + + for(LLAvatarPicks::picks_list_t::iterator it = picks->picks_list.begin(); + it != picks->picks_list.end(); ++it) + { + LLPanelPick* panel_pick = new LLPanelPick(FALSE); + 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 + if(tabs) + { + llinfos << "Adding tab for " << mAvatarID << " " << ((mAvatarID == gAgent.getID()) ? "Self" : "Other") << ": '" << it->second << "'" << llendl; + tabs->addTabPanel(panel_pick, it->second); + } + } + + // Make sure somebody is highlighted. This works even if there + // are no tabs in the container. + if(tabs) + { + tabs->selectFirstTab(); + } + + childSetVisible("New...", true); + childSetVisible("Delete...", true); + childSetVisible("loading_text", false); + + //For pick import and export - RK + childSetVisible("Import...", true); + childSetVisible("Export...", true); } } - - // Make sure somebody is highlighted. This works even if there - // are no tabs in the container. - if(tabs) - { - tabs->selectFirstTab(); - } - - childSetVisible("New...", true); - childSetVisible("Delete...", true); - childSetVisible("loading_text", false); - - //For pick import and export - RK - childSetVisible("Import...", true); - childSetVisible("Export...", true); } - // Create a new pick panel. It will automatically handle generating // its own id when it's time to save. // static @@ -1289,17 +1488,13 @@ bool LLPanelAvatarPicks::callbackDelete(const LLSD& notification, const LLSD& re // *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 { - msg->newMessage("PickDelete"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("PickID", panel_pick->getPickID()); + LLAvatarPropertiesProcessor::getInstance()->sendPickDelete(panel_pick->getPickID()); } - gAgent.sendReliableMessage(); + if(tabs) { @@ -1397,6 +1592,7 @@ BOOL LLPanelAvatar::postBuild(void) LLPanelAvatar::~LLPanelAvatar() { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarID,this); sAllPanels.remove(this); } @@ -1492,9 +1688,15 @@ void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id, const std::string &name 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 = is_agent_friend(mAvatarID); @@ -1504,6 +1706,11 @@ void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id, const std::string &name BOOL own_avatar = (mAvatarID == gAgent.getID() ); BOOL avatar_is_friend = LLAvatarTracker::instance().getBuddyInfo(mAvatarID) != NULL; + for(std::list::iterator it=mAvatarPanelList.begin();it!=mAvatarPanelList.end();++it) + { + (*it)->setAvatarID(avatar_id); + } + mPanelSecondLife->enableControls(own_avatar && mAllowEdit); mPanelWeb->enableControls(own_avatar && mAllowEdit); mPanelAdvanced->enableControls(own_avatar && mAllowEdit); @@ -1923,14 +2130,8 @@ void LLPanelAvatar::onClickCancel(void *userdata) void LLPanelAvatar::sendAvatarPropertiesRequest() { lldebugs << "LLPanelAvatar::sendAvatarPropertiesRequest()" << llendl; - 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, mAvatarID); - gAgent.sendReliableMessage(); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(mAvatarID); } void LLPanelAvatar::sendAvatarNotesUpdate() @@ -1949,334 +2150,55 @@ void LLPanelAvatar::sendAvatarNotesUpdate() return; } - LLMessageSystem *msg = gMessageSystem; - - msg->newMessage("AvatarNotesUpdate"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("TargetID", mAvatarID); - msg->addString("Notes", notes); - - gAgent.sendReliableMessage(); + LLAvatarPropertiesProcessor::getInstance()->sendNotes(mAvatarID,notes); } - -// static -void LLPanelAvatar::processAvatarPropertiesReply(LLMessageSystem *msg, void**) +// virtual +void LLPanelAvatar::processProperties(void* data, EAvatarProcessorType type) { - LLUUID agent_id; // your id - LLUUID avatar_id; // target of this panel - LLUUID image_id; - LLUUID fl_image_id; - LLUUID partner_id; - std::string about_text; - std::string fl_about_text; - std::string born_on; - S32 charter_member_size = 0; - BOOL allow_publish = FALSE; - //BOOL mature = FALSE; - BOOL identified = FALSE; - BOOL transacted = FALSE; - BOOL age_verified = FALSE; - BOOL online = FALSE; - std::string profile_url; - - U32 flags = 0x0; - - //llinfos << "properties packet size " << msg->getReceiveSize() << llendl; - - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_id ); - - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) + if(type == APT_PROPERTIES) { - LLPanelAvatar* self = *iter; - if (self->mAvatarID != avatar_id) + const LLAvatarData* pAvatarData = static_cast( data ); + if (pAvatarData && (mAvatarID == pAvatarData->avatar_id) && (pAvatarData->avatar_id != LLUUID::null)) { - continue; - } - self->childSetEnabled("Instant Message...",TRUE); - self->childSetEnabled("GroupInvite_Button",TRUE); - self->childSetEnabled("Pay...",TRUE); - self->childSetEnabled("Mute",TRUE); + childSetEnabled("Instant Message...",TRUE); + childSetEnabled("GroupInvite_Button",TRUE); + childSetEnabled("Pay...",TRUE); + childSetEnabled("Mute",TRUE); - self->childSetEnabled("drop target",TRUE); + childSetEnabled("drop target",TRUE); - self->mHaveProperties = TRUE; - self->enableOKIfReady(); + mHaveProperties = TRUE; + enableOKIfReady(); - msg->getUUIDFast( _PREHASH_PropertiesData, _PREHASH_ImageID, image_id ); - msg->getUUIDFast( _PREHASH_PropertiesData, _PREHASH_FLImageID, fl_image_id ); - msg->getUUIDFast(_PREHASH_PropertiesData, _PREHASH_PartnerID, partner_id); - msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_AboutText, about_text ); - msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_FLAboutText, fl_about_text ); - msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_BornOn, born_on); - msg->getString("PropertiesData","ProfileURL", profile_url); - msg->getU32Fast(_PREHASH_PropertiesData, _PREHASH_Flags, flags); - - /*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); - }*/ - - identified = (flags & AVATAR_IDENTIFIED); - transacted = (flags & AVATAR_TRANSACTED); - age_verified = (flags & AVATAR_AGEVERIFIED); // Not currently getting set in dataserver/lldataavatar.cpp for privacy considerations - allow_publish = (flags & AVATAR_ALLOW_PUBLISH); - online = (flags & AVATAR_ONLINE); - - U8 caption_index = 0; - std::string caption_text; - charter_member_size = msg->getSize("PropertiesData", "CharterMember"); - if(1 == charter_member_size) - { - msg->getBinaryData("PropertiesData", "CharterMember", &caption_index, 1); - } - else if(1 < charter_member_size) - { - msg->getString("PropertiesData", "CharterMember", caption_text); - } - - - if(caption_text.empty()) - { - LLStringUtil::format_map_t args; - caption_text = self->mPanelSecondLife->getString("CaptionTextAcctInfo"); + /*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); + }*/ - const char* ACCT_TYPE[] = { - "AcctTypeResident", - "AcctTypeTrial", - "AcctTypeCharterMember", - "AcctTypeEmployee" - }; - caption_index = llclamp(caption_index, (U8)0, (U8)(LL_ARRAY_SIZE(ACCT_TYPE)-1)); - args["[ACCTTYPE]"] = self->mPanelSecondLife->getString(ACCT_TYPE[caption_index]); - - std::string payment_text = " "; - const S32 DEFAULT_CAPTION_LINDEN_INDEX = 3; - if(caption_index != DEFAULT_CAPTION_LINDEN_INDEX) - { - if(transacted) - { - payment_text = "PaymentInfoUsed"; - } - else if (identified) - { - payment_text = "PaymentInfoOnFile"; - } - else - { - payment_text = "NoPaymentInfoOnFile"; - } - args["[PAYMENTINFO]"] = self->mPanelSecondLife->getString(payment_text); - std::string age_text = age_verified ? "AgeVerified" : "NotAgeVerified"; - // Do not display age verification status at this time - Mostly because it /doesn't work/. -HgB - //args["[AGEVERIFICATION]"] = self->mPanelSecondLife->getString(age_text); - args["[AGEVERIFICATION]"] = " "; - } - else - { - args["[PAYMENTINFO]"] = " "; - args["[AGEVERIFICATION]"] = " "; - } - LLStringUtil::format(caption_text, args); - } - - self->mPanelSecondLife->childSetValue("acct", caption_text); - //Chalice - Show avatar age in days. - int year, month, day; - sscanf(born_on.c_str(),"%d/%d/%d",&month,&day,&year); - time_t now = time(NULL); - struct tm * timeinfo; - timeinfo=localtime(&now); - timeinfo->tm_mon = --month; - timeinfo->tm_year = year - 1900; - timeinfo->tm_mday = day; - time_t birth = mktime(timeinfo); - std::stringstream NumberString; - NumberString << (difftime(now,birth) / (60*60*24)); - born_on += " ("; - born_on += NumberString.str(); - born_on += ")"; - self->mPanelSecondLife->childSetValue("born", born_on); - - EOnlineStatus online_status = (online) ? ONLINE_STATUS_YES : ONLINE_STATUS_NO; - - self->setOnlineStatus(online_status); - - self->mPanelWeb->setWebURL(profile_url); - - LLTextureCtrl* image_ctrl = self->mPanelSecondLife->getChild("img"); - if(image_ctrl) - { - image_ctrl->setImageAssetID(image_id); - } - self->childSetValue("about", about_text); - - self->mPanelSecondLife->setPartnerID(partner_id); - self->mPanelSecondLife->updatePartnerName(); - - if (self->mPanelFirstLife) - { - // Teens don't get these - self->mPanelFirstLife->childSetValue("about", fl_about_text); - LLTextureCtrl* image_ctrl = self->mPanelFirstLife->getChild("img"); - if(image_ctrl) - { - image_ctrl->setImageAssetID(fl_image_id); - } - - self->mPanelSecondLife->childSetValue("allow_publish", allow_publish); - + + bool online = (pAvatarData->flags & AVATAR_ONLINE); + + EOnlineStatus online_status = (online) ? ONLINE_STATUS_YES : ONLINE_STATUS_NO; + + setOnlineStatus(online_status); + + childSetValue("about", pAvatarData->about_text); } } -} - -// static -void LLPanelAvatar::processAvatarInterestsReply(LLMessageSystem *msg, void**) -{ - LLUUID agent_id; // your id - LLUUID avatar_id; // target of this panel - - U32 want_to_mask; - std::string want_to_text; - U32 skills_mask; - std::string skills_text; - std::string languages_text; - - //llinfos << "properties packet size " << msg->getReceiveSize() << llendl; - - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_id ); - - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) + else if(type == APT_NOTES) { - LLPanelAvatar* self = *iter; - if (self->mAvatarID != avatar_id) + const LLAvatarNotes* pAvatarNotes = static_cast( data ); + if (pAvatarNotes && (mAvatarID == pAvatarNotes->target_id) && (pAvatarNotes->target_id != LLUUID::null)) { - continue; - } - - msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_WantToMask, want_to_mask ); - msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_WantToText, want_to_text ); - msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_SkillsMask, skills_mask ); - msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_SkillsText, skills_text ); - msg->getString(_PREHASH_PropertiesData, "LanguagesText", languages_text ); - - self->mPanelAdvanced->setWantSkills(want_to_mask, want_to_text, skills_mask, skills_text, languages_text); - } -} - -// Separate function because the groups list can be very long, almost -// filling a packet. JC -// static -void LLPanelAvatar::processAvatarGroupsReply(LLMessageSystem *msg, void**) -{ - LLUUID agent_id; // your id - LLUUID avatar_id; // target of this panel - U64 group_powers; - std::string group_title; - LLUUID group_id; - std::string group_name; - LLUUID group_insignia_id; - - llinfos << "groups packet size " << msg->getReceiveSize() << llendl; - - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_id ); - - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelAvatar* self = *iter; - if (self->mAvatarID != avatar_id) - { - continue; - } - - LLScrollListCtrl* group_list = self->mPanelSecondLife->getChild("groups"); -// if(group_list) -// { -// group_list->deleteAllItems(); -// } - - S32 group_count = msg->getNumberOfBlocksFast(_PREHASH_GroupData); - if (0 == group_count) - { - if(group_list) group_list->addCommentText(std::string("None")); // *TODO: Translate - } - else - { - for(S32 i = 0; i < group_count; ++i) - { - msg->getU64( _PREHASH_GroupData, "GroupPowers", group_powers, i ); - msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupTitle, group_title, i ); - msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupID, group_id, i); - msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupName, group_name, i ); - msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupInsigniaID, group_insignia_id, i ); - - std::string group_string; - if (group_id.notNull()) - { - group_string.assign(group_name); - } - else - { - group_string.assign(""); - } - - // Is this really necessary? Remove existing entry if it exists. - // TODO: clear the whole list when a request for data is made - if (group_list) - { - S32 index = group_list->getItemIndex(group_id); - if ( index >= 0 ) - { - group_list->deleteSingleItem(index); - } - } - - LLSD row; - row["id"] = group_id; - row["columns"][0]["value"] = group_string; - row["columns"][0]["font"] = "SANSSERIF_SMALL"; - LLGroupData *group_data = NULL; - - if (avatar_id == agent_id) // own avatar - { - // Search for this group in the agent's groups list - LLDynamicArray::iterator i; - - for (i = gAgent.mGroups.begin(); i != gAgent.mGroups.end(); i++) - { - if (i->mID == group_id) - { - group_data = &*i; - break; - } - } - // Set normal color if not found or if group is visible in profile - if (group_data) - { - std::string font_style = group_data->mListInProfile ? "BOLD" : "NORMAL"; - if(group_data->mID == gAgent.getGroupID()) - font_style.append("|ITALIC"); - row["columns"][0]["font-style"] = font_style; - } - else - row["columns"][0]["font-style"] = "NORMAL"; - } - - if (group_list) - { - group_list->addElement(row,ADD_SORTED); - } - } + childSetValue("notes edit", pAvatarNotes->notes); + childSetEnabled("notes edit", true); + mHaveNotes = true; + mLastNotes = pAvatarNotes->notes; } } } @@ -2306,12 +2228,6 @@ void LLPanelAvatar::sendAvatarPropertiesUpdate() //A profile should never be mature. mature = FALSE; } - U32 want_to_mask = 0x0; - U32 skills_mask = 0x0; - std::string want_to_text; - std::string skills_text; - std::string languages_text; - mPanelAdvanced->getWantSkills(&want_to_mask, want_to_text, &skills_mask, skills_text, languages_text); LLUUID first_life_image_id; std::string first_life_about_text; @@ -2327,44 +2243,22 @@ void LLPanelAvatar::sendAvatarPropertiesUpdate() std::string about_text = mPanelSecondLife->childGetValue("about").asString(); - LLMessageSystem *msg = gMessageSystem; + LLAvatarData avatar_data; + avatar_data.image_id = mPanelSecondLife->getChild("img")->getImageAssetID(); + avatar_data.fl_image_id = first_life_image_id; + avatar_data.about_text = about_text; + avatar_data.fl_about_text = first_life_about_text; + avatar_data.allow_publish = allow_publish; + //avatar_data.mature = mature; + avatar_data.profile_url = mPanelWeb->childGetText("url_edit"); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesUpdate(&avatar_data); - msg->newMessageFast(_PREHASH_AvatarPropertiesUpdate); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - msg->nextBlockFast(_PREHASH_PropertiesData); - - LLTextureCtrl* image_ctrl = mPanelSecondLife->getChild("img"); - if(image_ctrl) - { - msg->addUUIDFast( _PREHASH_ImageID, image_ctrl->getImageAssetID()); - } - else - { - msg->addUUIDFast( _PREHASH_ImageID, LLUUID::null); - } -// msg->addUUIDFast( _PREHASH_ImageID, mPanelSecondLife->mimage_ctrl->getImageAssetID() ); - msg->addUUIDFast( _PREHASH_FLImageID, first_life_image_id); - msg->addStringFast( _PREHASH_AboutText, about_text); - msg->addStringFast( _PREHASH_FLAboutText, first_life_about_text); + 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); - msg->addBOOL("AllowPublish", allow_publish); - msg->addBOOL("MaturePublish", mature); - msg->addString("ProfileURL", mPanelWeb->childGetText("url_edit")); - gAgent.sendReliableMessage(); - - msg->newMessage("AvatarInterestsUpdate"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - msg->nextBlockFast(_PREHASH_PropertiesData); - msg->addU32Fast( _PREHASH_WantToMask, want_to_mask); - msg->addStringFast( _PREHASH_WantToText, want_to_text); - msg->addU32Fast( _PREHASH_SkillsMask, skills_mask); - msg->addStringFast( _PREHASH_SkillsText, skills_text); - msg->addString( "LanguagesText", languages_text); - gAgent.sendReliableMessage(); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarInterestsUpdate(&interests_data); } void LLPanelAvatar::selectTab(S32 tabnum) @@ -2390,77 +2284,6 @@ void LLPanelAvatar::selectTabByName(std::string tab_name) } } - -void LLPanelAvatar::processAvatarNotesReply(LLMessageSystem *msg, void**) -{ - // extract the agent id - LLUUID agent_id; - msg->getUUID("AgentData", "AgentID", agent_id); - - LLUUID target_id; - msg->getUUID("Data", "TargetID", target_id); - - // look up all panels which have this avatar - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelAvatar* self = *iter; - if (self->mAvatarID != target_id) - { - continue; - } - - std::string text; - msg->getString("Data", "Notes", text); - self->childSetValue("notes edit", text); - self->childSetEnabled("notes edit", true); - self->mHaveNotes = true; - self->mLastNotes = text; - } -} - - -void LLPanelAvatar::processAvatarClassifiedReply(LLMessageSystem *msg, void** userdata) -{ - LLUUID agent_id; - LLUUID target_id; - - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TargetID, target_id); - - // look up all panels which have this avatar target - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelAvatar* self = *iter; - if (self->mAvatarID != target_id) - { - continue; - } - - self->mPanelClassified->processAvatarClassifiedReply(msg, userdata); - } -} - -void LLPanelAvatar::processAvatarPicksReply(LLMessageSystem *msg, void** userdata) -{ - LLUUID agent_id; - LLUUID target_id; - - msg->getUUID("AgentData", "AgentID", agent_id); - msg->getUUID("AgentData", "TargetID", target_id); - - // look up all panels which have this avatar target - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelAvatar* self = *iter; - if (self->mAvatarID != target_id) - { - continue; - } - - self->mPanelPicks->processAvatarPicksReply(msg, userdata); - } -} - // static void LLPanelAvatar::onClickKick(void* userdata) { diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 812da4571..6d2c9441e 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -37,6 +37,7 @@ #include "v3dmath.h" #include "lluuid.h" #include "llmediactrl.h" +#include "llavatarpropertiesprocessor.h" class LLAvatarName; class LLButton; @@ -68,30 +69,29 @@ enum EOnlineStatus // Base class for all sub-tabs inside the avatar profile. Many of these // panels need to keep track of the parent panel (to get the avatar id) // and only request data from the database when they are first drawn. JC -class LLPanelAvatarTab : public LLPanel +class LLPanelAvatarTab : public LLPanel, public LLAvatarPropertiesObserver { public: LLPanelAvatarTab(const std::string& name, const LLRect &rect, LLPanelAvatar* panel_avatar); + virtual ~LLPanelAvatarTab(); + // Calls refresh() once per frame when panel is visible /*virtual*/ void draw(); LLPanelAvatar* getPanelAvatar() const { return mPanelAvatar; } + void setAvatarID(const LLUUID& avatar_id); + void setDataRequested(bool requested) { mDataRequested = requested; } bool isDataRequested() const { return mDataRequested; } - // If the data for this tab has not yet been requested, - // send the request. Used by tabs that are filled in only - // when they are first displayed. - // type is one of "avatarnotesrequest", "avatarpicksrequest", - // or "avatarclassifiedsrequest" - void sendAvatarProfileRequestIfNeeded(const std::string& method); - private: LLPanelAvatar* mPanelAvatar; bool mDataRequested; +protected: + LLUUID mAvatarID; }; @@ -101,6 +101,9 @@ public: LLPanelAvatarFirstLife(const std::string& name, const LLRect &rect, LLPanelAvatar* panel_avatar); /*virtual*/ BOOL postBuild(void); + + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + static void onClickImage( void *userdata); @@ -117,6 +120,8 @@ public: /*virtual*/ BOOL postBuild(void); /*virtual*/ void refresh(); + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + static void onClickImage( void *userdata); static void onClickFriends( void *userdata); static void onDoubleClickGroup(void* userdata); @@ -150,6 +155,8 @@ public: /*virtual*/ void refresh(); + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + void enableControls(BOOL own_avatar); void setWebURL(std::string url); @@ -177,6 +184,8 @@ public: /*virtual*/ BOOL postBuild(void); + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + void enableControls(BOOL own_avatar); void setWantSkills(U32 want_to_mask, const std::string& want_to_text, U32 skills_mask, const std::string& skills_text, @@ -204,6 +213,8 @@ public: /*virtual*/ void refresh(); + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type){} + void clearControls(); static void onCommitNotes(LLUICtrl* field, void* userdata); @@ -219,6 +230,8 @@ public: /*virtual*/ void refresh(); + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + // If can close, return TRUE. If cannot close, pop save/discard dialog // and return FALSE. BOOL canClose(); @@ -230,10 +243,6 @@ public: // Delete all the classified sub-panels from the tab container void deleteClassifiedPanels(); - // Unpack the outline of classified for this avatar (count, names, but not - // actual data). - void processAvatarClassifiedReply(LLMessageSystem* msg, void**); - private: static void onClickNew(void* data); static void onClickDelete(void* data); @@ -252,14 +261,11 @@ public: /*virtual*/ void refresh(); + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + // Delete all the pick sub-panels from the tab container void deletePickPanels(); - // Unpack the outline of picks for this avatar (count, names, but not - // actual data). - void processAvatarPicksReply(LLMessageSystem* msg, void**); - void processAvatarClassifiedReply(LLMessageSystem* msg, void**); - private: static void onClickNew(void* data); static void onClickDelete(void* data); @@ -276,7 +282,7 @@ private: }; -class LLPanelAvatar : public LLPanel +class LLPanelAvatar : public LLPanel, public LLAvatarPropertiesObserver { public: @@ -285,6 +291,8 @@ public: /*virtual*/ BOOL postBuild(void); + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + // If can close, return TRUE. If cannot close, pop save/discard dialog // and return FALSE. BOOL canClose(); @@ -318,13 +326,6 @@ public: BOOL haveData() { return mHaveProperties && mHaveStatistics; } BOOL isEditable() const { return mAllowEdit; } - static void processAvatarPropertiesReply(LLMessageSystem *msg, void **); - static void processAvatarInterestsReply(LLMessageSystem *msg, void **); - static void processAvatarGroupsReply(LLMessageSystem* msg, void**); - static void processAvatarNotesReply(LLMessageSystem *msg, void **); - static void processAvatarPicksReply(LLMessageSystem *msg, void **); - static void processAvatarClassifiedReply(LLMessageSystem *msg, void **); - static void onClickTrack( void *userdata); static void onClickIM( void *userdata); static void onClickGroupInvite( void *userdata); @@ -369,6 +370,8 @@ public: LLPanelAvatarFirstLife* mPanelFirstLife; LLPanelAvatarWeb* mPanelWeb; + std::list mAvatarPanelList; + LLDropTarget* mDropTarget; // Teen users are not allowed to see or enter data into the first life page, diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index c34f1aa30..9625cfcdc 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -213,12 +213,21 @@ LLPanelClassified::LLPanelClassified(bool in_finder, bool from_search) LLPanelClassified::~LLPanelClassified() { + if(mCreatorID.notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mCreatorID, this); + } sAllPanels.remove(this); } void LLPanelClassified::reset() { + if(mCreatorID.notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mCreatorID, this); + } + mClassifiedID.setNull(); mCreatorID.setNull(); mParcelID.setNull(); @@ -322,6 +331,82 @@ BOOL LLPanelClassified::postBuild() return TRUE; } +void LLPanelClassified::processProperties(void* data, EAvatarProcessorType type) +{ + if(APT_CLASSIFIED_INFO == type) + { + lldebugs << "processClassifiedInfoReply()" << llendl; + + LLAvatarClassifiedInfo* c_info = static_cast(data); + if(c_info && mClassifiedID == c_info->classified_id) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mCreatorID, this); + + // "Location text" is actually the original + // name that owner gave the parcel, and the location. + std::string location_text = c_info->parcel_name; + + if (!location_text.empty()) + location_text.append(", "); + + S32 region_x = llround((F32)c_info->pos_global.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = llround((F32)c_info->pos_global.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = llround((F32)c_info->pos_global.mdV[VZ]); + + std::string buffer = llformat("%s (%d, %d, %d)", c_info->sim_name.c_str(), region_x, region_y, region_z); + location_text.append(buffer); + + //BOOL enabled = is_cf_enabled(flags); + + time_t tim = c_info->creation_date; + tm *now=localtime(&tim); + + + // Found the panel, now fill in the information + mClassifiedID = c_info->classified_id; + mCreatorID = c_info->creator_id; + mParcelID = c_info->parcel_id; + mPriceForListing = c_info->price_for_listing; + mSimName = c_info->sim_name; + mPosGlobal = c_info->pos_global; + + // Update UI controls + mNameEditor->setText(c_info->name); + mDescEditor->setText(c_info->description); + mSnapshotCtrl->setImageAssetID(c_info->snapshot_id); + mLocationEditor->setText(location_text); + mLocationChanged = false; + + mCategoryCombo->setCurrentByIndex(c_info->category - 1); + + mMatureCombo->setCurrentByIndex(is_cf_mature(c_info->flags) ? MATURE_CONTENT : PG_CONTENT); + + if (mAutoRenewCheck) + { + mAutoRenewCheck->set(is_cf_auto_renew(c_info->flags)); + } + + std::string datestr; + timeStructToFormattedString(now, gSavedSettings.getString("ShortDateFormat"), datestr); + LLStringUtil::format_map_t string_args; + string_args["[DATE]"] = datestr; + string_args["[CURRENCY]"] = gHippoGridManager->getConnectedGrid()->getCurrencySymbol(); + string_args["[AMT]"] = llformat("%d", c_info->price_for_listing); + childSetText("classified_info_text", getString("ad_placed_paid", string_args)); + + // If we got data from the database, we know the listing is paid for. + mPaidFor = TRUE; + + mUpdateBtn->setLabel(getString("update_txt")); + + resetDirty(); + + // I don't know if a second call is deliberate or a bad merge, so I'm leaving it here. + resetDirty(); + } + } +} + BOOL LLPanelClassified::titleIsValid() { // Disallow leading spaces, punctuation, etc. that screw up @@ -488,19 +573,13 @@ std::string LLPanelClassified::getClassifiedName() void LLPanelClassified::sendClassifiedInfoRequest() { - LLMessageSystem *msg = gMessageSystem; - if (mClassifiedID != mRequestedID) { - msg->newMessageFast(_PREHASH_ClassifiedInfoRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->nextBlockFast(_PREHASH_Data); - msg->addUUIDFast(_PREHASH_ClassifiedID, mClassifiedID); - gAgent.sendReliableMessage(); + LLAvatarPropertiesProcessor::getInstance()->addObserver(mCreatorID, this); + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(mClassifiedID); mDataRequested = TRUE; + mRequestedID = mClassifiedID; // While we're at it let's get the stats from the new table if that @@ -517,9 +596,10 @@ void LLPanelClassified::sendClassifiedInfoRequest() } } - void LLPanelClassified::sendClassifiedInfoUpdate() { + LLAvatarClassifiedInfo c_data; + // If we don't have a classified id yet, we'll need to generate one, // otherwise we'll keep overwriting classified_id 00000 in the database. if (mClassifiedID.isNull()) @@ -528,180 +608,24 @@ void LLPanelClassified::sendClassifiedInfoUpdate() mClassifiedID.generate(); } - LLMessageSystem* msg = gMessageSystem; + c_data.agent_id = gAgent.getID(); + c_data.classified_id = mClassifiedID; + c_data.category = mCategoryCombo->getCurrentIndex() + 1; + c_data.name = mNameEditor->getText(); + c_data.description = mDescEditor->getText(); + c_data.parcel_id = mParcelID; + c_data.snapshot_id = mSnapshotCtrl->getImageAssetID(); + c_data.pos_global = mPosGlobal; + BOOL auto_renew = mAutoRenewCheck && mAutoRenewCheck->get(); + c_data.flags = pack_classified_flags_request(auto_renew, false, mMatureCombo->getCurrentIndex() == MATURE_CONTENT, false); + c_data.price_for_listing = mPriceForListing; + c_data.parent_estate = 0; //probably not required. - msg->newMessageFast(_PREHASH_ClassifiedInfoUpdate); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Data); - msg->addUUIDFast(_PREHASH_ClassifiedID, mClassifiedID); - // TODO: fix this - U32 category = mCategoryCombo->getCurrentIndex() + 1; - msg->addU32Fast(_PREHASH_Category, category); - msg->addStringFast(_PREHASH_Name, mNameEditor->getText()); - msg->addStringFast(_PREHASH_Desc, mDescEditor->getText()); - - // fills in on simulator if null - msg->addUUIDFast(_PREHASH_ParcelID, mParcelID); - // fills in on simulator if null - msg->addU32Fast(_PREHASH_ParentEstate, 0); - msg->addUUIDFast(_PREHASH_SnapshotID, mSnapshotCtrl->getImageAssetID()); - msg->addVector3dFast(_PREHASH_PosGlobal, mPosGlobal); - BOOL mature = mMatureCombo->getCurrentIndex() == MATURE_CONTENT; - BOOL auto_renew = FALSE; - if (mAutoRenewCheck) - { - auto_renew = mAutoRenewCheck->get(); - } - // These flags doesn't matter here. - const bool adult_enabled = false; - const bool is_pg = false; - U8 flags = pack_classified_flags_request(auto_renew, is_pg, mature, adult_enabled); - msg->addU8Fast(_PREHASH_ClassifiedFlags, flags); - msg->addS32("PriceForListing", mPriceForListing); - gAgent.sendReliableMessage(); + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoUpdate(&c_data); mDirty = false; } - -//static -void LLPanelClassified::processClassifiedInfoReply(LLMessageSystem *msg, void **) -{ - lldebugs << "processClassifiedInfoReply()" << llendl; - // Extract the agent id and verify the message is for this - // client. - LLUUID agent_id; - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); - if (agent_id != gAgent.getID()) - { - llwarns << "Agent ID mismatch in processClassifiedInfoReply" - << llendl; - return; - } - - LLUUID classified_id; - msg->getUUIDFast(_PREHASH_Data, _PREHASH_ClassifiedID, classified_id); - - LLUUID creator_id; - msg->getUUIDFast(_PREHASH_Data, _PREHASH_CreatorID, creator_id); - - LLUUID parcel_id; - msg->getUUIDFast(_PREHASH_Data, _PREHASH_ParcelID, parcel_id); - - std::string name; - msg->getStringFast(_PREHASH_Data, _PREHASH_Name, name); - - std::string desc; - msg->getStringFast(_PREHASH_Data, _PREHASH_Desc, desc); - - LLUUID snapshot_id; - msg->getUUIDFast(_PREHASH_Data, _PREHASH_SnapshotID, snapshot_id); - - // "Location text" is actually the original - // name that owner gave the parcel, and the location. - std::string location_text; - - msg->getStringFast(_PREHASH_Data, _PREHASH_ParcelName, location_text); - if (!location_text.empty()) - { - location_text.append(", "); - } - - std::string sim_name; - msg->getStringFast(_PREHASH_Data, _PREHASH_SimName, sim_name); - - LLVector3d pos_global; - msg->getVector3dFast(_PREHASH_Data, _PREHASH_PosGlobal, pos_global); - - S32 region_x = llround((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS; - S32 region_y = llround((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS; - S32 region_z = llround((F32)pos_global.mdV[VZ]); - - std::string buffer = llformat("%s (%d, %d, %d)", sim_name.c_str(), region_x, region_y, region_z); - location_text.append(buffer); - - U8 flags; - msg->getU8Fast(_PREHASH_Data, _PREHASH_ClassifiedFlags, flags); - //BOOL enabled = is_cf_enabled(flags); - bool mature = is_cf_mature(flags); - bool auto_renew = is_cf_auto_renew(flags); - - U32 date = 0; - msg->getU32Fast(_PREHASH_Data, _PREHASH_CreationDate, date); - time_t tim = date; - tm *now=localtime(&tim); - - // future use - U32 expiration_date = 0; - msg->getU32("Data", "ExpirationDate", expiration_date); - - U32 category = 0; - msg->getU32Fast(_PREHASH_Data, _PREHASH_Category, category); - - S32 price_for_listing = 0; - msg->getS32("Data", "PriceForListing", price_for_listing); - - // Look up the panel to fill in - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelClassified* self = *iter; - // For top picks, must match pick id - if (self->mClassifiedID != classified_id) - { - continue; - } - - // Found the panel, now fill in the information - self->mClassifiedID = classified_id; - self->mCreatorID = creator_id; - self->mParcelID = parcel_id; - self->mPriceForListing = price_for_listing; - self->mSimName.assign(sim_name); - self->mPosGlobal = pos_global; - - // Update UI controls - self->mNameEditor->setText(name); - self->mDescEditor->setText(desc); - self->mSnapshotCtrl->setImageAssetID(snapshot_id); - self->mLocationEditor->setText(location_text); - self->mLocationChanged = false; - - self->mCategoryCombo->setCurrentByIndex(category - 1); - if(mature) - { - self->mMatureCombo->setCurrentByIndex(MATURE_CONTENT); - } - else - { - self->mMatureCombo->setCurrentByIndex(PG_CONTENT); - } - if (self->mAutoRenewCheck) - { - self->mAutoRenewCheck->set(auto_renew); - } - - std::string datestr; - timeStructToFormattedString(now, gSavedSettings.getString("ShortDateFormat"), datestr); - LLStringUtil::format_map_t string_args; - string_args["[DATE]"] = datestr; - string_args["[CURRENCY]"] = gHippoGridManager->getConnectedGrid()->getCurrencySymbol(); - string_args["[AMT]"] = llformat("%d", price_for_listing); - self->childSetText("classified_info_text", self->getString("ad_placed_paid", string_args)); - - // If we got data from the database, we know the listing is paid for. - self->mPaidFor = TRUE; - - self->mUpdateBtn->setLabel(self->getString("update_txt")); - - self->resetDirty(); - - // I don't know if a second call is deliberate or a bad merge, so I'm leaving it here. - self->resetDirty(); - } -} - void LLPanelClassified::draw() { refresh(); diff --git a/indra/newview/llpanelclassified.h b/indra/newview/llpanelclassified.h index 417eddf46..a3bb42554 100644 --- a/indra/newview/llpanelclassified.h +++ b/indra/newview/llpanelclassified.h @@ -37,6 +37,7 @@ #ifndef LL_LLPANELCLASSIFIED_H #define LL_LLPANELCLASSIFIED_H +#include "llavatarpropertiesprocessor.h" #include "llpanel.h" #include "llclassifiedinfo.h" #include "v3dmath.h" @@ -55,7 +56,7 @@ class LLTextureCtrl; class LLUICtrl; class LLMessageSystem; -class LLPanelClassified : public LLPanel +class LLPanelClassified : public LLPanel, public LLAvatarPropertiesObserver { public: LLPanelClassified(bool in_finder, bool from_search); @@ -69,6 +70,8 @@ public: /*virtual*/ void refresh(); + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + void apply(); // If can close, return TRUE. If cannot close, pop save/discard dialog @@ -98,8 +101,6 @@ public: void sendClassifiedInfoUpdate(); void resetDirty(); - static void processClassifiedInfoReply(LLMessageSystem* msg, void**); - // Confirmation dialogs flow in this order bool confirmMature(const LLSD& notification, const LLSD& response); void gotMature(); diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp index aece29b17..812ec22a0 100644 --- a/indra/newview/llpanelpick.cpp +++ b/indra/newview/llpanelpick.cpp @@ -112,12 +112,20 @@ LLPanelPick::LLPanelPick(BOOL top_pick) LLPanelPick::~LLPanelPick() { + if(mDataRequested && !mDataReceived) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mCreatorID, this); + } sAllPanels.remove(this); } void LLPanelPick::reset() { + if(mDataRequested && !mDataReceived) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mCreatorID, this); + } mPickID.setNull(); mCreatorID.setNull(); mParcelID.setNull(); @@ -178,6 +186,72 @@ BOOL LLPanelPick::postBuild() return TRUE; } +void LLPanelPick::processProperties(void* data, EAvatarProcessorType type) +{ + if(APT_PICK_INFO != type) + { + return; + } + + LLPickData* pick_info = static_cast(data); + //llassert_always(pick_info->creator_id != gAgent.getID()); + //llassert_always(mCreatorID != gAgent.getID()); + if(!pick_info + || pick_info->creator_id != mCreatorID + || pick_info->pick_id != mPickID) + { + return; + } + + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mCreatorID, this); + + // "Location text" is actually the owner name, the original + // name that owner gave the parcel, and the location. + std::string location_text = pick_info->user_name + ", "; + + if (!pick_info->original_name.empty()) + { + location_text.append(pick_info->original_name); + location_text.append(", "); + } + + location_text.append(pick_info->sim_name); + location_text.append(" "); + + //Fix for location text importing - RK + for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) + { + LLPanelPick* self = *iter; + if(!self->mImporting) self->mLocationText = location_text; + else location_text = self->mLocationText; + self->mImporting = false; + } + + S32 region_x = llround((F32)pick_info->pos_global.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = llround((F32)pick_info->pos_global.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = llround((F32)pick_info->pos_global.mdV[VZ]); + + location_text.append(llformat("(%d, %d, %d)", region_x, region_y, region_z)); + + mDataReceived = TRUE; + + // Found the panel, now fill in the information + mPickID = pick_info->pick_id; + mCreatorID = pick_info->creator_id; + mParcelID = pick_info->parcel_id; + mSimName = pick_info->sim_name; + mPosGlobal = pick_info->pos_global; + + // Update UI controls + mNameEditor->setText(pick_info->name); + mDescEditor->setText(pick_info->desc); + mSnapshotCtrl->setImageAssetID(pick_info->snapshot_id); + mLocationEditor->setText(location_text); + mEnabledCheck->set(pick_info->enabled); + + mSortOrderEditor->setText(llformat("%d", pick_info->sort_order)); + +} // Fill in some reasonable defaults for a new pick. void LLPanelPick::initNewPick() @@ -307,12 +381,9 @@ std::string LLPanelPick::getPickName() void LLPanelPick::sendPickInfoRequest() { - // Must ask for a pick based on the creator id because - // the pick database is distributed to the inventory cluster. JC - std::vector strings; - strings.push_back( mCreatorID.asString() ); - strings.push_back( mPickID.asString() ); - send_generic_message("pickinforequest", strings); + //llassert_always(mCreatorID != gAgent.getID()); + LLAvatarPropertiesProcessor::getInstance()->addObserver(mCreatorID, this); + LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest(mCreatorID, mPickID); mDataRequested = TRUE; } @@ -320,6 +391,8 @@ void LLPanelPick::sendPickInfoRequest() void LLPanelPick::sendPickInfoUpdate() { + LLPickData pick_data; + // If we don't have a pick id yet, we'll need to generate one, // otherwise we'll keep overwriting pick_id 00000 in the database. if (mPickID.isNull()) @@ -327,146 +400,29 @@ void LLPanelPick::sendPickInfoUpdate() mPickID.generate(); } - LLMessageSystem* msg = gMessageSystem; + pick_data.agent_id = gAgent.getID(); + pick_data.session_id = gAgent.getSessionID(); + pick_data.pick_id = mPickID; + pick_data.creator_id = gAgent.getID(); - msg->newMessage("PickInfoUpdate"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("PickID", mPickID); - msg->addUUID("CreatorID", mCreatorID); - msg->addBOOL("TopPick", mTopPick); - // fills in on simulator if null - msg->addUUID("ParcelID", mParcelID); - msg->addString("Name", mNameEditor->getText()); - msg->addString("Desc", mDescEditor->getText()); - msg->addUUID("SnapshotID", mSnapshotCtrl->getImageAssetID()); - msg->addVector3d("PosGlobal", mPosGlobal); - - // Only top picks have a sort order - S32 sort_order; - if (mTopPick) - { - sort_order = atoi(mSortOrderEditor->getText().c_str()); - } + //legacy var need to be deleted + pick_data.top_pick = mTopPick; + pick_data.parcel_id = mParcelID; + pick_data.name = mNameEditor->getText(); + pick_data.desc = mDescEditor->getText(); + pick_data.snapshot_id = mSnapshotCtrl->getImageAssetID(); + pick_data.pos_global = mPosGlobal; + if(mTopPick) + pick_data.sort_order = atoi(mSortOrderEditor->getText().c_str()); else - { - sort_order = 0; - } - msg->addS32("SortOrder", sort_order); - msg->addBOOL("Enabled", mEnabledCheck->get()); - gAgent.sendReliableMessage(); + pick_data.sort_order = 0; + + pick_data.enabled = mEnabledCheck->get(); + + LLAvatarPropertiesProcessor::getInstance()->sendPickInfoUpdate(&pick_data); } -//static -void LLPanelPick::processPickInfoReply(LLMessageSystem *msg, void **) -{ - // Extract the agent id and verify the message is for this - // client. - LLUUID agent_id; - msg->getUUID("AgentData", "AgentID", agent_id ); - if (agent_id != gAgent.getID()) - { - llwarns << "Agent ID mismatch in processPickInfoReply" - << llendl; - return; - } - - LLUUID pick_id; - msg->getUUID("Data", "PickID", pick_id); - - LLUUID creator_id; - msg->getUUID("Data", "CreatorID", creator_id); - - BOOL top_pick; - msg->getBOOL("Data", "TopPick", top_pick); - - LLUUID parcel_id; - msg->getUUID("Data", "ParcelID", parcel_id); - - std::string name; - msg->getString("Data", "Name", name); - - std::string desc; - msg->getString("Data", "Desc", desc); - - LLUUID snapshot_id; - msg->getUUID("Data", "SnapshotID", snapshot_id); - - // "Location text" is actually the owner name, the original - // name that owner gave the parcel, and the location. - std::string location_text; - msg->getString("Data", "User", location_text); - location_text.append(", "); - - std::string original_name; - msg->getString("Data", "OriginalName", original_name); - if (!original_name.empty()) - { - location_text.append(original_name); - location_text.append(", "); - } - - std::string sim_name; - msg->getString("Data", "SimName", sim_name); - location_text.append(sim_name); - location_text.append(" "); - - //Fix for location text importing - RK - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelPick* self = *iter; - if(!self->mImporting) self->mLocationText = location_text; - else location_text = self->mLocationText; - self->mImporting = false; - } - - LLVector3d pos_global; - msg->getVector3d("Data", "PosGlobal", pos_global); - - S32 region_x = llround((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS; - S32 region_y = llround((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS; - S32 region_z = llround((F32)pos_global.mdV[VZ]); - - location_text.append(llformat("(%d, %d, %d)", region_x, region_y, region_z)); - - S32 sort_order; - msg->getS32("Data", "SortOrder", sort_order); - - BOOL enabled; - msg->getBOOL("Data", "Enabled", enabled); - - // Look up the panel to fill in - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelPick* self = *iter; - // For top picks, must match pick id - if (self->mPickID != pick_id) - { - continue; - } - - self->mDataReceived = TRUE; - - // Found the panel, now fill in the information - self->mPickID = pick_id; - self->mCreatorID = creator_id; - self->mParcelID = parcel_id; - self->mSimName.assign(sim_name); - self->mPosGlobal = pos_global; - - // Update UI controls - self->mNameEditor->setText(std::string(name)); - self->mDescEditor->setText(std::string(desc)); - self->mSnapshotCtrl->setImageAssetID(snapshot_id); - self->mLocationEditor->setText(location_text); - self->mEnabledCheck->set(enabled); - - self->mSortOrderEditor->setText(llformat("%d", sort_order)); - } -} void LLPanelPick::draw() { @@ -611,6 +567,9 @@ void LLPanelPick::onCommitAny(LLUICtrl* ctrl, void* data) { LLPanelPick* self = (LLPanelPick*)data; + if(self->mCreatorID != gAgent.getID()) + return; + // have we received up to date data for this pick? if (self->mDataReceived) { diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h index bfa702251..84f41b8da 100644 --- a/indra/newview/llpanelpick.h +++ b/indra/newview/llpanelpick.h @@ -40,6 +40,7 @@ #include "llpanel.h" #include "v3dmath.h" #include "lluuid.h" +#include "llavatarpropertiesprocessor.h" class LLButton; class LLCheckBoxCtrl; @@ -52,7 +53,7 @@ class LLUICtrl; class LLMessageSystem; class AIFilePicker; -class LLPanelPick : public LLPanel +class LLPanelPick : public LLPanel, public LLAvatarPropertiesObserver { public: LLPanelPick(BOOL top_pick); @@ -66,6 +67,8 @@ public: /*virtual*/ void refresh(); + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + // Setup a new pick, including creating an id, giving a sane // initial position, etc. void initNewPick(); @@ -91,8 +94,6 @@ public: void sendPickInfoRequest(); void sendPickInfoUpdate(); - static void processPickInfoReply(LLMessageSystem* msg, void**); - protected: static void onClickTeleport(void* data); static void onClickMap(void* data); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 2b29ac839..36b25a27c 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -3617,20 +3617,20 @@ void register_viewer_callbacks(LLMessageSystem* msg) LLViewerParcelMgr::processParcelDwellReply); msg->setHandlerFunc("AvatarPropertiesReply", - LLPanelAvatar::processAvatarPropertiesReply); + &LLAvatarPropertiesProcessor::processAvatarPropertiesReply); msg->setHandlerFunc("AvatarInterestsReply", - LLPanelAvatar::processAvatarInterestsReply); + &LLAvatarPropertiesProcessor::processAvatarInterestsReply); msg->setHandlerFunc("AvatarGroupsReply", - LLPanelAvatar::processAvatarGroupsReply); + &LLAvatarPropertiesProcessor::processAvatarGroupsReply); // ratings deprecated //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply, // LLPanelAvatar::processAvatarStatisticsReply); msg->setHandlerFunc("AvatarNotesReply", - LLPanelAvatar::processAvatarNotesReply); + &LLAvatarPropertiesProcessor::processAvatarNotesReply); msg->setHandlerFunc("AvatarPicksReply", - LLPanelAvatar::processAvatarPicksReply); + &LLAvatarPropertiesProcessor::processAvatarPicksReply); msg->setHandlerFunc("AvatarClassifiedReply", - LLPanelAvatar::processAvatarClassifiedReply); + &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply); msg->setHandlerFuncFast(_PREHASH_CreateGroupReply, LLGroupMgr::processCreateGroupReply); @@ -3704,8 +3704,9 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFunc("MapItemReply", LLWorldMap::processMapItemReply); msg->setHandlerFunc("EventInfoReply", LLPanelEvent::processEventInfoReply); - msg->setHandlerFunc("PickInfoReply", LLPanelPick::processPickInfoReply); - msg->setHandlerFunc("ClassifiedInfoReply", LLPanelClassified::processClassifiedInfoReply); + msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply); + //msg->setHandlerFunc("ClassifiedInfoReply", LLPanelClassified::processClassifiedInfoReply); + msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply); msg->setHandlerFunc("ParcelInfoReply", LLPanelPlace::processParcelInfoReply); msg->setHandlerFunc("ScriptDialog", process_script_dialog); msg->setHandlerFunc("LoadURL", process_load_url); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index bff31c7f0..590625b72 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -46,6 +46,7 @@ #include "llagentcamera.h" #include "llagentwearables.h" #include "llanimationstates.h" +#include "llavatarpropertiesprocessor.h" #include "llviewercontrol.h" #include "lldrawpoolavatar.h" #include "lldriverparam.h" @@ -7936,9 +7937,7 @@ bool LLVOAvatar::sendAvatarTexturesRequest() bool sent = false; if (mRuthTimer.getElapsedTimeF32() > DERUTHING_TIMEOUT_SECONDS) { - std::vector strings; - strings.push_back(getID().asString()); - send_generic_message("avatartexturesrequest", strings); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarTexturesRequest(getID()); mRuthTimer.reset(); sent = true; }