diff options
Diffstat (limited to 'indra/newview/llpanelprofile.cpp')
-rw-r--r-- | indra/newview/llpanelprofile.cpp | 1658 |
1 files changed, 1432 insertions, 226 deletions
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 5f13b223fb..49b18874f3 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llpanelprofile.cpp * @brief Profile panel implementation * * $LicenseInfo:firstyear=2009&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$ */ @@ -27,31 +27,66 @@ #include "llviewerprecompiledheaders.h" #include "llpanelprofile.h" -#include "llagent.h" +// Common +#include "llavatarnamecache.h" +#include "llslurl.h" +#include "lldateutil.h" //ageFromDate + +// UI +#include "llavatariconctrl.h" +#include "llclipboard.h" +#include "llcheckboxctrl.h" +#include "lllineeditor.h" +#include "llloadingindicator.h" +#include "llmenubutton.h" +#include "lltabcontainer.h" +#include "lltextbox.h" +#include "lltexteditor.h" +#include "lltexturectrl.h" +#include "lltoggleablemenu.h" +#include "llgrouplist.h" + +// Newview +#include "llagent.h" //gAgent +#include "llagentpicksinfo.h" #include "llavataractions.h" -#include "llfloaterreg.h" +#include "llavatarpropertiesprocessor.h" +#include "llcallingcard.h" #include "llcommandhandler.h" -#include "llnotificationsutil.h" -#include "llpanelpicks.h" -#include "lltabcontainer.h" -#include "llviewercontrol.h" -#include "llviewernetwork.h" +#include "llfloaterreg.h" +#include "llfirstuse.h" +#include "llgroupactions.h" #include "llmutelist.h" +#include "llnotificationsutil.h" #include "llpanelblockedlist.h" +#include "llpanelprofileclassifieds.h" +#include "llpanelprofilepicks.h" +#include "lltrans.h" +#include "llviewercontrol.h" +#include "llviewermenu.h" //is_agent_mappable +#include "llvoiceclient.h" #include "llweb.h" -static const std::string PANEL_PICKS = "panel_picks"; -std::string getProfileURL(const std::string& agent_name) -{ - std::string url = "[WEB_PROFILE_URL][AGENT_NAME]"; - LLSD subs; - subs["WEB_PROFILE_URL"] = LLGridManager::getInstance()->getWebProfileURL(); - subs["AGENT_NAME"] = agent_name; - url = LLWeb::expandURLSubstitutions(url, subs); - LLStringUtil::toLower(url); - return url; -} +static LLPanelInjector<LLPanelProfileSecondLife> t_panel_profile_secondlife("panel_profile_secondlife"); +static LLPanelInjector<LLPanelProfileWeb> t_panel_web("panel_profile_web"); +static LLPanelInjector<LLPanelProfileInterests> t_panel_interests("panel_profile_interests"); +static LLPanelInjector<LLPanelProfilePicks> t_panel_picks("panel_profile_picks"); +static LLPanelInjector<LLPanelProfileFirstLife> t_panel_firstlife("panel_profile_firstlife"); +static LLPanelInjector<LLPanelProfileNotes> t_panel_notes("panel_profile_notes"); +static LLPanelInjector<LLPanelProfile> t_panel_profile("panel_profile"); + +static const std::string PANEL_SECONDLIFE = "panel_profile_secondlife"; +static const std::string PANEL_WEB = "panel_profile_web"; +static const std::string PANEL_INTERESTS = "panel_profile_interests"; +static const std::string PANEL_PICKS = "panel_profile_picks"; +static const std::string PANEL_CLASSIFIEDS = "panel_profile_classifieds"; +static const std::string PANEL_FIRSTLIFE = "panel_profile_firstlife"; +static const std::string PANEL_NOTES = "panel_profile_notes"; + + +////////////////////////////////////////////////////////////////////////// +// LLProfileHandler class LLProfileHandler : public LLCommandHandler { @@ -73,6 +108,10 @@ public: }; LLProfileHandler gProfileHandler; + +////////////////////////////////////////////////////////////////////////// +// LLAgentHandler + class LLAgentHandler : public LLCommandHandler { public: @@ -184,273 +223,1440 @@ public: LLAgentHandler gAgentHandler; -//-- LLPanelProfile::ChildStack begins ---------------------------------------- -LLPanelProfile::ChildStack::ChildStack() -: mParent(NULL) + +////////////////////////////////////////////////////////////////////////// +// LLPanelProfileSecondLife + +LLPanelProfileSecondLife::LLPanelProfileSecondLife() + : LLPanelProfileTab() + , mStatusText(NULL) + , mAvatarNameCacheConnection() { } -LLPanelProfile::ChildStack::~ChildStack() +LLPanelProfileSecondLife::~LLPanelProfileSecondLife() { - while (mStack.size() != 0) - { - view_list_t& top = mStack.back(); - for (view_list_t::const_iterator it = top.begin(); it != top.end(); ++it) - { - LLView* viewp = *it; - if (viewp) - { - viewp->die(); - } - } - mStack.pop_back(); - } + if (getAvatarId().notNull()) + { + LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); + } + + if (LLVoiceClient::instanceExists()) + { + LLVoiceClient::getInstance()->removeObserver((LLVoiceClientStatusObserver*)this); + } + + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } } -void LLPanelProfile::ChildStack::setParent(LLPanel* parent) +BOOL LLPanelProfileSecondLife::postBuild() { - llassert_always(parent != NULL); - mParent = parent; + mStatusText = getChild<LLTextBox>("status"); + mGroupList = getChild<LLGroupList>("group_list"); + mShowInSearchCheckbox = getChild<LLCheckBoxCtrl>("show_in_search_checkbox"); + mSecondLifePic = getChild<LLTextureCtrl>("2nd_life_pic"); + mSecondLifePicLayout = getChild<LLPanel>("image_stack"); + mDescriptionEdit = getChild<LLTextBase>("sl_description_edit"); + mTeleportButton = getChild<LLButton>("teleport"); + mShowOnMapButton = getChild<LLButton>("show_on_map_btn"); + mBlockButton = getChild<LLButton>("block"); + mUnblockButton = getChild<LLButton>("unblock"); + mNameLabel = getChild<LLUICtrl>("name_label"); + mDisplayNameButton = getChild<LLButton>("set_name"); + mAddFriendButton = getChild<LLButton>("add_friend"); + mGroupInviteButton = getChild<LLButton>("group_invite"); + mPayButton = getChild<LLButton>("pay"); + mIMButton = getChild<LLButton>("im"); + mCopyMenuButton = getChild<LLMenuButton>("copy_btn"); + mGiveInvPanel = getChild<LLPanel>("give_stack"); + + mStatusText->setVisible(FALSE); + mCopyMenuButton->setVisible(FALSE); + + mAddFriendButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onAddFriendButtonClick, this)); + mIMButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onIMButtonClick, this)); + mTeleportButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onTeleportButtonClick, this)); + mShowOnMapButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onMapButtonClick, this)); + mPayButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::pay, this)); + mBlockButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onClickToggleBlock, this)); + mUnblockButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onClickToggleBlock, this)); + mGroupInviteButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onGroupInvite,this)); + mDisplayNameButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onClickSetName, this)); + mSecondLifePic->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onCommitTexture, this)); + + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar commit; + commit.add("Profile.CopyName", [this](LLUICtrl*, const LLSD& userdata) { onCommitMenu(userdata); }); + + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable; + enable.add("Profile.EnableCall", [this](LLUICtrl*, const LLSD&) { return mVoiceStatus; }); + enable.add("Profile.EnableGod", [](LLUICtrl*, const LLSD&) { return gAgent.isGodlike(); }); + + mGroupList->setDoubleClickCallback(boost::bind(&LLPanelProfileSecondLife::openGroupProfile, this)); + mGroupList->setReturnCallback(boost::bind(&LLPanelProfileSecondLife::openGroupProfile, this)); + + LLVoiceClient::getInstance()->addObserver((LLVoiceClientStatusObserver*)this); + mCopyMenuButton->setMenu("menu_name_field.xml", LLMenuButton::MP_BOTTOM_RIGHT); + + return TRUE; } -/// Save current parent's child views and remove them from the child list. -bool LLPanelProfile::ChildStack::push() +void LLPanelProfileSecondLife::onOpen(const LLSD& key) { - view_list_t vlist = *mParent->getChildList(); + LLPanelProfileTab::onOpen(key); - for (view_list_t::const_iterator it = vlist.begin(); it != vlist.end(); ++it) - { - LLView* viewp = *it; - mParent->removeChild(viewp); - } + resetData(); + + LLUUID avatar_id = getAvatarId(); + LLAvatarPropertiesProcessor::getInstance()->addObserver(avatar_id, this); + + BOOL own_profile = getSelfProfile(); + + mGroupInviteButton->setVisible(!own_profile); + mShowOnMapButton->setVisible(!own_profile); + mPayButton->setVisible(!own_profile); + mTeleportButton->setVisible(!own_profile); + mIMButton->setVisible(!own_profile); + mAddFriendButton->setVisible(!own_profile); + mBlockButton->setVisible(!own_profile); + mUnblockButton->setVisible(!own_profile); + mGroupList->setShowNone(!own_profile); + mGiveInvPanel->setVisible(!own_profile); - mStack.push_back(vlist); - dump(); - return true; + mSecondLifePic->setOpenTexPreview(!own_profile); + + if (own_profile && !getEmbedded()) + { + // Group list control cannot toggle ForAgent loading + // Less than ideal, but viewing own profile via search is edge case + mGroupList->enableForAgent(false); + } + + if (own_profile && !getEmbedded() ) + { + mNameLabel->setVisible(FALSE); + mDisplayNameButton->setVisible(TRUE); + mDisplayNameButton->setEnabled(TRUE); + } + + mDescriptionEdit->setParseHTML(!own_profile && !getEmbedded()); + + LLProfileDropTarget* drop_target = getChild<LLProfileDropTarget>("drop_target"); + drop_target->setVisible(!own_profile); + drop_target->setEnabled(!own_profile); + + if (!own_profile) + { + mVoiceStatus = LLAvatarActions::canCall() && (LLAvatarActions::isFriend(avatar_id) ? LLAvatarTracker::instance().isBuddyOnline(avatar_id) : TRUE); + drop_target->setAgentID(avatar_id); + updateOnlineStatus(); + } + + updateButtons(); + + mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileSecondLife::onAvatarNameCache, this, _1, _2)); } -/// Restore saved children (adding them back to the child list). -bool LLPanelProfile::ChildStack::pop() +void LLPanelProfileSecondLife::apply(LLAvatarData* data) { - if (mStack.size() == 0) - { - LL_WARNS() << "Empty stack" << LL_ENDL; - llassert(mStack.size() == 0); - return false; - } + if (getIsLoaded() && getSelfProfile()) + { + data->image_id = mSecondLifePic->getImageAssetID(); + data->about_text = mDescriptionEdit->getValue().asString(); + data->allow_publish = mShowInSearchCheckbox->getValue(); - view_list_t& top = mStack.back(); - for (view_list_t::const_iterator it = top.begin(); it != top.end(); ++it) - { - LLView* viewp = *it; - mParent->addChild(viewp); - } + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesUpdate(data); + } +} + +void LLPanelProfileSecondLife::updateData() +{ + LLUUID avatar_id = getAvatarId(); + if (!getIsLoading() && avatar_id.notNull() && !(getSelfProfile() && !getEmbedded())) + { + setIsLoading(); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarGroupsRequest(avatar_id); + } +} + +void LLPanelProfileSecondLife::processProperties(void* data, EAvatarProcessorType type) +{ - mStack.pop_back(); - dump(); - return true; + if (APT_PROPERTIES == type) + { + const LLAvatarData* avatar_data = static_cast<const LLAvatarData*>(data); + if(avatar_data && getAvatarId() == avatar_data->avatar_id) + { + processProfileProperties(avatar_data); + updateButtons(); + } + } + else if (APT_GROUPS == type) + { + LLAvatarGroups* avatar_groups = static_cast<LLAvatarGroups*>(data); + if(avatar_groups && getAvatarId() == avatar_groups->avatar_id) + { + processGroupProperties(avatar_groups); + } + } } -/// Temporarily add all saved children back. -void LLPanelProfile::ChildStack::preParentReshape() +void LLPanelProfileSecondLife::resetData() { - mSavedStack = mStack; - while(mStack.size() > 0) - { - pop(); - } + resetLoading(); + getChild<LLUICtrl>("complete_name")->setValue(LLStringUtil::null); + getChild<LLUICtrl>("register_date")->setValue(LLStringUtil::null); + getChild<LLUICtrl>("acc_status_text")->setValue(LLStringUtil::null); + getChild<LLUICtrl>("partner_text")->setValue(LLStringUtil::null); + + // Set default image and 1:1 dimensions for it + mSecondLifePic->setValue(mSecondLifePic->getDefaultImageAssetID()); + LLRect imageRect = mSecondLifePicLayout->getRect(); + mSecondLifePicLayout->reshape(imageRect.getHeight(), imageRect.getHeight()); + + mDescriptionEdit->setValue(LLStringUtil::null); + mStatusText->setVisible(FALSE); + mCopyMenuButton->setVisible(FALSE); + mGroups.clear(); + mGroupList->setGroups(mGroups); } -/// Add the temporarily saved children back. -void LLPanelProfile::ChildStack::postParentReshape() +void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avatar_data) { - mStack = mSavedStack; - mSavedStack = stack_t(); + LLUUID avatar_id = getAvatarId(); + if (!LLAvatarActions::isFriend(avatar_id) && !getSelfProfile()) + { + // this is non-friend avatar. Status will be updated from LLAvatarPropertiesProcessor. + // in LLPanelProfileSecondLife::processOnlineStatus() - for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it) - { - const view_list_t& vlist = (*stack_it); - for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it) - { - LLView* viewp = *list_it; - LL_DEBUGS() << "removing " << viewp->getName() << LL_ENDL; - mParent->removeChild(viewp); - } - } + // subscribe observer to get online status. Request will be sent by LLPanelProfileSecondLife itself. + // do not subscribe for friend avatar because online status can be wrong overridden + // via LLAvatarData::flags if Preferences: "Only Friends & Groups can see when I am online" is set. + processOnlineStatus(avatar_data->flags & AVATAR_ONLINE); + } + + fillCommonData(avatar_data); + + fillPartnerData(avatar_data); + + fillAccountStatus(avatar_data); } -void LLPanelProfile::ChildStack::dump() +void LLPanelProfileSecondLife::processGroupProperties(const LLAvatarGroups* avatar_groups) { - unsigned lvl = 0; - LL_DEBUGS() << "child stack dump:" << LL_ENDL; - for (stack_t::const_iterator stack_it = mStack.begin(); stack_it != mStack.end(); ++stack_it, ++lvl) - { - std::ostringstream dbg_line; - dbg_line << "lvl #" << lvl << ":"; - const view_list_t& vlist = (*stack_it); - for (view_list_t::const_iterator list_it = vlist.begin(); list_it != vlist.end(); ++list_it) - { - dbg_line << " " << (*list_it)->getName(); - } - LL_DEBUGS() << dbg_line.str() << LL_ENDL; - } + //KC: the group_list ctrl can handle all this for us on our own profile + if (getSelfProfile() && !getEmbedded()) + { + return; + } + + // *NOTE dzaporozhan + // Group properties may arrive in two callbacks, we need to save them across + // different calls. We can't do that in textbox as textbox may change the text. + + LLAvatarGroups::group_list_t::const_iterator it = avatar_groups->group_list.begin(); + const LLAvatarGroups::group_list_t::const_iterator it_end = avatar_groups->group_list.end(); + + for (; it_end != it; ++it) + { + LLAvatarGroups::LLGroupData group_data = *it; + mGroups[group_data.group_name] = group_data.group_id; + } + + mGroupList->setGroups(mGroups); } -//-- LLPanelProfile::ChildStack ends ------------------------------------------ +void LLPanelProfileSecondLife::openGroupProfile() +{ + LLUUID group_id = mGroupList->getSelectedUUID(); + LLGroupActions::show(group_id); +} -LLPanelProfile::LLPanelProfile() - : LLPanel() - , mAvatarId(LLUUID::null) +void LLPanelProfileSecondLife::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) { - mChildStack.setParent(this); + mAvatarNameCacheConnection.disconnect(); + + getChild<LLUICtrl>("complete_name")->setValue( av_name.getCompleteName() ); + mCopyMenuButton->setVisible(TRUE); } -BOOL LLPanelProfile::postBuild() +void LLPanelProfileSecondLife::fillCommonData(const LLAvatarData* avatar_data) { - LLPanelPicks* panel_picks = findChild<LLPanelPicks>(PANEL_PICKS); - panel_picks->setProfilePanel(this); + // Refresh avatar id in cache with new info to prevent re-requests + // and to make sure icons in text will be up to date + LLAvatarIconIDCache::getInstance()->add(avatar_data->avatar_id, avatar_data->image_id); + + LLStringUtil::format_map_t args; + { + std::string birth_date = LLTrans::getString("AvatarBirthDateFormat"); + LLStringUtil::format(birth_date, LLSD().with("datetime", (S32) avatar_data->born_on.secondsSinceEpoch())); + args["[REG_DATE]"] = birth_date; + } - getTabContainer()[PANEL_PICKS] = panel_picks; + args["[AGE]"] = LLDateUtil::ageFromDate( avatar_data->born_on, LLDate::now()); + std::string register_date = getString("RegisterDateFormat", args); + getChild<LLUICtrl>("register_date")->setValue(register_date ); + mDescriptionEdit->setValue(avatar_data->about_text); + mSecondLifePic->setValue(avatar_data->image_id); - return TRUE; + //Don't bother about boost level, picker will set it + LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(avatar_data->image_id); + if (imagep->getFullHeight()) + { + onImageLoaded(true, imagep); + } + else + { + imagep->setLoadedCallback(onImageLoaded, + MAX_DISCARD_LEVEL, + FALSE, + FALSE, + new LLHandle<LLPanel>(getHandle()), + NULL, + FALSE); + } + + if (getSelfProfile()) + { + mShowInSearchCheckbox->setValue((BOOL)(avatar_data->flags & AVATAR_ALLOW_PUBLISH)); + } } -// virtual -void LLPanelProfile::reshape(S32 width, S32 height, BOOL called_from_parent) +void LLPanelProfileSecondLife::fillPartnerData(const LLAvatarData* avatar_data) { - // Temporarily add saved children back and reshape them. - mChildStack.preParentReshape(); - LLPanel::reshape(width, height, called_from_parent); - mChildStack.postParentReshape(); + LLTextEditor* partner_text = getChild<LLTextEditor>("partner_text"); + if (avatar_data->partner_id.notNull()) + { + partner_text->setText(LLSLURL("agent", avatar_data->partner_id, "inspect").getSLURLString()); + } + else + { + partner_text->setText(getString("no_partner_text")); + } } -void LLPanelProfile::onOpen(const LLSD& key) +void LLPanelProfileSecondLife::fillAccountStatus(const LLAvatarData* avatar_data) { - getTabContainer()[PANEL_PICKS]->onOpen(getAvatarId()); + LLStringUtil::format_map_t args; + args["[ACCTTYPE]"] = LLAvatarPropertiesProcessor::accountType(avatar_data); + args["[PAYMENTINFO]"] = LLAvatarPropertiesProcessor::paymentInfo(avatar_data); - // support commands to open further pieces of UI - if (key.has("show_tab_panel")) - { - std::string panel = key["show_tab_panel"].asString(); - if (panel == "create_classified") - { - LLPanelPicks* picks = dynamic_cast<LLPanelPicks *>(getTabContainer()[PANEL_PICKS]); - if (picks) - { - picks->createNewClassified(); - } - } - else if (panel == "classified_details") - { - LLPanelPicks* picks = dynamic_cast<LLPanelPicks *>(getTabContainer()[PANEL_PICKS]); - if (picks) - { - LLSD params = key; - params.erase("show_tab_panel"); - params.erase("open_tab_name"); - picks->openClassifiedInfo(params); - } - } - else if (panel == "edit_classified") - { - LLPanelPicks* picks = dynamic_cast<LLPanelPicks *>(getTabContainer()[PANEL_PICKS]); - if (picks) - { - LLSD params = key; - params.erase("show_tab_panel"); - params.erase("open_tab_name"); - picks->openClassifiedEdit(params); - } - } - else if (panel == "create_pick") - { - LLPanelPicks* picks = dynamic_cast<LLPanelPicks *>(getTabContainer()[PANEL_PICKS]); - if (picks) - { - picks->createNewPick(); - } - } - else if (panel == "edit_pick") - { - LLPanelPicks* picks = dynamic_cast<LLPanelPicks *>(getTabContainer()[PANEL_PICKS]); - if (picks) - { - LLSD params = key; - params.erase("show_tab_panel"); - params.erase("open_tab_name"); - picks->openPickEdit(params); - } - } - } + std::string caption_text = getString("CaptionTextAcctInfo", args); + getChild<LLUICtrl>("acc_status_text")->setValue(caption_text); } -void LLPanelProfile::onTabSelected(const LLSD& param) +void LLPanelProfileSecondLife::onMapButtonClick() { - std::string tab_name = param.asString(); - if (NULL != getTabContainer()[tab_name]) - { - getTabContainer()[tab_name]->onOpen(getAvatarId()); - } + LLAvatarActions::showOnMap(getAvatarId()); +} + +void LLPanelProfileSecondLife::pay() +{ + LLAvatarActions::pay(getAvatarId()); +} + +void LLPanelProfileSecondLife::onClickToggleBlock() +{ + bool blocked = LLAvatarActions::toggleBlock(getAvatarId()); + + updateButtons(); + // we are hiding one button and showing another, set focus + if (blocked) + { + mUnblockButton->setFocus(true); + } + else + { + mBlockButton->setFocus(true); + } +} + +void LLPanelProfileSecondLife::onAddFriendButtonClick() +{ + LLAvatarActions::requestFriendshipDialog(getAvatarId()); +} + +void LLPanelProfileSecondLife::onIMButtonClick() +{ + LLAvatarActions::startIM(getAvatarId()); +} + +void LLPanelProfileSecondLife::onTeleportButtonClick() +{ + LLAvatarActions::offerTeleport(getAvatarId()); +} + +void LLPanelProfileSecondLife::onGroupInvite() +{ + LLAvatarActions::inviteToGroup(getAvatarId()); +} + +void LLPanelProfileSecondLife::onImageLoaded(BOOL success, LLViewerFetchedTexture *imagep) +{ + LLRect imageRect = mSecondLifePicLayout->getRect(); + if (!success || imagep->getFullWidth() == imagep->getFullHeight()) + { + mSecondLifePicLayout->reshape(imageRect.getHeight(), imageRect.getHeight()); + } + else + { + // assume 3:4, for sake of firestorm + mSecondLifePicLayout->reshape(imageRect.getHeight() * 4 / 3, imageRect.getHeight()); + } +} + +//static +void LLPanelProfileSecondLife::onImageLoaded(BOOL success, + LLViewerFetchedTexture *src_vi, + LLImageRaw* src, + LLImageRaw* aux_src, + S32 discard_level, + BOOL final, + void* userdata) +{ + if (!userdata) return; + + LLHandle<LLPanel>* handle = (LLHandle<LLPanel>*)userdata; + + if (!handle->isDead()) + { + LLPanelProfileSecondLife* panel = static_cast<LLPanelProfileSecondLife*>(handle->get()); + if (panel) + { + panel->onImageLoaded(success, src_vi); + } + } + + if (final || !success) + { + delete handle; + } +} + +// virtual, called by LLAvatarTracker +void LLPanelProfileSecondLife::changed(U32 mask) +{ + updateOnlineStatus(); + updateButtons(); +} + +// virtual, called by LLVoiceClient +void LLPanelProfileSecondLife::onChange(EStatusType status, const std::string &channelURI, bool proximal) +{ + if(status == STATUS_JOINING || status == STATUS_LEFT_CHANNEL) + { + return; + } + + mVoiceStatus = LLAvatarActions::canCall() && (LLAvatarActions::isFriend(getAvatarId()) ? LLAvatarTracker::instance().isBuddyOnline(getAvatarId()) : TRUE); +} + +void LLPanelProfileSecondLife::setAvatarId(const LLUUID& avatar_id) +{ + if (avatar_id.notNull()) + { + if (getAvatarId().notNull()) + { + LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); + } + + LLPanelProfileTab::setAvatarId(avatar_id); + + if (LLAvatarActions::isFriend(getAvatarId())) + { + LLAvatarTracker::instance().addParticularFriendObserver(getAvatarId(), this); + } + } +} + +bool LLPanelProfileSecondLife::isGrantedToSeeOnlineStatus() +{ + // set text box visible to show online status for non-friends who has not set in Preferences + // "Only Friends & Groups can see when I am online" + if (!LLAvatarActions::isFriend(getAvatarId())) + { + return true; + } + + // *NOTE: GRANT_ONLINE_STATUS is always set to false while changing any other status. + // When avatar disallow me to see her online status processOfflineNotification Message is received by the viewer + // see comments for ChangeUserRights template message. EXT-453. + // If GRANT_ONLINE_STATUS flag is changed it will be applied when viewer restarts. EXT-3880 + const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); + return relationship->isRightGrantedFrom(LLRelationship::GRANT_ONLINE_STATUS); +} + +// method was disabled according to EXT-2022. Re-enabled & improved according to EXT-3880 +void LLPanelProfileSecondLife::updateOnlineStatus() +{ + if (!LLAvatarActions::isFriend(getAvatarId())) return; + // For friend let check if he allowed me to see his status + const LLRelationship* relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); + bool online = relationship->isOnline(); + processOnlineStatus(online); +} + +void LLPanelProfileSecondLife::processOnlineStatus(bool online) +{ + mStatusText->setVisible(isGrantedToSeeOnlineStatus()); + + std::string status = getString(online ? "status_online" : "status_offline"); + + mStatusText->setValue(status); + mStatusText->setColor(online ? + LLUIColorTable::instance().getColor("StatusUserOnline") : + LLUIColorTable::instance().getColor("StatusUserOffline")); +} + +void LLPanelProfileSecondLife::updateButtons() +{ + LLPanelProfileTab::updateButtons(); + + if (getSelfProfile() && !getEmbedded()) + { + mShowInSearchCheckbox->setVisible(TRUE); + mShowInSearchCheckbox->setEnabled(TRUE); + mDescriptionEdit->setEnabled(TRUE); + } + + if (!getSelfProfile()) + { + LLUUID av_id = getAvatarId(); + bool is_buddy_online = LLAvatarTracker::instance().isBuddyOnline(getAvatarId()); + + if (LLAvatarActions::isFriend(av_id)) + { + mTeleportButton->setEnabled(is_buddy_online); + //Disable "Add Friend" button for friends. + mAddFriendButton->setEnabled(false); + } + else + { + mTeleportButton->setEnabled(true); + mAddFriendButton->setEnabled(true); + } + + bool enable_map_btn = (is_buddy_online && is_agent_mappable(av_id)) || gAgent.isGodlike(); + mShowOnMapButton->setEnabled(enable_map_btn); + + bool enable_block_btn = LLAvatarActions::canBlock(av_id) && !LLAvatarActions::isBlocked(av_id); + mBlockButton->setVisible(enable_block_btn); + + bool enable_unblock_btn = LLAvatarActions::isBlocked(av_id); + mUnblockButton->setVisible(enable_unblock_btn); + } +} + +void LLPanelProfileSecondLife::onClickSetName() +{ + LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileSecondLife::onAvatarNameCacheSetName, this, _1, _2)); + + LLFirstUse::setDisplayName(false); +} + +void LLPanelProfileSecondLife::onCommitTexture() +{ + LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(mSecondLifePic->getImageAssetID()); + if (imagep->getFullHeight()) + { + onImageLoaded(true, imagep); + } + else + { + imagep->setLoadedCallback(onImageLoaded, + MAX_DISCARD_LEVEL, + FALSE, + FALSE, + new LLHandle<LLPanel>(getHandle()), + NULL, + FALSE); + } +} + +void LLPanelProfileSecondLife::onCommitMenu(const LLSD& userdata) +{ + LLAvatarName av_name; + if (!LLAvatarNameCache::get(getAvatarId(), &av_name)) + { + // shouldn't happen, button(menu) is supposed to be invisible while name is fetching + LL_WARNS() << "Failed to get agent data" << LL_ENDL; + return; + } + + const std::string item_name = userdata.asString(); + LLWString wstr; + if (item_name == "display") + { + wstr = utf8str_to_wstring(av_name.getDisplayName(true)); + } + else if (item_name == "name") + { + wstr = utf8str_to_wstring(av_name.getAccountName()); + } + else if (item_name == "id") + { + wstr = utf8str_to_wstring(getAvatarId().asString()); + } + LLClipboard::instance().copyToClipboard(wstr, 0, wstr.size()); +} + +void LLPanelProfileSecondLife::onAvatarNameCacheSetName(const LLUUID& agent_id, const LLAvatarName& av_name) +{ + if (av_name.getDisplayName().empty()) + { + // something is wrong, tell user to try again later + LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); + return; + } + + LL_INFOS("LegacyProfile") << "name-change now " << LLDate::now() << " next_update " + << LLDate(av_name.mNextUpdate) << LL_ENDL; + F64 now_secs = LLDate::now().secondsSinceEpoch(); + + if (now_secs < av_name.mNextUpdate) + { + // if the update time is more than a year in the future, it means updates have been blocked + // show a more general message + static const S32 YEAR = 60*60*24*365; + if (now_secs + YEAR < av_name.mNextUpdate) + { + LLNotificationsUtil::add("SetDisplayNameBlocked"); + return; + } + } + + LLFloaterReg::showInstance("display_name"); +} + +////////////////////////////////////////////////////////////////////////// +// LLPanelProfileWeb + +LLPanelProfileWeb::LLPanelProfileWeb() + : LLPanelProfileTab() + , mWebBrowser(NULL) + , mAvatarNameCacheConnection() +{ +} + +LLPanelProfileWeb::~LLPanelProfileWeb() +{ + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } +} + +void LLPanelProfileWeb::onOpen(const LLSD& key) +{ + LLPanelProfileTab::onOpen(key); + + resetData(); + + mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileWeb::onAvatarNameCache, this, _1, _2)); +} + +BOOL LLPanelProfileWeb::postBuild() +{ + mWebBrowser = getChild<LLMediaCtrl>("profile_html"); + mWebBrowser->addObserver(this); + mWebBrowser->setHomePageUrl("about:blank"); + + return TRUE; +} + +void LLPanelProfileWeb::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_PROPERTIES == type) + { + const LLAvatarData* avatar_data = static_cast<const LLAvatarData*>(data); + if (avatar_data && getAvatarId() == avatar_data->avatar_id) + { + updateButtons(); + } + } +} + +void LLPanelProfileWeb::resetData() +{ + mWebBrowser->navigateHome(); +} + +void LLPanelProfileWeb::apply(LLAvatarData* data) +{ + +} + +void LLPanelProfileWeb::updateData() +{ + LLUUID avatar_id = getAvatarId(); + if (!getIsLoading() && avatar_id.notNull() && !mURLWebProfile.empty()) + { + setIsLoading(); + + mWebBrowser->setVisible(TRUE); + mPerformanceTimer.start(); + mWebBrowser->navigateTo(mURLWebProfile, HTTP_CONTENT_TEXT_HTML); + } +} + +void LLPanelProfileWeb::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) +{ + mAvatarNameCacheConnection.disconnect(); + + std::string username = av_name.getAccountName(); + if (username.empty()) + { + username = LLCacheName::buildUsername(av_name.getDisplayName()); + } + else + { + LLStringUtil::replaceChar(username, ' ', '.'); + } + + mURLWebProfile = getProfileURL(username, true); + if (mURLWebProfile.empty()) + { + return; + } + + //if the tab was opened before name was resolved, load the panel now + updateData(); +} + +void LLPanelProfileWeb::onCommitLoad(LLUICtrl* ctrl) +{ + if (!mURLHome.empty()) + { + LLSD::String valstr = ctrl->getValue().asString(); + if (valstr.empty()) + { + mWebBrowser->setVisible(TRUE); + mPerformanceTimer.start(); + mWebBrowser->navigateTo( mURLHome, HTTP_CONTENT_TEXT_HTML ); + } + else if (valstr == "popout") + { + // open in viewer's browser, new window + LLWeb::loadURLInternal(mURLHome); + } + else if (valstr == "external") + { + // open in external browser + LLWeb::loadURLExternal(mURLHome); + } + } +} + +void LLPanelProfileWeb::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + switch(event) + { + case MEDIA_EVENT_STATUS_TEXT_CHANGED: + childSetValue("status_text", LLSD( self->getStatusText() ) ); + break; + + case MEDIA_EVENT_NAVIGATE_BEGIN: + { + if (mFirstNavigate) + { + mFirstNavigate = false; + } + else + { + mPerformanceTimer.start(); + } + } + break; + + case MEDIA_EVENT_NAVIGATE_COMPLETE: + { + LLStringUtil::format_map_t args; + args["[TIME]"] = llformat("%.2f", mPerformanceTimer.getElapsedTimeF32()); + childSetValue("status_text", LLSD( getString("LoadTime", args)) ); + } + break; + + default: + // Having a default case makes the compiler happy. + break; + } +} + +void LLPanelProfileWeb::updateButtons() +{ + LLPanelProfileTab::updateButtons(); +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +static const S32 WANT_CHECKS = 8; +static const S32 SKILL_CHECKS = 6; + +LLPanelProfileInterests::LLPanelProfileInterests() + : LLPanelProfileTab() +{ +} + +LLPanelProfileInterests::~LLPanelProfileInterests() +{ +} + +void LLPanelProfileInterests::onOpen(const LLSD& key) +{ + LLPanelProfileTab::onOpen(key); + + resetData(); +} + +BOOL LLPanelProfileInterests::postBuild() +{ + mWantToEditor = getChild<LLLineEditor>("want_to_edit"); + mSkillsEditor = getChild<LLLineEditor>("skills_edit"); + mLanguagesEditor = getChild<LLLineEditor>("languages_edit"); + + for (S32 i = 0; i < WANT_CHECKS; ++i) + { + std::string check_name = llformat("chk%d", i); + mWantChecks[i] = getChild<LLCheckBoxCtrl>(check_name); + } + + for (S32 i = 0; i < SKILL_CHECKS; ++i) + { + std::string check_name = llformat("schk%d", i); + mSkillChecks[i] = getChild<LLCheckBoxCtrl>(check_name); + } + + return TRUE; +} + + +void LLPanelProfileInterests::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_INTERESTS_INFO == type) + { + const LLInterestsData* interests_data = static_cast<const LLInterestsData*>(data); + if (interests_data && getAvatarId() == interests_data->avatar_id) + { + for (S32 i = 0; i < WANT_CHECKS; ++i) + { + if (interests_data->want_to_mask & (1<<i)) + { + mWantChecks[i]->setValue(TRUE); + } + else + { + mWantChecks[i]->setValue(FALSE); + } + } + + for (S32 i = 0; i < SKILL_CHECKS; ++i) + { + if (interests_data->skills_mask & (1<<i)) + { + mSkillChecks[i]->setValue(TRUE); + } + else + { + mSkillChecks[i]->setValue(FALSE); + } + } + + mWantToEditor->setText(interests_data->want_to_text); + mSkillsEditor->setText(interests_data->skills_text); + mLanguagesEditor->setText(interests_data->languages_text); + + updateButtons(); + } + } +} + +void LLPanelProfileInterests::resetData() +{ + mWantToEditor->setValue(LLStringUtil::null); + mSkillsEditor->setValue(LLStringUtil::null); + mLanguagesEditor->setValue(LLStringUtil::null); + + for (S32 i = 0; i < WANT_CHECKS; ++i) + { + mWantChecks[i]->setValue(FALSE); + } + + for (S32 i = 0; i < SKILL_CHECKS; ++i) + { + mSkillChecks[i]->setValue(FALSE); + } +} + +void LLPanelProfileInterests::apply() +{ + if (getIsLoaded() && getSelfProfile()) + { + LLInterestsData interests_data = LLInterestsData(); + + interests_data.want_to_mask = 0; + for (S32 i = 0; i < WANT_CHECKS; ++i) + { + if (mWantChecks[i]->getValue().asBoolean()) + { + interests_data.want_to_mask |= (1 << i); + } + } + + interests_data.skills_mask = 0; + for (S32 i = 0; i < SKILL_CHECKS; ++i) + { + if (mSkillChecks[i]->getValue().asBoolean()) + { + interests_data.skills_mask |= (1 << i); + } + } + + interests_data.want_to_text = mWantToEditor->getText(); + interests_data.skills_text = mSkillsEditor->getText(); + interests_data.languages_text = mLanguagesEditor->getText(); + + LLAvatarPropertiesProcessor::getInstance()->sendInterestsInfoUpdate(&interests_data); + } + +} + +void LLPanelProfileInterests::updateButtons() +{ + LLPanelProfileTab::updateButtons(); + + if (getSelfProfile() && !getEmbedded()) + { + mWantToEditor->setEnabled(TRUE); + mSkillsEditor->setEnabled(TRUE); + mLanguagesEditor->setEnabled(TRUE); + + for (S32 i = 0; i < WANT_CHECKS; ++i) + { + mWantChecks[i]->setEnabled(TRUE); + } + + for (S32 i = 0; i < SKILL_CHECKS; ++i) + { + mSkillChecks[i]->setEnabled(TRUE); + } + } +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLPanelProfileFirstLife::LLPanelProfileFirstLife() + : LLPanelProfileTab(), + mIsEditing(false) +{ +} + +LLPanelProfileFirstLife::~LLPanelProfileFirstLife() +{ +} + +BOOL LLPanelProfileFirstLife::postBuild() +{ + mDescriptionEdit = getChild<LLTextEditor>("fl_description_edit"); + mPicture = getChild<LLTextureCtrl>("real_world_pic"); + + mDescriptionEdit->setFocusReceivedCallback(boost::bind(&LLPanelProfileFirstLife::onDescriptionFocusReceived, this)); + + return TRUE; +} + +void LLPanelProfileFirstLife::onOpen(const LLSD& key) +{ + LLPanelProfileTab::onOpen(key); + + resetData(); +} + + +void LLPanelProfileFirstLife::onDescriptionFocusReceived() +{ + if (!mIsEditing && getSelfProfile()) + { + mIsEditing = true; + mDescriptionEdit->setParseHTML(false); + mDescriptionEdit->setText(mCurrentDescription); + } +} + +void LLPanelProfileFirstLife::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_PROPERTIES == type) + { + const LLAvatarData* avatar_data = static_cast<const LLAvatarData*>(data); + if (avatar_data && getAvatarId() == avatar_data->avatar_id) + { + mCurrentDescription = avatar_data->fl_about_text; + mDescriptionEdit->setValue(mCurrentDescription); + mPicture->setValue(avatar_data->fl_image_id); + updateButtons(); + } + } +} + +void LLPanelProfileFirstLife::resetData() +{ + mDescriptionEdit->setValue(LLStringUtil::null); + mPicture->setValue(mPicture->getDefaultImageAssetID()); +} + +void LLPanelProfileFirstLife::apply(LLAvatarData* data) +{ + data->fl_image_id = mPicture->getImageAssetID(); + data->fl_about_text = mDescriptionEdit->getValue().asString(); } -void LLPanelProfile::openPanel(LLPanel* panel, const LLSD& params) +void LLPanelProfileFirstLife::updateButtons() { - // Hide currently visible panel (STORM-690). - mChildStack.push(); + LLPanelProfileTab::updateButtons(); - // Add the panel or bring it to front. - if (panel->getParent() != this) + if (getSelfProfile() && !getEmbedded()) + { + mDescriptionEdit->setEnabled(TRUE); + mPicture->setEnabled(TRUE); + } +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLPanelProfileNotes::LLPanelProfileNotes() +: LLPanelProfileTab() +, mAvatarNameCacheConnection() +{ + +} + +LLPanelProfileNotes::~LLPanelProfileNotes() +{ + if (getAvatarId().notNull()) + { + LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); + } + + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } +} + +void LLPanelProfileNotes::updateData() +{ + LLUUID avatar_id = getAvatarId(); + if (!getIsLoading() && avatar_id.notNull()) + { + setIsLoading(); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarNotesRequest(avatar_id); + } +} + +BOOL LLPanelProfileNotes::postBuild() +{ + mOnlineStatus = getChild<LLCheckBoxCtrl>("status_check"); + mMapRights = getChild<LLCheckBoxCtrl>("map_check"); + mEditObjectRights = getChild<LLCheckBoxCtrl>("objects_check"); + mNotesEditor = getChild<LLTextEditor>("notes_edit"); + mCharacterLimitWarning = getChild<LLTextBox>("character_limit_warning"); + + mEditObjectRights->setCommitCallback(boost::bind(&LLPanelProfileNotes::onCommitRights, this)); + + mNotesEditor->setCommitCallback(boost::bind(&LLPanelProfileNotes::onCommitNotes,this)); + + return TRUE; +} + +void LLPanelProfileNotes::onOpen(const LLSD& key) +{ + LLPanelProfileTab::onOpen(key); + + resetData(); + + fillRightsData(); + + mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileNotes::onAvatarNameCache, this, _1, _2)); +} + +void LLPanelProfileNotes::apply() +{ + onCommitNotes(); + applyRights(); +} + +void LLPanelProfileNotes::fillRightsData() +{ + mOnlineStatus->setValue(FALSE); + mMapRights->setValue(FALSE); + mEditObjectRights->setValue(FALSE); + + const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); + // If true - we are viewing friend's profile, enable check boxes and set values. + if(relation) + { + S32 rights = relation->getRightsGrantedTo(); + + mOnlineStatus->setValue(LLRelationship::GRANT_ONLINE_STATUS & rights ? TRUE : FALSE); + mMapRights->setValue(LLRelationship::GRANT_MAP_LOCATION & rights ? TRUE : FALSE); + mEditObjectRights->setValue(LLRelationship::GRANT_MODIFY_OBJECTS & rights ? TRUE : FALSE); + } + + enableCheckboxes(NULL != relation); +} + +void LLPanelProfileNotes::onCommitNotes() +{ + if (getIsLoaded()) + { + std::string notes = mNotesEditor->getValue().asString(); + LLAvatarPropertiesProcessor::getInstance()->sendNotes(getAvatarId(),notes); + } +} + +void LLPanelProfileNotes::rightsConfirmationCallback(const LLSD& notification, + const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) + { + mEditObjectRights->setValue(mEditObjectRights->getValue().asBoolean() ? FALSE : TRUE); + } +} + +void LLPanelProfileNotes::confirmModifyRights(bool grant) +{ + LLSD args; + args["NAME"] = LLSLURL("agent", getAvatarId(), "completename").getSLURLString(); + + + LLNotificationsUtil::add(grant ? "GrantModifyRights" : "RevokeModifyRights", args, LLSD(), + boost::bind(&LLPanelProfileNotes::rightsConfirmationCallback, this, _1, _2)); + +} + +void LLPanelProfileNotes::onCommitRights() +{ + const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); + + if (!buddy_relationship) { - addChild(panel); + LL_WARNS("LegacyProfile") << "Trying to modify rights for non-friend avatar. Skipped." << LL_ENDL; + return; } - else + + bool allow_modify_objects = mEditObjectRights->getValue().asBoolean(); + + // if modify objects checkbox clicked + if (buddy_relationship->isRightGrantedTo( + LLRelationship::GRANT_MODIFY_OBJECTS) != allow_modify_objects) { - sendChildToFront(panel); + confirmModifyRights(allow_modify_objects); } +} + +void LLPanelProfileNotes::applyRights() +{ + const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); - panel->setVisible(TRUE); - panel->setFocus(TRUE); // prevent losing focus by the floater - panel->onOpen(params); + if (!buddy_relationship) + { + // Lets have a warning log message instead of having a crash. EXT-4947. + LL_WARNS("LegacyProfile") << "Trying to modify rights for non-friend avatar. Skipped." << LL_ENDL; + return; + } - LLRect new_rect = getRect(); - panel->reshape(new_rect.getWidth(), new_rect.getHeight()); - new_rect.setLeftTopAndSize(0, new_rect.getHeight(), new_rect.getWidth(), new_rect.getHeight()); - panel->setRect(new_rect); + S32 rights = 0; + + if (mOnlineStatus->getValue().asBoolean()) + { + rights |= LLRelationship::GRANT_ONLINE_STATUS; + } + if (mMapRights->getValue().asBoolean()) + { + rights |= LLRelationship::GRANT_MAP_LOCATION; + } + if (mEditObjectRights->getValue().asBoolean()) + { + rights |= LLRelationship::GRANT_MODIFY_OBJECTS; + } + + LLAvatarPropertiesProcessor::getInstance()->sendFriendRights(getAvatarId(), rights); } -void LLPanelProfile::closePanel(LLPanel* panel) +void LLPanelProfileNotes::updateWarning() { - panel->setVisible(FALSE); + mCharacterLimitWarning->setText(std::string()); - if (panel->getParent() == this) - { - removeChild(panel); + std::string str = getString("header_symbol_limit"); + mCharacterLimitWarning->appendText(str, false, LLStyle::Params().color(LLColor4::yellow)); + mCharacterLimitWarning->appendText(" ", false, LLStyle::Params()); - // Make the underlying panel visible. - mChildStack.pop(); + LLStringUtil::format_map_t args; + if (!mURLWebProfile.empty()) + { + args["[PROFILE_URL]"] = mURLWebProfile; + } + else + { + args["[PROFILE_URL]"] = getProfileURL(getAvatarId().asString()); + } + str = getString("body_symbol_limit", args); + mCharacterLimitWarning->appendText(str, false, LLStyle::Params()); +} - // Prevent losing focus by the floater - const child_list_t* child_list = getChildList(); - if (child_list->size() > 0) - { - child_list->front()->setFocus(TRUE); - } - else - { - LL_WARNS() << "No underlying panel to focus." << LL_ENDL; - } - } +void LLPanelProfileNotes::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_NOTES == type) + { + LLAvatarNotes* avatar_notes = static_cast<LLAvatarNotes*>(data); + if (avatar_notes && getAvatarId() == avatar_notes->target_id) + { + mNotesEditor->setValue(avatar_notes->notes); + mNotesEditor->setEnabled(TRUE); + updateButtons(); + + if (avatar_notes->notes.size() > 1000) + { + mCharacterLimitWarning->setVisible(TRUE); + updateWarning(); + } + else + { + mCharacterLimitWarning->setVisible(FALSE); + } + + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); + } + } } -S32 LLPanelProfile::notifyParent(const LLSD& info) +void LLPanelProfileNotes::resetData() { - std::string action = info["action"]; - // lets update Picks list after Pick was saved - if("save_new_pick" == action) - { - onOpen(info); - return 1; - } + resetLoading(); + mNotesEditor->setValue(LLStringUtil::null); + mOnlineStatus->setValue(FALSE); + mMapRights->setValue(FALSE); + mEditObjectRights->setValue(FALSE); + mCharacterLimitWarning->setVisible(FALSE); + + mURLWebProfile.clear(); +} + +void LLPanelProfileNotes::enableCheckboxes(bool enable) +{ + mOnlineStatus->setEnabled(enable); + mMapRights->setEnabled(enable); + mEditObjectRights->setEnabled(enable); +} + +// virtual, called by LLAvatarTracker +void LLPanelProfileNotes::changed(U32 mask) +{ + // update rights to avoid have checkboxes enabled when friendship is terminated. EXT-4947. + fillRightsData(); +} + +void LLPanelProfileNotes::setAvatarId(const LLUUID& avatar_id) +{ + if (avatar_id.notNull()) + { + if (getAvatarId().notNull()) + { + LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); + } + LLPanelProfileTab::setAvatarId(avatar_id); + LLAvatarTracker::instance().addParticularFriendObserver(getAvatarId(), this); + } +} + +void LLPanelProfileNotes::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) +{ + mAvatarNameCacheConnection.disconnect(); + + std::string username = av_name.getAccountName(); + if (username.empty()) + { + username = LLCacheName::buildUsername(av_name.getDisplayName()); + } + else + { + LLStringUtil::replaceChar(username, ' ', '.'); + } - return LLPanel::notifyParent(info); + mURLWebProfile = getProfileURL(username, false); + + if (mCharacterLimitWarning->getVisible()) + { + updateWarning(); + } } + + +////////////////////////////////////////////////////////////////////////// +// LLPanelProfile + +LLPanelProfile::LLPanelProfile() + : LLPanelProfileTab() +{ +} + +LLPanelProfile::~LLPanelProfile() +{ +} + +BOOL LLPanelProfile::postBuild() +{ + return TRUE; +} + +void LLPanelProfile::processProperties(void* data, EAvatarProcessorType type) +{ + //*TODO: figure out what this does + mTabContainer->setCommitCallback(boost::bind(&LLPanelProfile::onTabChange, this)); + + // Load data on currently opened tab as well + onTabChange(); +} + +void LLPanelProfile::onTabChange() +{ + LLPanelProfileTab* active_panel = dynamic_cast<LLPanelProfileTab*>(mTabContainer->getCurrentPanel()); + if (active_panel) + { + active_panel->updateData(); + } + updateBtnsVisibility(); +} + +void LLPanelProfile::updateBtnsVisibility() +{ + getChild<LLUICtrl>("ok_btn")->setVisible(((getSelfProfile() && !getEmbedded()) || isNotesTabSelected())); + getChild<LLUICtrl>("cancel_btn")->setVisible(((getSelfProfile() && !getEmbedded()) || isNotesTabSelected())); +} + +void LLPanelProfile::onOpen(const LLSD& key) +{ + LLUUID avatar_id = key["id"].asUUID(); + + // Don't reload the same profile + if (getAvatarId() == avatar_id) + { + return; + } + + LLPanelProfileTab::onOpen(avatar_id); + + mTabContainer = getChild<LLTabContainer>("panel_profile_tabs"); + mPanelSecondlife = findChild<LLPanelProfileSecondLife>(PANEL_SECONDLIFE); + mPanelWeb = findChild<LLPanelProfileWeb>(PANEL_WEB); + mPanelInterests = findChild<LLPanelProfileInterests>(PANEL_INTERESTS); + mPanelPicks = findChild<LLPanelProfilePicks>(PANEL_PICKS); + mPanelClassifieds = findChild<LLPanelProfileClassifieds>(PANEL_CLASSIFIEDS); + mPanelFirstlife = findChild<LLPanelProfileFirstLife>(PANEL_FIRSTLIFE); + mPanelNotes = findChild<LLPanelProfileNotes>(PANEL_NOTES); + + mPanelSecondlife->onOpen(avatar_id); + mPanelWeb->onOpen(avatar_id); + mPanelInterests->onOpen(avatar_id); + mPanelPicks->onOpen(avatar_id); + mPanelClassifieds->onOpen(avatar_id); + mPanelFirstlife->onOpen(avatar_id); + mPanelNotes->onOpen(avatar_id); + + mPanelSecondlife->setEmbedded(getEmbedded()); + mPanelWeb->setEmbedded(getEmbedded()); + mPanelInterests->setEmbedded(getEmbedded()); + mPanelPicks->setEmbedded(getEmbedded()); + mPanelClassifieds->setEmbedded(getEmbedded()); + mPanelFirstlife->setEmbedded(getEmbedded()); + mPanelNotes->setEmbedded(getEmbedded()); + + // Always request the base profile info + resetLoading(); + updateData(); + + updateBtnsVisibility(); + + // KC - Not handling pick and classified opening thru onOpen + // because this would make unique profile floaters per slurl + // and result in multiple profile floaters for the same avatar +} + +void LLPanelProfile::updateData() +{ + LLUUID avatar_id = getAvatarId(); + if (!getIsLoading() && avatar_id.notNull()) + { + setIsLoading(); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPropertiesRequest(avatar_id); + } +} + +void LLPanelProfile::apply() +{ + if (getSelfProfile()) + { + //KC - AvatarData is spread over 3 different panels + // collect data from the last 2 and give to the first to save + LLAvatarData data = LLAvatarData(); + data.avatar_id = gAgentID; + mPanelFirstlife->apply(&data); + mPanelWeb->apply(&data); + mPanelSecondlife->apply(&data); + + mPanelInterests->apply(); + mPanelPicks->apply(); + mPanelNotes->apply(); + mPanelClassifieds->apply(); + + //KC - Classifieds handles this itself + } + else + { + mPanelNotes->apply(); + } +} + +void LLPanelProfile::showPick(const LLUUID& pick_id) +{ + if (pick_id.notNull()) + { + mPanelPicks->selectPick(pick_id); + } + mTabContainer->selectTabPanel(mPanelPicks); +} + +bool LLPanelProfile::isPickTabSelected() +{ + return (mTabContainer->getCurrentPanel() == mPanelPicks); +} + +bool LLPanelProfile::isNotesTabSelected() +{ + return (mTabContainer->getCurrentPanel() == mPanelNotes); +} + +void LLPanelProfile::showClassified(const LLUUID& classified_id, bool edit) +{ + if (classified_id.notNull()) + { + mPanelClassifieds->selectClassified(classified_id, edit); + } + mTabContainer->selectTabPanel(mPanelClassifieds); +} + + + |