From 18d8be556c03bf6f7db175e51cce93ece37c45d2 Mon Sep 17 00:00:00 2001 From: Kadah_Coba Date: Tue, 12 Feb 2019 18:57:47 -0800 Subject: Backed out changeset: 25426acca617 Added back the display name floater --- indra/newview/CMakeLists.txt | 4 + indra/newview/llfloaterdisplayname.cpp | 217 +++++++++++++++++++++++++++++++++ indra/newview/llfloaterdisplayname.h | 38 ++++++ indra/newview/llpanelme.cpp | 1 + indra/newview/llviewerdisplayname.cpp | 211 ++++++++++++++++++++++++++++++++ indra/newview/llviewerdisplayname.h | 53 ++++++++ indra/newview/llviewerfloaterreg.cpp | 2 + 7 files changed, 526 insertions(+) create mode 100644 indra/newview/llfloaterdisplayname.cpp create mode 100644 indra/newview/llfloaterdisplayname.h create mode 100644 indra/newview/llviewerdisplayname.cpp create mode 100644 indra/newview/llviewerdisplayname.h (limited to 'indra') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ce8b662231..c1bbdeaf46 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -226,6 +226,7 @@ set(viewer_SOURCE_FILES llfloaterdeleteenvpreset.cpp llfloaterdeleteprefpreset.cpp llfloaterdestinations.cpp + llfloaterdisplayname.cpp llfloatereditdaycycle.cpp llfloatereditsky.cpp llfloatereditwater.cpp @@ -628,6 +629,7 @@ set(viewer_SOURCE_FILES llviewercontrol.cpp llviewercontrollistener.cpp llviewerdisplay.cpp + llviewerdisplayname.cpp llviewerfloaterreg.cpp llviewerfoldertype.cpp llviewergenericmessage.cpp @@ -850,6 +852,7 @@ set(viewer_HEADER_FILES llfloaterdeleteprefpreset.h llfloaterdeleteenvpreset.h llfloaterdestinations.h + llfloaterdisplayname.h llfloatereditdaycycle.h llfloatereditsky.h llfloatereditwater.h @@ -1247,6 +1250,7 @@ set(viewer_HEADER_FILES llviewercontrol.h llviewercontrollistener.h llviewerdisplay.h + llviewerdisplayname.h llviewerfloaterreg.h llviewerfoldertype.h llviewergenericmessage.h diff --git a/indra/newview/llfloaterdisplayname.cpp b/indra/newview/llfloaterdisplayname.cpp new file mode 100644 index 0000000000..596e8c0dbe --- /dev/null +++ b/indra/newview/llfloaterdisplayname.cpp @@ -0,0 +1,217 @@ +/** + * @file llfloaterdisplayname.cpp + * @author Leyla Farazha + * @brief Implementation of the LLFloaterDisplayName class. + * + * $LicenseInfo:firstyear=2002&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 "llfloaterreg.h" +#include "llfloater.h" + +#include "llnotificationsutil.h" +#include "llviewerdisplayname.h" + +#include "llnotifications.h" +#include "llfloaterdisplayname.h" +#include "llavatarnamecache.h" + +#include "llagent.h" + + +class LLFloaterDisplayName : public LLFloater +{ +public: + LLFloaterDisplayName(const LLSD& key); + virtual ~LLFloaterDisplayName() { } + /*virtual*/ BOOL postBuild(); + void onSave(); + void onReset(); + void onCancel(); + /*virtual*/ void onOpen(const LLSD& key); + +private: + + void onCacheSetName(bool success, + const std::string& reason, + const LLSD& content); +}; + +LLFloaterDisplayName::LLFloaterDisplayName(const LLSD& key) : + LLFloater(key) +{ +} + +void LLFloaterDisplayName::onOpen(const LLSD& key) +{ + getChild("display_name_editor")->clear(); + getChild("display_name_confirm")->clear(); + + LLAvatarName av_name; + LLAvatarNameCache::get(gAgent.getID(), &av_name); + + F64 now_secs = LLDate::now().secondsSinceEpoch(); + + if (now_secs < av_name.mNextUpdate) + { + // ...can't update until some time in the future + F64 next_update_local_secs = + av_name.mNextUpdate - LLStringOps::getLocalTimeOffset(); + LLDate next_update_local(next_update_local_secs); + // display as "July 18 12:17 PM" + std::string next_update_string = + next_update_local.toHTTPDateString("%B %d %I:%M %p"); + getChild("lockout_text")->setTextArg("[TIME]", next_update_string); + getChild("lockout_text")->setVisible(true); + getChild("save_btn")->setEnabled(false); + getChild("display_name_editor")->setEnabled(false); + getChild("display_name_confirm")->setEnabled(false); + getChild("cancel_btn")->setFocus(TRUE); + + } + else + { + getChild("lockout_text")->setVisible(false); + getChild("save_btn")->setEnabled(true); + getChild("display_name_editor")->setEnabled(true); + getChild("display_name_confirm")->setEnabled(true); + + } +} + +BOOL LLFloaterDisplayName::postBuild() +{ + getChild("reset_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onReset, this)); + getChild("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onCancel, this)); + getChild("save_btn")->setCommitCallback(boost::bind(&LLFloaterDisplayName::onSave, this)); + + center(); + + return TRUE; +} + +void LLFloaterDisplayName::onCacheSetName(bool success, + const std::string& reason, + const LLSD& content) +{ + if (success) + { + // Inform the user that the change took place, but will take a while + // to percolate. + LLSD args; + args["DISPLAY_NAME"] = content["display_name"]; + LLNotificationsUtil::add("SetDisplayNameSuccess", args); + return; + } + + // Request failed, notify the user + std::string error_tag = content["error_tag"].asString(); + LL_INFOS() << "set name failure error_tag " << error_tag << LL_ENDL; + + // We might have a localized string for this message + // error_args will usually be empty from the server. + if (!error_tag.empty() + && LLNotifications::getInstance()->templateExists(error_tag)) + { + LLNotificationsUtil::add(error_tag); + return; + } + + // The server error might have a localized message for us + std::string lang_code = LLUI::getLanguage(); + LLSD error_desc = content["error_description"]; + if (error_desc.has( lang_code )) + { + LLSD args; + args["MESSAGE"] = error_desc[lang_code].asString(); + LLNotificationsUtil::add("GenericAlert", args); + return; + } + + // No specific error, throw a generic one + LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); +} + +void LLFloaterDisplayName::onCancel() +{ + setVisible(false); +} + +void LLFloaterDisplayName::onReset() +{ + if (LLAvatarNameCache::hasNameLookupURL()) + { + LLViewerDisplayName::set("",boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3)); + } + else + { + LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); + } + + setVisible(false); +} + + +void LLFloaterDisplayName::onSave() +{ + std::string display_name_utf8 = getChild("display_name_editor")->getValue().asString(); + std::string display_name_confirm = getChild("display_name_confirm")->getValue().asString(); + + if (display_name_utf8.compare(display_name_confirm)) + { + LLNotificationsUtil::add("SetDisplayNameMismatch"); + return; + } + + const U32 DISPLAY_NAME_MAX_LENGTH = 31; // characters, not bytes + LLWString display_name_wstr = utf8string_to_wstring(display_name_utf8); + if (display_name_wstr.size() > DISPLAY_NAME_MAX_LENGTH) + { + LLSD args; + args["LENGTH"] = llformat("%d", DISPLAY_NAME_MAX_LENGTH); + LLNotificationsUtil::add("SetDisplayNameFailedLength", args); + return; + } + + if (LLAvatarNameCache::hasNameLookupURL()) + { + LLViewerDisplayName::set(display_name_utf8,boost::bind(&LLFloaterDisplayName::onCacheSetName, this, _1, _2, _3)); + } + else + { + LLNotificationsUtil::add("SetDisplayNameFailedGeneric"); + } + + setVisible(false); +} + + +////////////////////////////////////////////////////////////////////////////// +// LLInspectObjectUtil +////////////////////////////////////////////////////////////////////////////// +void LLFloaterDisplayNameUtil::registerFloater() +{ + LLFloaterReg::add("display_name", "floater_display_name.xml", + &LLFloaterReg::build); +} diff --git a/indra/newview/llfloaterdisplayname.h b/indra/newview/llfloaterdisplayname.h new file mode 100644 index 0000000000..a00bf56712 --- /dev/null +++ b/indra/newview/llfloaterdisplayname.h @@ -0,0 +1,38 @@ +/** + * @file llfloaterdisplayname.h + * + * $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$ + */ + +#ifndef LLFLOATERDISPLAYNAME_H +#define LLFLOATERDISPLAYNAME_H + + +namespace LLFloaterDisplayNameUtil +{ + // Register with LLFloaterReg + void registerFloater(); +} + + + +#endif diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp index 55e4ffff5e..cedd3025fc 100644 --- a/indra/newview/llpanelme.cpp +++ b/indra/newview/llpanelme.cpp @@ -37,6 +37,7 @@ #include "llfloaterreg.h" #include "llhints.h" #include "llviewercontrol.h" +#include "llviewerdisplayname.h" // Linden libraries #include "llavatarnamecache.h" // IDEVO diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp new file mode 100644 index 0000000000..e390e8776d --- /dev/null +++ b/indra/newview/llviewerdisplayname.cpp @@ -0,0 +1,211 @@ +/** + * @file llviewerdisplayname.cpp + * @brief Wrapper for display name functionality + * + * $LicenseInfo:firstyear=2010&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 "llviewerdisplayname.h" + +// viewer includes +#include "llagent.h" +#include "llviewerregion.h" +#include "llvoavatar.h" + +// library includes +#include "llavatarnamecache.h" +#include "llhttpclient.h" +#include "llhttpnode.h" +#include "llnotificationsutil.h" +#include "llui.h" // getLanguage() + +namespace LLViewerDisplayName +{ + // Fired when viewer receives server response to display name change + set_name_signal_t sSetDisplayNameSignal; + + // Fired when there is a change in the agent's name + name_changed_signal_t sNameChangedSignal; + + void addNameChangedCallback(const name_changed_signal_t::slot_type& cb) + { + sNameChangedSignal.connect(cb); + } + + void doNothing() { } +} + +class LLSetDisplayNameResponder : public LLHTTPClient::Responder +{ + LOG_CLASS(LLSetDisplayNameResponder); +private: + // only care about errors + /*virtual*/ void httpFailure() + { + LL_WARNS() << dumpResponse() << LL_ENDL; + LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD()); + LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); + } +}; + +void LLViewerDisplayName::set(const std::string& display_name, const set_name_slot_t& slot) +{ + // TODO: simple validation here + + LLViewerRegion* region = gAgent.getRegion(); + llassert(region); + std::string cap_url = region->getCapability("SetDisplayName"); + if (cap_url.empty()) + { + // this server does not support display names, report error + slot(false, "unsupported", LLSD()); + return; + } + + // People API can return localized error messages. Indicate our + // language preference via header. + LLSD headers; + headers[HTTP_OUT_HEADER_ACCEPT_LANGUAGE] = LLUI::getLanguage(); + + // People API requires both the old and new value to change a variable. + // Our display name will be in cache before the viewer's UI is available + // to request a change, so we can use direct lookup without callback. + LLAvatarName av_name; + if (!LLAvatarNameCache::get( gAgent.getID(), &av_name)) + { + slot(false, "name unavailable", LLSD()); + return; + } + + // People API expects array of [ "old value", "new value" ] + LLSD change_array = LLSD::emptyArray(); + change_array.append(av_name.getDisplayName()); + change_array.append(display_name); + + LL_INFOS() << "Set name POST to " << cap_url << LL_ENDL; + + // Record our caller for when the server sends back a reply + sSetDisplayNameSignal.connect(slot); + + // POST the requested change. The sim will not send a response back to + // this request directly, rather it will send a separate message after it + // communicates with the back-end. + LLSD body; + body["display_name"] = change_array; + LLHTTPClient::post(cap_url, body, new LLSetDisplayNameResponder, headers); +} + +class LLSetDisplayNameReply : public LLHTTPNode +{ + LOG_CLASS(LLSetDisplayNameReply); +public: + /*virtual*/ void post( + LLHTTPNode::ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + LLSD body = input["body"]; + + S32 status = body["status"].asInteger(); + bool success = (status == HTTP_OK); + std::string reason = body["reason"].asString(); + LLSD content = body["content"]; + + LL_INFOS() << "status " << status << " reason " << reason << LL_ENDL; + + // If viewer's concept of display name is out-of-date, the set request + // will fail with 409 Conflict. If that happens, fetch up-to-date + // name information. + if (status == HTTP_CONFLICT) + { + LLUUID agent_id = gAgent.getID(); + // Flush stale data + LLAvatarNameCache::erase( agent_id ); + // Queue request for new data: nothing to do on callback though... + // Note: no need to disconnect the callback as it never gets out of scope + LLAvatarNameCache::get(agent_id, boost::bind(&LLViewerDisplayName::doNothing)); + // Kill name tag, as it is wrong + LLVOAvatar::invalidateNameTag( agent_id ); + } + + // inform caller of result + LLViewerDisplayName::sSetDisplayNameSignal(success, reason, content); + LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); + } +}; + + +class LLDisplayNameUpdate : public LLHTTPNode +{ + /*virtual*/ void post( + LLHTTPNode::ResponsePtr response, + const LLSD& context, + const LLSD& input) const + { + LLSD body = input["body"]; + LLUUID agent_id = body["agent_id"]; + std::string old_display_name = body["old_display_name"]; + // By convention this record is called "agent" in the People API + LLSD name_data = body["agent"]; + + // Inject the new name data into cache + LLAvatarName av_name; + av_name.fromLLSD( name_data ); + + LL_INFOS() << "name-update now " << LLDate::now() + << " next_update " << LLDate(av_name.mNextUpdate) + << LL_ENDL; + + // Name expiration time may be provided in headers, or we may use a + // default value + // *TODO: get actual headers out of ResponsePtr + //LLSD headers = response->mHeaders; + LLSD headers; + av_name.mExpires = + LLAvatarNameCache::nameExpirationFromHeaders(headers); + + LLAvatarNameCache::insert(agent_id, av_name); + + // force name tag to update + LLVOAvatar::invalidateNameTag(agent_id); + + LLSD args; + args["OLD_NAME"] = old_display_name; + args["SLID"] = av_name.getUserName(); + args["NEW_NAME"] = av_name.getDisplayName(); + LLNotificationsUtil::add("DisplayNameUpdate", args); + if (agent_id == gAgent.getID()) + { + LLViewerDisplayName::sNameChangedSignal(); + } + } +}; + +LLHTTPRegistration + gHTTPRegistrationMessageSetDisplayNameReply( + "/message/SetDisplayNameReply"); + +LLHTTPRegistration + gHTTPRegistrationMessageDisplayNameUpdate( + "/message/DisplayNameUpdate"); diff --git a/indra/newview/llviewerdisplayname.h b/indra/newview/llviewerdisplayname.h new file mode 100644 index 0000000000..16d59ae43b --- /dev/null +++ b/indra/newview/llviewerdisplayname.h @@ -0,0 +1,53 @@ +/** + * @file llviewerdisplayname.h + * @brief Wrapper for display name functionality + * + * $LicenseInfo:firstyear=2010&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 LLVIEWERDISPLAYNAME_H +#define LLVIEWERDISPLAYNAME_H + +#include + +class LLSD; +class LLUUID; + +namespace LLViewerDisplayName +{ + typedef boost::signals2::signal< + void (bool success, const std::string& reason, const LLSD& content)> + set_name_signal_t; + typedef set_name_signal_t::slot_type set_name_slot_t; + + typedef boost::signals2::signal name_changed_signal_t; + typedef name_changed_signal_t::slot_type name_changed_slot_t; + + // Sends an update to the server to change a display name + // and call back when done. May not succeed due to service + // unavailable or name not available. + void set(const std::string& display_name, const set_name_slot_t& slot); + + void addNameChangedCallback(const name_changed_signal_t::slot_type& cb); +} + +#endif // LLVIEWERDISPLAYNAME_H diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 0ebacddd9b..e0e86bd597 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -58,6 +58,7 @@ #include "llfloaterdeleteenvpreset.h" #include "llfloaterdeleteprefpreset.h" #include "llfloaterdestinations.h" +#include "llfloaterdisplayname.h" #include "llfloatereditdaycycle.h" #include "llfloatereditsky.h" #include "llfloatereditwater.h" @@ -256,6 +257,7 @@ void LLViewerFloaterReg::registerFloaters() LLInspectRemoteObjectUtil::registerFloater(); LLFloaterVoiceVolumeUtil::registerFloater(); LLNotificationsUI::registerFloater(); + LLFloaterDisplayNameUtil::registerFloater(); LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); -- cgit v1.2.3 From 396f172636db85093f97fafa8906b3ad4cf6eecd Mon Sep 17 00:00:00 2001 From: Kadah_Coba Date: Wed, 13 Feb 2019 00:28:57 -0800 Subject: Updated LLViewerDisplayName to coroutine --- indra/newview/llviewerdisplayname.cpp | 47 ++++++++++++++++++++--------------- indra/newview/llviewerdisplayname.h | 6 +++-- 2 files changed, 31 insertions(+), 22 deletions(-) (limited to 'indra') diff --git a/indra/newview/llviewerdisplayname.cpp b/indra/newview/llviewerdisplayname.cpp index e390e8776d..24291de6df 100644 --- a/indra/newview/llviewerdisplayname.cpp +++ b/indra/newview/llviewerdisplayname.cpp @@ -35,7 +35,6 @@ // library includes #include "llavatarnamecache.h" -#include "llhttpclient.h" #include "llhttpnode.h" #include "llnotificationsutil.h" #include "llui.h" // getLanguage() @@ -56,19 +55,6 @@ namespace LLViewerDisplayName void doNothing() { } } -class LLSetDisplayNameResponder : public LLHTTPClient::Responder -{ - LOG_CLASS(LLSetDisplayNameResponder); -private: - // only care about errors - /*virtual*/ void httpFailure() - { - LL_WARNS() << dumpResponse() << LL_ENDL; - LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD()); - LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); - } -}; - void LLViewerDisplayName::set(const std::string& display_name, const set_name_slot_t& slot) { // TODO: simple validation here @@ -83,11 +69,6 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl return; } - // People API can return localized error messages. Indicate our - // language preference via header. - LLSD headers; - headers[HTTP_OUT_HEADER_ACCEPT_LANGUAGE] = LLUI::getLanguage(); - // People API requires both the old and new value to change a variable. // Our display name will be in cache before the viewer's UI is available // to request a change, so we can use direct lookup without callback. @@ -113,7 +94,33 @@ void LLViewerDisplayName::set(const std::string& display_name, const set_name_sl // communicates with the back-end. LLSD body; body["display_name"] = change_array; - LLHTTPClient::post(cap_url, body, new LLSetDisplayNameResponder, headers); + LLCoros::instance().launch("LLViewerDisplayName::SetDisplayNameCoro", + boost::bind(&LLViewerDisplayName::setDisplayNameCoro, cap_url, body)); +} + +void LLViewerDisplayName::setDisplayNameCoro(const std::string& cap_url, const LLSD& body) +{ + LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); + LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t + httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("SetDisplayNameCoro", httpPolicy)); + LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); + LLCore::HttpHeaders::ptr_t httpHeaders(new LLCore::HttpHeaders); + + // People API can return localized error messages. Indicate our + // language preference via header. + httpHeaders->append(HTTP_OUT_HEADER_ACCEPT_LANGUAGE, LLUI::getLanguage()); + + LLSD result = httpAdapter->postAndSuspend(httpRequest, cap_url, body, httpHeaders); + + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; + LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + + if (!status) + { + LL_WARNS() << "Unable to set display name. Status: " << status.toString() << LL_ENDL; + LLViewerDisplayName::sSetDisplayNameSignal(false, "", LLSD()); + LLViewerDisplayName::sSetDisplayNameSignal.disconnect_all_slots(); + } } class LLSetDisplayNameReply : public LLHTTPNode diff --git a/indra/newview/llviewerdisplayname.h b/indra/newview/llviewerdisplayname.h index 16d59ae43b..337aaa68b6 100644 --- a/indra/newview/llviewerdisplayname.h +++ b/indra/newview/llviewerdisplayname.h @@ -45,8 +45,10 @@ namespace LLViewerDisplayName // Sends an update to the server to change a display name // and call back when done. May not succeed due to service // unavailable or name not available. - void set(const std::string& display_name, const set_name_slot_t& slot); - + void set(const std::string& display_name, const set_name_slot_t& slot); + + void setDisplayNameCoro(const std::string& cap_url, const LLSD& body); + void addNameChangedCallback(const name_changed_signal_t::slot_type& cb); } -- cgit v1.2.3 From 3dea03ed4af39f11dd554d07085726c37b56e00b Mon Sep 17 00:00:00 2001 From: Kadah_Coba Date: Sat, 2 Mar 2019 23:34:31 -0800 Subject: Added LLTextBase::setParseHTML --- indra/llui/lltextbase.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra') diff --git a/indra/llui/lltextbase.h b/indra/llui/lltextbase.h index 5fdde445ef..3331b8aeee 100644 --- a/indra/llui/lltextbase.h +++ b/indra/llui/lltextbase.h @@ -366,6 +366,8 @@ public: virtual void onFocusReceived(); virtual void onFocusLost(); + void setParseHTML(bool parse_html) { mParseHTML = parse_html; } + // LLSpellCheckMenuHandler overrides /*virtual*/ bool getSpellCheck() const; -- cgit v1.2.3 From a4517dee8911bf7845afe9778dec65855de5bf6b Mon Sep 17 00:00:00 2001 From: Kadah_Coba Date: Sat, 2 Mar 2019 23:50:20 -0800 Subject: Added intrests info support to LLAvatarPropertiesProcessor --- indra/newview/llavatarpropertiesprocessor.cpp | 38 +++++++++++++++++++++++++++ indra/newview/llavatarpropertiesprocessor.h | 14 ++++++++++ 2 files changed, 52 insertions(+) (limited to 'indra') diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp index 856eb3414e..44ca3c1b5f 100644 --- a/indra/newview/llavatarpropertiesprocessor.cpp +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -299,6 +299,21 @@ void LLAvatarPropertiesProcessor::processAvatarInterestsReply(LLMessageSystem* m That will suppress the warnings and be compatible with old server versions. WARNING: LLTemplateMessageReader::decodeData: Message from 216.82.37.237:13000 with no handler function received: AvatarInterestsReply */ + + LLInterestsData interests_data; + + msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AgentID, interests_data.agent_id ); + msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AvatarID, interests_data.avatar_id ); + msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_WantToMask, interests_data.want_to_mask ); + msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_WantToText, interests_data.want_to_text ); + msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_SkillsMask, interests_data.skills_mask ); + msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_SkillsText, interests_data.skills_text ); + msg->getString( _PREHASH_PropertiesData, _PREHASH_LanguagesText, interests_data.languages_text ); + + LLAvatarPropertiesProcessor* self = getInstance(); + // Request processed, no longer pending + self->removePendingRequest(interests_data.avatar_id, APT_INTERESTS_INFO); + self->notifyObservers(interests_data.avatar_id, &interests_data, APT_INTERESTS_INFO); } void LLAvatarPropertiesProcessor::processAvatarClassifiedsReply(LLMessageSystem* msg, void**) @@ -538,6 +553,29 @@ void LLAvatarPropertiesProcessor::sendClassifiedDelete(const LLUUID& classified_ gAgent.sendReliableMessage(); } +void LLAvatarPropertiesProcessor::sendInterestsInfoUpdate(const LLInterestsData* interests_data) +{ + if(!interests_data) + { + 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_data->want_to_mask); + msg->addStringFast( _PREHASH_WantToText, interests_data->want_to_text); + msg->addU32Fast( _PREHASH_SkillsMask, interests_data->skills_mask); + msg->addStringFast( _PREHASH_SkillsText, interests_data->skills_text); + msg->addString( _PREHASH_LanguagesText, interests_data->languages_text); + + gAgent.sendReliableMessage(); +} + void LLAvatarPropertiesProcessor::sendPickInfoUpdate(const LLPickData* new_pick) { if (!new_pick) return; diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h index d5c5c75c69..1c981d5b2e 100644 --- a/indra/newview/llavatarpropertiesprocessor.h +++ b/indra/newview/llavatarpropertiesprocessor.h @@ -56,10 +56,22 @@ enum EAvatarProcessorType APT_PICKS, APT_PICK_INFO, APT_TEXTURES, + APT_INTERESTS_INFO, APT_CLASSIFIEDS, APT_CLASSIFIED_INFO }; +struct LLInterestsData +{ + 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; +}; + struct LLAvatarData { LLUUID agent_id; @@ -223,6 +235,8 @@ public: void sendClassifiedDelete(const LLUUID& classified_id); + void sendInterestsInfoUpdate(const LLInterestsData* interests_data); + // 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); -- cgit v1.2.3 From ce55a2d5692e72b2082aba33e97dc8b03d02cf92 Mon Sep 17 00:00:00 2001 From: Kadah_Coba Date: Sun, 3 Mar 2019 19:16:56 -0800 Subject: Remvoed dead code --- indra/newview/llstartup.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 37aaece5d6..5472ef12e3 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -95,6 +95,7 @@ #include "llfloateravatarpicker.h" #include "llcallbacklist.h" #include "llcallingcard.h" +#include "llclassifiedinfo.h" #include "llconsole.h" #include "llcontainerview.h" #include "llconversationlog.h" @@ -123,7 +124,6 @@ #include "llpanellogin.h" #include "llmutelist.h" #include "llavatarpropertiesprocessor.h" -#include "llpanelclassified.h" #include "llpanelpick.h" #include "llpanelgrouplandmoney.h" #include "llpanelgroupnotices.h" @@ -2517,7 +2517,6 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply); msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply); -// msg->setHandlerFunc("ClassifiedInfoReply", LLPanelClassified::processClassifiedInfoReply); msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply); msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply); msg->setHandlerFunc("ScriptDialog", process_script_dialog); -- cgit v1.2.3 From 0be2b5ce51a7625b01884d512906cdcf3a580444 Mon Sep 17 00:00:00 2001 From: Kadah_Coba Date: Sun, 3 Mar 2019 22:56:19 -0800 Subject: Corrected LLPanelIMControlPanel source file header info --- indra/newview/llpanelimcontrolpanel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp index 389baa86cd..07a8641a92 100644 --- a/indra/newview/llpanelimcontrolpanel.cpp +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -1,6 +1,6 @@ /** - * @file llpanelavatar.cpp - * @brief LLPanelAvatar and related class implementations + * @file llpanelimcontrolpanel.cpp + * @brief LLPanelIMControlPanel and related class implementations * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code -- cgit v1.2.3 From b82d70cf2aa2b56a2c0bfdd941ee4f74e690e4df Mon Sep 17 00:00:00 2001 From: Kadah_Coba Date: Mon, 4 Mar 2019 00:18:45 -0800 Subject: Added viewer based profiles Split picks and classifieds in to separate panels Moved getProfileURL to LLAvatarActions Removed dead XUI panels Removed picks/classifieds floater --- indra/newview/CMakeLists.txt | 12 +- indra/newview/llavataractions.cpp | 109 +- indra/newview/llavataractions.h | 21 +- indra/newview/llfloateroutfitsnapshot.cpp | 1 - indra/newview/llfloaterprofile.cpp | 107 ++ indra/newview/llfloaterprofile.h | 62 + indra/newview/llgrouplist.cpp | 185 ++- indra/newview/llgrouplist.h | 19 +- indra/newview/llpanelavatar.cpp | 207 +-- indra/newview/llpanelavatar.h | 167 ++- indra/newview/llpanelclassified.cpp | 1178 --------------- indra/newview/llpanelclassified.h | 301 ---- indra/newview/llpanelexperiences.h | 1 - indra/newview/llpanelme.cpp | 68 - indra/newview/llpanelme.h | 50 - indra/newview/llpanelpicks.cpp | 1454 ------------------- indra/newview/llpanelpicks.h | 314 ---- indra/newview/llpanelprofile.cpp | 1494 +++++++++++++++++--- indra/newview/llpanelprofile.h | 406 +++++- indra/newview/llpanelprofileclassifieds.cpp | 1331 +++++++++++++++++ indra/newview/llpanelprofileclassifieds.h | 366 +++++ indra/newview/llpanelprofilepicks.cpp | 774 ++++++++++ indra/newview/llpanelprofilepicks.h | 234 +++ indra/newview/llviewerfloaterreg.cpp | 8 +- indra/newview/llviewermedia.cpp | 2 +- indra/newview/llviewermenu.cpp | 10 + indra/newview/llwebprofile.cpp | 2 +- indra/newview/skins/default/colors.xml | 16 + indra/newview/skins/default/xui/da/panel_me.xml | 7 - .../skins/default/xui/da/panel_side_tray.xml | 29 - .../newview/skins/default/xui/de/floater_picks.xml | 2 - indra/newview/skins/default/xui/de/panel_me.xml | 4 - .../newview/skins/default/xui/en/floater_picks.xml | 21 - .../skins/default/xui/en/floater_profile.xml | 119 ++ indra/newview/skins/default/xui/en/menu_viewer.xml | 3 +- .../default/xui/en/panel_group_list_item_short.xml | 83 ++ indra/newview/skins/default/xui/en/panel_me.xml | 19 - .../default/xui/en/panel_profile_classified.xml | 711 ++++++++++ .../default/xui/en/panel_profile_classifieds.xml | 76 + .../default/xui/en/panel_profile_firstlife.xml | 59 + .../default/xui/en/panel_profile_interests.xml | 250 ++++ .../skins/default/xui/en/panel_profile_notes.xml | 86 ++ .../skins/default/xui/en/panel_profile_pick.xml | 109 ++ .../skins/default/xui/en/panel_profile_picks.xml | 87 ++ .../default/xui/en/panel_profile_secondlife.xml | 512 +++++++ .../skins/default/xui/en/panel_profile_web.xml | 92 ++ indra/newview/skins/default/xui/en/strings.xml | 12 +- .../newview/skins/default/xui/es/floater_picks.xml | 2 - indra/newview/skins/default/xui/es/panel_me.xml | 4 - .../newview/skins/default/xui/fr/floater_picks.xml | 2 - indra/newview/skins/default/xui/fr/panel_me.xml | 4 - .../newview/skins/default/xui/it/floater_picks.xml | 2 - indra/newview/skins/default/xui/it/panel_me.xml | 4 - .../newview/skins/default/xui/ja/floater_picks.xml | 2 - indra/newview/skins/default/xui/ja/panel_me.xml | 4 - .../newview/skins/default/xui/pl/floater_picks.xml | 2 - indra/newview/skins/default/xui/pl/panel_me.xml | 4 - .../newview/skins/default/xui/pt/floater_picks.xml | 2 - indra/newview/skins/default/xui/pt/panel_me.xml | 4 - .../newview/skins/default/xui/ru/floater_picks.xml | 2 - indra/newview/skins/default/xui/ru/panel_me.xml | 4 - .../newview/skins/default/xui/tr/floater_picks.xml | 2 - indra/newview/skins/default/xui/tr/panel_me.xml | 4 - .../newview/skins/default/xui/zh/floater_picks.xml | 2 - indra/newview/skins/default/xui/zh/panel_me.xml | 4 - 65 files changed, 7159 insertions(+), 4075 deletions(-) create mode 100644 indra/newview/llfloaterprofile.cpp create mode 100644 indra/newview/llfloaterprofile.h delete mode 100644 indra/newview/llpanelclassified.cpp delete mode 100644 indra/newview/llpanelclassified.h delete mode 100644 indra/newview/llpanelme.cpp delete mode 100644 indra/newview/llpanelme.h delete mode 100644 indra/newview/llpanelpicks.cpp delete mode 100644 indra/newview/llpanelpicks.h create mode 100644 indra/newview/llpanelprofileclassifieds.cpp create mode 100644 indra/newview/llpanelprofileclassifieds.h create mode 100644 indra/newview/llpanelprofilepicks.cpp create mode 100644 indra/newview/llpanelprofilepicks.h delete mode 100644 indra/newview/skins/default/xui/da/panel_me.xml delete mode 100644 indra/newview/skins/default/xui/da/panel_side_tray.xml delete mode 100644 indra/newview/skins/default/xui/de/floater_picks.xml delete mode 100644 indra/newview/skins/default/xui/de/panel_me.xml delete mode 100644 indra/newview/skins/default/xui/en/floater_picks.xml create mode 100644 indra/newview/skins/default/xui/en/floater_profile.xml create mode 100644 indra/newview/skins/default/xui/en/panel_group_list_item_short.xml delete mode 100644 indra/newview/skins/default/xui/en/panel_me.xml create mode 100644 indra/newview/skins/default/xui/en/panel_profile_classified.xml create mode 100644 indra/newview/skins/default/xui/en/panel_profile_classifieds.xml create mode 100644 indra/newview/skins/default/xui/en/panel_profile_firstlife.xml create mode 100644 indra/newview/skins/default/xui/en/panel_profile_interests.xml create mode 100644 indra/newview/skins/default/xui/en/panel_profile_notes.xml create mode 100644 indra/newview/skins/default/xui/en/panel_profile_pick.xml create mode 100644 indra/newview/skins/default/xui/en/panel_profile_picks.xml create mode 100644 indra/newview/skins/default/xui/en/panel_profile_secondlife.xml create mode 100644 indra/newview/skins/default/xui/en/panel_profile_web.xml delete mode 100644 indra/newview/skins/default/xui/es/floater_picks.xml delete mode 100644 indra/newview/skins/default/xui/es/panel_me.xml delete mode 100644 indra/newview/skins/default/xui/fr/floater_picks.xml delete mode 100644 indra/newview/skins/default/xui/fr/panel_me.xml delete mode 100644 indra/newview/skins/default/xui/it/floater_picks.xml delete mode 100644 indra/newview/skins/default/xui/it/panel_me.xml delete mode 100644 indra/newview/skins/default/xui/ja/floater_picks.xml delete mode 100644 indra/newview/skins/default/xui/ja/panel_me.xml delete mode 100644 indra/newview/skins/default/xui/pl/floater_picks.xml delete mode 100644 indra/newview/skins/default/xui/pl/panel_me.xml delete mode 100644 indra/newview/skins/default/xui/pt/floater_picks.xml delete mode 100644 indra/newview/skins/default/xui/pt/panel_me.xml delete mode 100644 indra/newview/skins/default/xui/ru/floater_picks.xml delete mode 100644 indra/newview/skins/default/xui/ru/panel_me.xml delete mode 100644 indra/newview/skins/default/xui/tr/floater_picks.xml delete mode 100644 indra/newview/skins/default/xui/tr/panel_me.xml delete mode 100644 indra/newview/skins/default/xui/zh/floater_picks.xml delete mode 100644 indra/newview/skins/default/xui/zh/panel_me.xml (limited to 'indra') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index c1bbdeaf46..30d6ef4416 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -280,6 +280,7 @@ set(viewer_SOURCE_FILES llfloaterpay.cpp llfloaterperms.cpp llfloaterpostprocess.cpp + llfloaterprofile.cpp llfloaterpreference.cpp llfloaterpreviewtrash.cpp llfloaterproperties.cpp @@ -421,7 +422,6 @@ set(viewer_SOURCE_FILES llpanelavatar.cpp llpanelavatartag.cpp llpanelblockedlist.cpp - llpanelclassified.cpp llpanelcontents.cpp llpaneleditwearable.cpp llpanelexperiencelisteditor.cpp @@ -453,7 +453,6 @@ set(viewer_SOURCE_FILES llpanelmediasettingsgeneral.cpp llpanelmediasettingspermissions.cpp llpanelmediasettingssecurity.cpp - llpanelme.cpp llpanelnearbymedia.cpp llpanelobject.cpp llpanelobjectinventory.cpp @@ -464,7 +463,6 @@ set(viewer_SOURCE_FILES llpanelpeoplemenus.cpp llpanelpermissions.cpp llpanelpick.cpp - llpanelpicks.cpp llpanelplaceinfo.cpp llpanelplaceprofile.cpp llpanelplaces.cpp @@ -472,6 +470,8 @@ set(viewer_SOURCE_FILES llpanelpresetspulldown.cpp llpanelprimmediacontrols.cpp llpanelprofile.cpp + llpanelprofileclassifieds.cpp + llpanelprofilepicks.cpp llpanelsnapshot.cpp llpanelsnapshotinventory.cpp llpanelsnapshotlocal.cpp @@ -909,6 +909,7 @@ set(viewer_HEADER_FILES llfloaterpay.h llfloaterperms.h llfloaterpostprocess.h + llfloaterprofile.h llfloaterpreference.h llfloaterpreviewtrash.h llfloaterproperties.h @@ -1040,7 +1041,6 @@ set(viewer_HEADER_FILES llpanelavatar.h llpanelavatartag.h llpanelblockedlist.h - llpanelclassified.h llpanelcontents.h llpaneleditwearable.h llpanelexperiencelisteditor.h @@ -1073,7 +1073,6 @@ set(viewer_HEADER_FILES llpanelmediasettingsgeneral.h llpanelmediasettingspermissions.h llpanelmediasettingssecurity.h - llpanelme.h llpanelnearbymedia.h llpanelobject.h llpanelobjectinventory.h @@ -1084,7 +1083,6 @@ set(viewer_HEADER_FILES llpanelpeoplemenus.h llpanelpermissions.h llpanelpick.h - llpanelpicks.h llpanelplaceinfo.h llpanelplaceprofile.h llpanelplaces.h @@ -1092,6 +1090,8 @@ set(viewer_HEADER_FILES llpanelpresetspulldown.h llpanelprimmediacontrols.h llpanelprofile.h + llpanelprofileclassifieds.h + llpanelprofilepicks.h llpanelsnapshot.h llpanelteleporthistory.h llpaneltiptoast.h diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp index f0b74e7439..ecfb2cd5a8 100644 --- a/indra/newview/llavataractions.cpp +++ b/indra/newview/llavataractions.cpp @@ -48,6 +48,7 @@ #include "llfloatergroups.h" #include "llfloaterreg.h" #include "llfloaterpay.h" +#include "llfloaterprofile.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterwebcontent.h" #include "llfloaterworldmap.h" @@ -67,6 +68,7 @@ #include "llviewercontrol.h" #include "llviewerobjectlist.h" #include "llviewermessage.h" // for handle_lure +#include "llviewernetwork.h" //LLGridManager #include "llviewerregion.h" #include "lltrans.h" #include "llcallingcard.h" @@ -81,6 +83,18 @@ const U32 KICK_FLAGS_FREEZE = 1 << 0; const U32 KICK_FLAGS_UNFREEZE = 1 << 1; +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 void LLAvatarActions::requestFriendshipDialog(const LLUUID& id, const std::string& name) { @@ -319,7 +333,7 @@ void LLAvatarActions::startConference(const uuid_vec_t& ids, const LLUUID& float static const char* get_profile_floater_name(const LLUUID& avatar_id) { // Use different floater XML for our profile to be able to save its rect. - return avatar_id == gAgentID ? "my_profile" : "profile"; + return avatar_id == gAgentID ? "my_profile_web" : "profile_web"; } static void on_avatar_name_show_profile(const LLUUID& agent_id, const LLAvatarName& av_name) @@ -333,40 +347,101 @@ static void on_avatar_name_show_profile(const LLUUID& agent_id, const LLAvatarNa } // static -void LLAvatarActions::showProfile(const LLUUID& id) +void LLAvatarActions::showProfile(const LLUUID& avatar_id) +{ + if (avatar_id.notNull()) + { + LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id)); + } +} + +// static +void LLAvatarActions::showPicks(const LLUUID& avatar_id) { - if (id.notNull()) + if (avatar_id.notNull()) { - LLAvatarNameCache::get(id, boost::bind(&on_avatar_name_show_profile, _1, _2)); + LLFloaterProfile* profilefloater = dynamic_cast(LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id))); + if (profilefloater) + { + profilefloater->showPick(); + } + } +} + +// static +void LLAvatarActions::showPick(const LLUUID& avatar_id, const LLUUID& pick_id) +{ + if (avatar_id.notNull()) + { + LLFloaterProfile* profilefloater = dynamic_cast(LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id))); + if (profilefloater) + { + profilefloater->showPick(pick_id); + } + } +} + +// static +void LLAvatarActions::showClassifieds(const LLUUID& avatar_id) +{ + if (avatar_id.notNull()) + { + LLFloaterProfile* profilefloater = dynamic_cast(LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id))); + if (profilefloater) + { + profilefloater->showClassified(); + } + } +} + +// static +void LLAvatarActions::showClassified(const LLUUID& avatar_id, const LLUUID& classified_id, bool edit) +{ + if (avatar_id.notNull()) + { + LLFloaterProfile* profilefloater = dynamic_cast(LLFloaterReg::showInstance("profile", LLSD().with("id", avatar_id))); + if (profilefloater) + { + profilefloater->showClassified(classified_id, edit); + } } } //static -bool LLAvatarActions::profileVisible(const LLUUID& id) +bool LLAvatarActions::profileVisible(const LLUUID& avatar_id) { LLSD sd; - sd["id"] = id; - LLFloater* browser = getProfileFloater(id); - return browser && browser->isShown(); + sd["id"] = avatar_id; + LLFloater* floater = getProfileFloater(avatar_id); + return floater && floater->isShown(); } //static -LLFloater* LLAvatarActions::getProfileFloater(const LLUUID& id) +LLFloater* LLAvatarActions::getProfileFloater(const LLUUID& avatar_id) +{ + LLFloaterProfile* floater = LLFloaterReg::findTypedInstance("profile", LLSD().with("id", avatar_id)); + return floater; +} + +// static +void LLAvatarActions::showProfileWeb(const LLUUID& avatar_id) { - LLFloaterWebContent *browser = dynamic_cast - (LLFloaterReg::findInstance(get_profile_floater_name(id), LLSD().with("id", id))); - return browser; + if (avatar_id.notNull()) + { + LLAvatarNameCache::get(avatar_id, boost::bind(&on_avatar_name_show_profile, _1, _2)); + } } + //static -void LLAvatarActions::hideProfile(const LLUUID& id) +void LLAvatarActions::hideProfile(const LLUUID& avatar_id) { LLSD sd; - sd["id"] = id; - LLFloater* browser = getProfileFloater(id); - if (browser) + sd["id"] = avatar_id; + LLFloater* floater = getProfileFloater(avatar_id); + if (floater) { - browser->closeFloater(); + floater->closeFloater(); } } diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h index b56d5b0fb9..3383b3f5f9 100644 --- a/indra/newview/llavataractions.h +++ b/indra/newview/llavataractions.h @@ -38,6 +38,8 @@ class LLInventoryPanel; class LLFloater; class LLView; +std::string getProfileURL(const std::string& agent_name); + /** * Friend-related actions (add, remove, offer teleport, etc) */ @@ -91,13 +93,18 @@ public: */ static void startConference(const uuid_vec_t& ids, const LLUUID& floater_id = LLUUID::null); - /** - * Show avatar profile. - */ - static void showProfile(const LLUUID& id); - static void hideProfile(const LLUUID& id); - static bool profileVisible(const LLUUID& id); - static LLFloater* getProfileFloater(const LLUUID& id); + /** + * Show avatar profile. + */ + static void showProfile(const LLUUID& avatar_id); + static void showPicks(const LLUUID& avatar_id); + static void showPick(const LLUUID& avatar_id, const LLUUID& pick_id); + static void showClassifieds(const LLUUID& avatar_id); + static void showClassified(const LLUUID& avatar_id, const LLUUID& classified_id, bool edit = false); + static void hideProfile(const LLUUID& avatar_id); + static bool profileVisible(const LLUUID& avatar_id); + static LLFloater* getProfileFloater(const LLUUID& avatar_id); + static void showProfileWeb(const LLUUID& avatar_id); /** * Show avatar on world map. diff --git a/indra/newview/llfloateroutfitsnapshot.cpp b/indra/newview/llfloateroutfitsnapshot.cpp index d80793f9e4..4fbb64a1db 100644 --- a/indra/newview/llfloateroutfitsnapshot.cpp +++ b/indra/newview/llfloateroutfitsnapshot.cpp @@ -46,7 +46,6 @@ #include "llviewercontrol.h" #include "lltoolfocus.h" #include "lltoolmgr.h" -#include "llwebprofile.h" ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs diff --git a/indra/newview/llfloaterprofile.cpp b/indra/newview/llfloaterprofile.cpp new file mode 100644 index 0000000000..6b8f881b08 --- /dev/null +++ b/indra/newview/llfloaterprofile.cpp @@ -0,0 +1,107 @@ +/** + * @file llfloaterprofile.cpp + * @brief Avatar profile floater. + * + * $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$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterprofile.h" + +#include "llpanelavatar.h" +#include "llpanelprofile.h" +#include "llagent.h" //gAgent + +static const std::string PANEL_PROFILE_VIEW = "panel_profile_view"; + +LLFloaterProfile::LLFloaterProfile(const LLSD& key) + : LLFloater(key), + mAvatarId(key["id"].asUUID()), + mNameCallbackConnection() +{ +} + +LLFloaterProfile::~LLFloaterProfile() +{ + if (mNameCallbackConnection.connected()) + { + mNameCallbackConnection.disconnect(); + } +} + +void LLFloaterProfile::onOpen(const LLSD& key) +{ + mPanelProfile->onOpen(key); + + if (mAvatarId == gAgentID) + { + getChild("ok_btn")->setVisible(TRUE); + getChild("cancel_btn")->setVisible(TRUE); + } + + // Update the avatar name. + mNameCallbackConnection = LLAvatarNameCache::get(mAvatarId, boost::bind(&LLFloaterProfile::onAvatarNameCache, this, _1, _2)); +} + +BOOL LLFloaterProfile::postBuild() +{ + mPanelProfile = findChild(PANEL_PROFILE_VIEW); + + childSetAction("ok_btn", boost::bind(&LLFloaterProfile::onOKBtn, this)); + childSetAction("cancel_btn", boost::bind(&LLFloaterProfile::onCancelBtn, this)); + + return TRUE; +} + +void LLFloaterProfile::showPick(const LLUUID& pick_id) +{ + mPanelProfile->showPick(pick_id); +} + +void LLFloaterProfile::showClassified(const LLUUID& classified_id, bool edit) +{ + mPanelProfile->showClassified(classified_id, edit); +} + +void LLFloaterProfile::onOKBtn() +{ + if (mAvatarId == gAgentID) + { + mPanelProfile->apply(); + } + + closeFloater(); +} + +void LLFloaterProfile::onCancelBtn() +{ + closeFloater(); +} + +void LLFloaterProfile::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) +{ + mNameCallbackConnection.disconnect(); + setTitle(av_name.getCompleteName()); +} + +// eof diff --git a/indra/newview/llfloaterprofile.h b/indra/newview/llfloaterprofile.h new file mode 100644 index 0000000000..fa06347cee --- /dev/null +++ b/indra/newview/llfloaterprofile.h @@ -0,0 +1,62 @@ +/** + * @file llfloaterprofile.h + * @brief Avatar profile floater. + * + * $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$ + */ + +#ifndef LL_LLFLOATERPROFILE_H +#define LL_LLFLOATERPROFILE_H + +#include "llavatarnamecache.h" +#include "llfloater.h" + +class LLPanelProfile; + +class LLFloaterProfile : public LLFloater +{ + LOG_CLASS(LLFloaterProfile); +public: + LLFloaterProfile(const LLSD& key); + virtual ~LLFloaterProfile(); + + /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ BOOL postBuild(); + + void showPick(const LLUUID& pick_id = LLUUID::null); + + void showClassified(const LLUUID& classified_id = LLUUID::null, bool edit = false); + +protected: + void onOKBtn(); + void onCancelBtn(); + +private: + LLAvatarNameCache::callback_connection_t mNameCallbackConnection; + void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); + + LLPanelProfile* mPanelProfile; + + LLUUID mAvatarId; +}; + +#endif // LL_LLFLOATERPROFILE_H diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 62414d3bbb..3a81d1557e 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -65,22 +65,46 @@ public: } }; -static const LLGroupComparator GROUP_COMPARATOR; +static LLGroupComparator GROUP_COMPARATOR; +LLGroupList::Params::Params() +: for_agent("for_agent", true) +{ +} LLGroupList::LLGroupList(const Params& p) : LLFlatListViewEx(p) + , mForAgent(p.for_agent) , mDirty(true) // to force initial update + , mShowIcons(false) + , mShowNone(true) { - // Listen for agent group changes. - gAgent.addListener(this, "new group"); - - mShowIcons = gSavedSettings.getBOOL("GroupListShowIcons"); setCommitOnSelectionChange(true); // Set default sort order. setComparator(&GROUP_COMPARATOR); + if (mForAgent) + { + enableForAgent(true); + } +} + +LLGroupList::~LLGroupList() +{ + if (mForAgent) gAgent.removeListener(this); + if (mContextMenuHandle.get()) mContextMenuHandle.get()->die(); +} + +void LLGroupList::enableForAgent(bool show_icons) +{ + mForAgent = true; + + mShowIcons = mForAgent && gSavedSettings.getBOOL("GroupListShowIcons") && show_icons; + + // Listen for agent group changes. + gAgent.addListener(this, "new group"); + // Set up context menu. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; @@ -94,12 +118,6 @@ LLGroupList::LLGroupList(const Params& p) mContextMenuHandle = context_menu->getHandle(); } -LLGroupList::~LLGroupList() -{ - gAgent.removeListener(this); - if (mContextMenuHandle.get()) mContextMenuHandle.get()->die(); -} - // virtual void LLGroupList::draw() { @@ -114,12 +132,15 @@ BOOL LLGroupList::handleRightMouseDown(S32 x, S32 y, MASK mask) { BOOL handled = LLUICtrl::handleRightMouseDown(x, y, mask); - LLToggleableMenu* context_menu = mContextMenuHandle.get(); - if (context_menu && size() > 0) - { - context_menu->buildDrawLabels(); - context_menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, context_menu, x, y); + if (mForAgent) + { + LLToggleableMenu* context_menu = mContextMenuHandle.get(); + if (context_menu && size() > 0) + { + context_menu->buildDrawLabels(); + context_menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, context_menu, x, y); + } } return handled; @@ -164,34 +185,49 @@ static bool findInsensitive(std::string haystack, const std::string& needle_uppe void LLGroupList::refresh() { - const LLUUID& highlight_id = gAgent.getGroupID(); - S32 count = gAgent.mGroups.size(); - LLUUID id; - bool have_filter = !mNameFilter.empty(); - - clear(); - - for(S32 i = 0; i < count; ++i) - { - id = gAgent.mGroups.at(i).mID; - const LLGroupData& group_data = gAgent.mGroups.at(i); - if (have_filter && !findInsensitive(group_data.mName, mNameFilter)) - continue; - addNewItem(id, group_data.mName, group_data.mInsigniaID, ADD_BOTTOM); - } - - // Sort the list. - sort(); - - // Add "none" to list at top if filter not set (what's the point of filtering "none"?). - // but only if some real groups exists. EXT-4838 - if (!have_filter && count > 0) - { - std::string loc_none = LLTrans::getString("GroupsNone"); - addNewItem(LLUUID::null, loc_none, LLUUID::null, ADD_TOP); - } - - selectItemByUUID(highlight_id); + if (mForAgent) + { + const LLUUID& highlight_id = gAgent.getGroupID(); + S32 count = gAgent.mGroups.size(); + LLUUID id; + bool have_filter = !mNameFilter.empty(); + + clear(); + + for(S32 i = 0; i < count; ++i) + { + id = gAgent.mGroups.at(i).mID; + const LLGroupData& group_data = gAgent.mGroups.at(i); + if (have_filter && !findInsensitive(group_data.mName, mNameFilter)) + continue; + addNewItem(id, group_data.mName, group_data.mInsigniaID, ADD_BOTTOM, group_data.mListInProfile); + } + + // Sort the list. + sort(); + + // Add "none" to list at top if filter not set (what's the point of filtering "none"?). + // but only if some real groups exists. EXT-4838 + if (!have_filter && count > 0 && mShowNone) + { + std::string loc_none = LLTrans::getString("GroupsNone"); + addNewItem(LLUUID::null, loc_none, LLUUID::null, ADD_TOP); + } + + selectItemByUUID(highlight_id); + } + else + { + clear(); + + for (group_map_t::iterator it = mGroups.begin(); it != mGroups.end(); ++it) + { + addNewItem(it->second, it->first, LLUUID::null, ADD_BOTTOM); + } + + // Sort the list. + sort(); + } setDirty(false); onCommit(); @@ -212,13 +248,19 @@ void LLGroupList::toggleIcons() } } +void LLGroupList::setGroups(const std::map< std::string,LLUUID> group_list) +{ + mGroups = group_list; + setDirty(true); +} + ////////////////////////////////////////////////////////////////////////// // PRIVATE Section ////////////////////////////////////////////////////////////////////////// -void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos) +void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos, bool visible_in_profile) { - LLGroupListItem* item = new LLGroupListItem(); + LLGroupListItem* item = new LLGroupListItem(mForAgent && mShowIcons); item->setGroupID(id); item->setName(name, mNameFilter); @@ -227,7 +269,7 @@ void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LL item->getChildView("info_btn")->setVisible( false); item->getChildView("profile_btn")->setVisible( false); item->setGroupIconVisible(mShowIcons); - + item->setVisibleInProfile(visible_in_profile); addItem(item, id, pos); // setCommentVisible(false); @@ -243,6 +285,29 @@ bool LLGroupList::handleEvent(LLPointer event, const LLSD& return true; } + if (event->desc() == "value_changed") + { + LLSD data = event->getValue(); + if (data.has("group_id") && data.has("visible")) + { + LLUUID group_id = data["group_id"].asUUID(); + bool visible = data["visible"].asBoolean(); + + std::vector items; + getItems(items); + for (std::vector::iterator it = items.begin(); it != items.end(); ++it) + { + LLGroupListItem* item = dynamic_cast(*it); + if (item && item->getGroupID() == group_id) + { + item->setVisibleInProfile(visible); + break; + } + } + } + return true; + } + return false; } @@ -294,18 +359,25 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata) /* LLGroupListItem implementation */ /************************************************************************/ -LLGroupListItem::LLGroupListItem() +LLGroupListItem::LLGroupListItem(bool for_agent) : LLPanel(), mGroupIcon(NULL), mGroupNameBox(NULL), mInfoBtn(NULL), mGroupID(LLUUID::null) { - buildFromFile( "panel_group_list_item.xml"); + if (for_agent) + { + buildFromFile( "panel_group_list_item.xml"); + } + else + { + buildFromFile( "panel_group_list_item_short.xml"); + } // Remember group icon width including its padding from the name text box, // so that we can hide and show the icon again later. - if (!sIconWidth) + if (!sIconWidth && mGroupNameBox) { sIconWidth = mGroupNameBox->getRect().mLeft - mGroupIcon->getRect().mLeft; } @@ -397,6 +469,11 @@ void LLGroupListItem::setGroupIconVisible(bool visible) mGroupNameBox->setRect(name_rect); } +void LLGroupListItem::setVisibleInProfile(bool visible) +{ + mGroupNameBox->setColor(LLUIColorTable::instance().getColor((visible ? "GroupVisibleInProfile" : "GroupHiddenInProfile"), LLColor4::red).get()); +} + ////////////////////////////////////////////////////////////////////////// // Private Section ////////////////////////////////////////////////////////////////////////// @@ -433,8 +510,10 @@ void LLGroupListItem::onProfileBtnClick() void LLGroupListItem::changed(LLGroupChange gc) { LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(mID); - if(group_data) - setGroupIconID(group_data->mInsigniaID); + if ((gc == GC_ALL || gc == GC_PROPERTIES) && group_data) + { + setGroupIconID(group_data->mInsigniaID); + } } //EOF diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h index 171b77fb00..063b50f5c5 100644 --- a/indra/newview/llgrouplist.h +++ b/indra/newview/llgrouplist.h @@ -50,12 +50,15 @@ class LLGroupList: public LLFlatListViewEx, public LLOldEvents::LLSimpleListener public: struct Params : public LLInitParam::Block { - Params(){}; + Optional for_agent; + Params(); }; LLGroupList(const Params& p); virtual ~LLGroupList(); + void enableForAgent(bool show_icons); + virtual void draw(); // from LLView /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); // from LLView /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); // from LLView @@ -63,13 +66,16 @@ public: void setNameFilter(const std::string& filter); void toggleIcons(); bool getIconsVisible() const { return mShowIcons; } + void setIconsVisible(bool show_icons) { mShowIcons = show_icons; } + void setShowNone(bool show_none) { mShowNone = show_none; } + void setGroups(const std::map< std::string,LLUUID> group_list); LLToggleableMenu* getContextMenu() const { return mContextMenuHandle.get(); } private: void setDirty(bool val = true) { mDirty = val; } void refresh(); - void addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos = ADD_BOTTOM); + void addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos = ADD_BOTTOM, bool visible_in_profile = true); bool handleEvent(LLPointer event, const LLSD& userdata); // called on agent group list changes bool onContextMenuItemClick(const LLSD& userdata); @@ -80,6 +86,11 @@ private: bool mShowIcons; bool mDirty; std::string mNameFilter; + + bool mForAgent; + bool mShowNone; + typedef std::map< std::string,LLUUID> group_map_t; + group_map_t mGroups; }; class LLButton; @@ -90,7 +101,7 @@ class LLGroupListItem : public LLPanel , public LLGroupMgrObserver { public: - LLGroupListItem(); + LLGroupListItem(bool for_agent); ~LLGroupListItem(); /*virtual*/ BOOL postBuild(); /*virtual*/ void setValue(const LLSD& value); @@ -106,6 +117,8 @@ public: void setGroupIconVisible(bool visible); virtual void changed(LLGroupChange gc); + + void setVisibleInProfile(bool visible); private: void setActive(bool active); void onInfoBtnClick(); diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 5d1b582d1f..dbda6070fa 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llpanelavatar.cpp * @brief LLPanelAvatar and related class implementations * * $LicenseInfo:firstyear=2004&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$ */ @@ -28,172 +28,107 @@ #include "llpanelavatar.h" #include "llagent.h" -#include "llavataractions.h" -#include "llcallingcard.h" -#include "llcombobox.h" -#include "lldateutil.h" // ageFromDate() -#include "llimview.h" -#include "llmenubutton.h" -#include "llnotificationsutil.h" -#include "llslurl.h" -#include "lltexteditor.h" -#include "lltexturectrl.h" -#include "lltoggleablemenu.h" +#include "llloadingindicator.h" #include "lltooldraganddrop.h" -#include "llscrollcontainer.h" -#include "llavatariconctrl.h" -#include "llfloaterreg.h" -#include "llnotificationsutil.h" -#include "llvoiceclient.h" -#include "lltextbox.h" -#include "lltrans.h" - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLDropTarget -// -// This handy class is a simple way to drop something on another -// view. It handles drop events, always setting itself to the size of -// its parent. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLDropTarget : public LLView -{ -public: - struct Params : public LLInitParam::Block - { - Optional agent_id; - Params() - : agent_id("agent_id") - { - changeDefault(mouse_opaque, false); - changeDefault(follows.flags, FOLLOWS_ALL); - } - }; - - LLDropTarget(const Params&); - ~LLDropTarget(); - - void doDrop(EDragAndDropType cargo_type, void* cargo_data); - - // - // LLView functionality - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - void setAgentID(const LLUUID &agent_id) { mAgentID = agent_id; } -protected: - LLUUID mAgentID; -}; - -LLDropTarget::LLDropTarget(const LLDropTarget::Params& p) -: LLView(p), - mAgentID(p.agent_id) -{} -LLDropTarget::~LLDropTarget() +////////////////////////////////////////////////////////////////////////// +// LLProfileDropTarget + +LLProfileDropTarget::LLProfileDropTarget(const LLProfileDropTarget::Params& p) +: LLView(p), + mAgentID(p.agent_id) {} -void LLDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data) +void LLProfileDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data) { - LL_INFOS() << "LLDropTarget::doDrop()" << LL_ENDL; + LL_INFOS() << "LLProfileDropTarget::doDrop()" << LL_ENDL; } -BOOL LLDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) +BOOL LLProfileDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) { - if(getParent()) - { - LLToolDragAndDrop::handleGiveDragAndDrop(mAgentID, LLUUID::null, drop, - cargo_type, cargo_data, accept); + if (getParent()) + { + LLToolDragAndDrop::handleGiveDragAndDrop(mAgentID, LLUUID::null, drop, + cargo_type, cargo_data, accept); - return TRUE; - } + return TRUE; + } - return FALSE; + return FALSE; } -static LLDefaultChildRegistry::Register r("drop_target"); +static LLDefaultChildRegistry::Register r("profile_drop_target"); ////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// +// LLPanelProfileTab LLPanelProfileTab::LLPanelProfileTab() : LLPanel() , mAvatarId(LLUUID::null) +, mLoading(false) +, mLoaded(false) +, mEmbedded(false) +, mSelfProfile(false) { } LLPanelProfileTab::~LLPanelProfileTab() { - if(getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); - } + if(getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); + } } -void LLPanelProfileTab::setAvatarId(const LLUUID& id) +void LLPanelProfileTab::setAvatarId(const LLUUID& avatar_id) { - if(id.notNull()) - { - if(getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarId,this); - } - mAvatarId = id; - LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(),this); - } + if (avatar_id.notNull()) + { + if (getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarId, this); + } + mAvatarId = avatar_id; + LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); + + mSelfProfile = (getAvatarId() == gAgentID); + } } void LLPanelProfileTab::onOpen(const LLSD& key) { - // Don't reset panel if we are opening it for same avatar. - if(getAvatarId() != key.asUUID()) - { - resetControls(); - resetData(); - - scrollToTop(); - } - - // Update data even if we are viewing same avatar profile as some data might been changed. - setAvatarId(key.asUUID()); - updateData(); - updateButtons(); -} + // Update data even if we are viewing same avatar profile as some data might been changed. + setAvatarId(key.asUUID()); -void LLPanelProfileTab::scrollToTop() -{ - LLScrollContainer* scrollContainer = findChild("profile_scroll"); - if (scrollContainer) - scrollContainer->goToTop(); + setApplyProgress(true); } -void LLPanelProfileTab::onMapButtonClick() +void LLPanelProfileTab::updateButtons() { - LLAvatarActions::showOnMap(getAvatarId()); + setApplyProgress(false); + + mLoaded = true; } -void LLPanelProfileTab::updateButtons() +void LLPanelProfileTab::setApplyProgress(bool started) { - bool is_buddy_online = LLAvatarTracker::instance().isBuddyOnline(getAvatarId()); - - if(LLAvatarActions::isFriend(getAvatarId())) - { - getChildView("teleport")->setEnabled(is_buddy_online); - } - else - { - getChildView("teleport")->setEnabled(true); - } - - bool enable_map_btn = (is_buddy_online && - is_agent_mappable(getAvatarId())) - || gAgent.isGodlike(); - getChildView("show_on_map_btn")->setEnabled(enable_map_btn); + LLLoadingIndicator* indicator = findChild("progress_indicator"); + + if (indicator) + { + indicator->setVisible(started); + + if (started) + { + indicator->start(); + } + else + { + indicator->stop(); + } + } } diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index e33a850cfa..f73ea0643d 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -1,25 +1,25 @@ -/** +/** * @file llpanelavatar.h - * @brief LLPanelAvatar and related class definitions + * @brief Legacy profile panel base class * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * + * Copyright (C) 2019, 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$ */ @@ -29,80 +29,125 @@ #include "llpanel.h" #include "llavatarpropertiesprocessor.h" -#include "llcallingcard.h" -#include "llvoiceclient.h" #include "llavatarnamecache.h" class LLComboBox; class LLLineEditor; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLProfileDropTarget +// +// This handy class is a simple way to drop something on another +// view. It handles drop events, always setting itself to the size of +// its parent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLProfileDropTarget : public LLView +{ +public: + struct Params : public LLInitParam::Block + { + Optional agent_id; + Params() + : agent_id("agent_id") + { + changeDefault(mouse_opaque, false); + changeDefault(follows.flags, FOLLOWS_ALL); + } + }; + + LLProfileDropTarget(const Params&); + ~LLProfileDropTarget() {} + + void doDrop(EDragAndDropType cargo_type, void* cargo_data); + + // + // LLView functionality + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + + void setAgentID(const LLUUID &agent_id) { mAgentID = agent_id; } + +protected: + LLUUID mAgentID; +}; + + /** * Base class for any Profile View. */ class LLPanelProfileTab - : public LLPanel - , public LLAvatarPropertiesObserver + : public LLPanel + , public LLAvatarPropertiesObserver { public: - /** - * Sets avatar ID, sets panel as observer of avatar related info replies from server. - */ - virtual void setAvatarId(const LLUUID& id); - - /** - * Returns avatar ID. - */ - virtual const LLUUID& getAvatarId() { return mAvatarId; } - - /** - * Sends update data request to server. - */ - virtual void updateData() = 0; - - /** - * Clears panel data if viewing avatar info for first time and sends update data request. - */ - virtual void onOpen(const LLSD& key); - - /** - * Profile tabs should close any opened panels here. - * - * Called from LLPanelProfile::onOpen() before opening new profile. - * See LLPanelPicks::onClosePanel for example. LLPanelPicks closes picture info panel - * before new profile is displayed, otherwise new profile will - * be hidden behind picture info panel. - */ - virtual void onClosePanel() {} - - /** - * Resets controls visibility, state, etc. - */ - virtual void resetControls(){}; - - /** - * Clears all data received from server. - */ - virtual void resetData(){}; - - /*virtual*/ ~LLPanelProfileTab(); + /** + * Sets avatar ID, sets panel as observer of avatar related info replies from server. + */ + virtual void setAvatarId(const LLUUID& avatar_id); + + /** + * Returns avatar ID. + */ + virtual const LLUUID& getAvatarId() { return mAvatarId; } + + /** + * Sends update data request to server. + */ + virtual void updateData() {}; + + /** + * Clears panel data if viewing avatar info for first time and sends update data request. + */ + virtual void onOpen(const LLSD& key); + + /** + * Processes data received from server. + */ + virtual void processProperties(void* data, EAvatarProcessorType type) = 0; + + /** + * Clears all data received from server. + */ + virtual void resetData(){}; + + /*virtual*/ ~LLPanelProfileTab(); + + void setEmbedded(bool embedded) { mEmbedded = embedded; } protected: - LLPanelProfileTab(); + LLPanelProfileTab(); + + + // mLoading: false: Initial state, can request + // true: Data requested, skip duplicate requests (happens due to LLUI's habit of repeated callbacks) + // mLoaded: false: Initial state, show loading indicator + // true: Data recieved, which comes in a single message, hide indicator + bool getIsLoading() { return mLoading; } + void setIsLoading() { mLoading = true; } + bool getIsLoaded() { return mLoaded; } + void resetLoading() { mLoading = false; mLoaded = false; } + + const bool getEmbedded() const { return mEmbedded; } - /** - * Scrolls panel to top when viewing avatar info for first time. - */ - void scrollToTop(); + const bool getSelfProfile() const { return mSelfProfile; } - virtual void onMapButtonClick(); + void setApplyProgress(bool started); - virtual void updateButtons(); + virtual void updateButtons(); private: - LLUUID mAvatarId; + LLUUID mAvatarId; + bool mLoading; + bool mLoaded; + bool mEmbedded; + bool mSelfProfile; }; #endif // LL_LLPANELAVATAR_H diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp deleted file mode 100644 index b9b97f4cce..0000000000 --- a/indra/newview/llpanelclassified.cpp +++ /dev/null @@ -1,1178 +0,0 @@ -/** - * @file llpanelclassified.cpp - * @brief LLPanelClassified class implementation - * - * $LicenseInfo:firstyear=2005&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$ - */ - -// Display of a classified used both for the global view in the -// Find directory, and also for each individual user's classified in their -// profile. - -#include "llviewerprecompiledheaders.h" - -#include "llpanelclassified.h" - -#include "lldispatcher.h" -#include "llfloaterreg.h" -#include "llnotifications.h" -#include "llnotificationsutil.h" -#include "llparcel.h" - -#include "llagent.h" -#include "llclassifiedflags.h" -#include "llcommandhandler.h" // for classified HTML detail page click tracking -#include "lliconctrl.h" -#include "lllineeditor.h" -#include "llcombobox.h" -#include "lltexturectrl.h" -#include "lltexteditor.h" -#include "llviewerparcelmgr.h" -#include "llfloaterworldmap.h" -#include "llviewergenericmessage.h" // send_generic_message -#include "llviewerregion.h" -#include "llviewertexture.h" -#include "lltrans.h" -#include "llscrollcontainer.h" -#include "llstatusbar.h" -#include "llviewertexture.h" -#include "llcorehttputil.h" - -const S32 MINIMUM_PRICE_FOR_LISTING = 50; // L$ - -//static -LLPanelClassifiedInfo::panel_list_t LLPanelClassifiedInfo::sAllPanels; - -// "classifiedclickthrough" -// strings[0] = classified_id -// strings[1] = teleport_clicks -// strings[2] = map_clicks -// strings[3] = profile_clicks -class LLDispatchClassifiedClickThrough : public LLDispatchHandler -{ -public: - virtual bool operator()( - const LLDispatcher* dispatcher, - const std::string& key, - const LLUUID& invoice, - const sparam_t& strings) - { - if (strings.size() != 4) return false; - LLUUID classified_id(strings[0]); - S32 teleport_clicks = atoi(strings[1].c_str()); - S32 map_clicks = atoi(strings[2].c_str()); - S32 profile_clicks = atoi(strings[3].c_str()); - - LLPanelClassifiedInfo::setClickThrough( - classified_id, teleport_clicks, map_clicks, profile_clicks, false); - - return true; - } -}; -static LLDispatchClassifiedClickThrough sClassifiedClickThrough; - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -LLPanelClassifiedInfo::LLPanelClassifiedInfo() - : LLPanel() - , mInfoLoaded(false) - , mScrollingPanel(NULL) - , mScrollContainer(NULL) - , mScrollingPanelMinHeight(0) - , mScrollingPanelWidth(0) - , mSnapshotStreched(false) - , mTeleportClicksOld(0) - , mMapClicksOld(0) - , mProfileClicksOld(0) - , mTeleportClicksNew(0) - , mMapClicksNew(0) - , mProfileClicksNew(0) - , mSnapshotCtrl(NULL) -{ - sAllPanels.push_back(this); -} - -LLPanelClassifiedInfo::~LLPanelClassifiedInfo() -{ - sAllPanels.remove(this); -} - -// static -LLPanelClassifiedInfo* LLPanelClassifiedInfo::create() -{ - LLPanelClassifiedInfo* panel = new LLPanelClassifiedInfo(); - panel->buildFromFile("panel_classified_info.xml"); - return panel; -} - -BOOL LLPanelClassifiedInfo::postBuild() -{ - childSetAction("back_btn", boost::bind(&LLPanelClassifiedInfo::onExit, this)); - childSetAction("show_on_map_btn", boost::bind(&LLPanelClassifiedInfo::onMapClick, this)); - childSetAction("teleport_btn", boost::bind(&LLPanelClassifiedInfo::onTeleportClick, this)); - - mScrollingPanel = getChild("scroll_content_panel"); - mScrollContainer = getChild("profile_scroll"); - - mScrollingPanelMinHeight = mScrollContainer->getScrolledViewRect().getHeight(); - mScrollingPanelWidth = mScrollingPanel->getRect().getWidth(); - - mSnapshotCtrl = getChild("classified_snapshot"); - mSnapshotRect = getDefaultSnapshotRect(); - - return TRUE; -} - -void LLPanelClassifiedInfo::setExitCallback(const commit_callback_t& cb) -{ - getChild("back_btn")->setClickedCallback(cb); -} - -void LLPanelClassifiedInfo::setEditClassifiedCallback(const commit_callback_t& cb) -{ - getChild("edit_btn")->setClickedCallback(cb); -} - -void LLPanelClassifiedInfo::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) -{ - LLPanel::reshape(width, height, called_from_parent); - - if (!mScrollContainer || !mScrollingPanel) - return; - - static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); - - S32 scroll_height = mScrollContainer->getRect().getHeight(); - if (mScrollingPanelMinHeight >= scroll_height) - { - mScrollingPanel->reshape(mScrollingPanelWidth, mScrollingPanelMinHeight); - } - else - { - mScrollingPanel->reshape(mScrollingPanelWidth + scrollbar_size, scroll_height); - } - - mSnapshotRect = getDefaultSnapshotRect(); - stretchSnapshot(); -} - -void LLPanelClassifiedInfo::onOpen(const LLSD& key) -{ - LLUUID avatar_id = key["classified_creator_id"]; - if(avatar_id.isNull()) - { - return; - } - - if(getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); - } - - setAvatarId(avatar_id); - - resetData(); - resetControls(); - scrollToTop(); - - setClassifiedId(key["classified_id"]); - setClassifiedName(key["classified_name"]); - setDescription(key["classified_desc"]); - setSnapshotId(key["classified_snapshot_id"]); - setFromSearch(key["from_search"]); - - LL_INFOS() << "Opening classified [" << getClassifiedName() << "] (" << getClassifiedId() << ")" << LL_ENDL; - - LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); - LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId()); - gGenericDispatcher.addHandler("classifiedclickthrough", &sClassifiedClickThrough); - - if (gAgent.getRegion()) - { - // While we're at it let's get the stats from the new table if that - // capability exists. - std::string url = gAgent.getRegion()->getCapability("SearchStatRequest"); - if (!url.empty()) - { - LL_INFOS() << "Classified stat request via capability" << LL_ENDL; - LLSD body; - LLUUID classifiedId = getClassifiedId(); - body["classified_id"] = classifiedId; - LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body, - boost::bind(&LLPanelClassifiedInfo::handleSearchStatResponse, classifiedId, _1)); - } - } - // Update classified click stats. - // *TODO: Should we do this when opening not from search? - sendClickMessage("profile"); - - setInfoLoaded(false); -} - -/*static*/ -void LLPanelClassifiedInfo::handleSearchStatResponse(LLUUID classifiedId, LLSD result) -{ - S32 teleport = result["teleport_clicks"].asInteger(); - S32 map = result["map_clicks"].asInteger(); - S32 profile = result["profile_clicks"].asInteger(); - S32 search_teleport = result["search_teleport_clicks"].asInteger(); - S32 search_map = result["search_map_clicks"].asInteger(); - S32 search_profile = result["search_profile_clicks"].asInteger(); - - LLPanelClassifiedInfo::setClickThrough(classifiedId, - teleport + search_teleport, - map + search_map, - profile + search_profile, - true); -} - -void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType type) -{ - if(APT_CLASSIFIED_INFO == type) - { - LLAvatarClassifiedInfo* c_info = static_cast(data); - if(c_info && getClassifiedId() == c_info->classified_id) - { - setClassifiedName(c_info->name); - setDescription(c_info->description); - setSnapshotId(c_info->snapshot_id); - setParcelId(c_info->parcel_id); - setPosGlobal(c_info->pos_global); - setSimName(c_info->sim_name); - - setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); - getChild("category")->setValue(LLClassifiedInfo::sCategories[c_info->category]); - - static std::string mature_str = getString("type_mature"); - static std::string pg_str = getString("type_pg"); - static LLUIString price_str = getString("l$_price"); - static std::string date_fmt = getString("date_fmt"); - - bool mature = is_cf_mature(c_info->flags); - getChild("content_type")->setValue(mature ? mature_str : pg_str); - getChild("content_type_moderate")->setVisible(mature); - getChild("content_type_general")->setVisible(!mature); - - std::string auto_renew_str = is_cf_auto_renew(c_info->flags) ? - getString("auto_renew_on") : getString("auto_renew_off"); - getChild("auto_renew")->setValue(auto_renew_str); - - price_str.setArg("[PRICE]", llformat("%d", c_info->price_for_listing)); - getChild("price_for_listing")->setValue(LLSD(price_str)); - - std::string date_str = date_fmt; - LLStringUtil::format(date_str, LLSD().with("datetime", (S32) c_info->creation_date)); - getChild("creation_date")->setValue(date_str); - - setInfoLoaded(true); - } - } -} - -void LLPanelClassifiedInfo::resetData() -{ - setClassifiedName(LLStringUtil::null); - setDescription(LLStringUtil::null); - setClassifiedLocation(LLStringUtil::null); - setClassifiedId(LLUUID::null); - setSnapshotId(LLUUID::null); - setPosGlobal(LLVector3d::zero); - setParcelId(LLUUID::null); - setSimName(LLStringUtil::null); - setFromSearch(false); - - // reset click stats - mTeleportClicksOld = 0; - mMapClicksOld = 0; - mProfileClicksOld = 0; - mTeleportClicksNew = 0; - mMapClicksNew = 0; - mProfileClicksNew = 0; - - getChild("category")->setValue(LLStringUtil::null); - getChild("content_type")->setValue(LLStringUtil::null); - getChild("click_through_text")->setValue(LLStringUtil::null); - getChild("price_for_listing")->setValue(LLStringUtil::null); - getChild("auto_renew")->setValue(LLStringUtil::null); - getChild("creation_date")->setValue(LLStringUtil::null); - getChild("click_through_text")->setValue(LLStringUtil::null); - getChild("content_type_moderate")->setVisible(FALSE); - getChild("content_type_general")->setVisible(FALSE); -} - -void LLPanelClassifiedInfo::resetControls() -{ - bool is_self = getAvatarId() == gAgent.getID(); - - getChildView("edit_btn")->setEnabled(is_self); - getChildView("edit_btn")->setVisible( is_self); - getChildView("price_layout_panel")->setVisible( is_self); - getChildView("clickthrough_layout_panel")->setVisible( is_self); -} - -void LLPanelClassifiedInfo::setClassifiedName(const std::string& name) -{ - getChild("classified_name")->setValue(name); -} - -std::string LLPanelClassifiedInfo::getClassifiedName() -{ - return getChild("classified_name")->getValue().asString(); -} - -void LLPanelClassifiedInfo::setDescription(const std::string& desc) -{ - getChild("classified_desc")->setValue(desc); -} - -std::string LLPanelClassifiedInfo::getDescription() -{ - return getChild("classified_desc")->getValue().asString(); -} - -void LLPanelClassifiedInfo::setClassifiedLocation(const std::string& location) -{ - getChild("classified_location")->setValue(location); -} - -std::string LLPanelClassifiedInfo::getClassifiedLocation() -{ - return getChild("classified_location")->getValue().asString(); -} - -void LLPanelClassifiedInfo::setSnapshotId(const LLUUID& id) -{ - mSnapshotCtrl->setValue(id); - mSnapshotStreched = false; -} - -void LLPanelClassifiedInfo::draw() -{ - LLPanel::draw(); - - // Stretch in draw because it takes some time to load a texture, - // going to try to stretch snapshot until texture is loaded - if(!mSnapshotStreched) - { - stretchSnapshot(); - } -} - -LLUUID LLPanelClassifiedInfo::getSnapshotId() -{ - return getChild("classified_snapshot")->getValue().asUUID(); -} - -// static -void LLPanelClassifiedInfo::setClickThrough( - const LLUUID& classified_id, - S32 teleport, - S32 map, - S32 profile, - bool from_new_table) -{ - LL_INFOS() << "Click-through data for classified " << classified_id << " arrived: [" - << teleport << ", " << map << ", " << profile << "] (" - << (from_new_table ? "new" : "old") << ")" << LL_ENDL; - - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelClassifiedInfo* self = *iter; - if (self->getClassifiedId() != classified_id) - { - continue; - } - - // *HACK: Skip LLPanelClassifiedEdit instances: they don't display clicks data. - // Those instances should not be in the list at all. - if (typeid(*self) != typeid(LLPanelClassifiedInfo)) - { - continue; - } - - LL_INFOS() << "Updating classified info panel" << LL_ENDL; - - // We need to check to see if the data came from the new stat_table - // or the old classified table. We also need to cache the data from - // the two separate sources so as to display the aggregate totals. - - if (from_new_table) - { - self->mTeleportClicksNew = teleport; - self->mMapClicksNew = map; - self->mProfileClicksNew = profile; - } - else - { - self->mTeleportClicksOld = teleport; - self->mMapClicksOld = map; - self->mProfileClicksOld = profile; - } - - static LLUIString ct_str = self->getString("click_through_text_fmt"); - - ct_str.setArg("[TELEPORT]", llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld)); - ct_str.setArg("[MAP]", llformat("%d", self->mMapClicksNew + self->mMapClicksOld)); - ct_str.setArg("[PROFILE]", llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld)); - - self->getChild("click_through_text")->setValue(ct_str.getString()); - // *HACK: remove this when there is enough room for click stats in the info panel - self->getChildView("click_through_text")->setToolTip(ct_str.getString()); - - LL_INFOS() << "teleport: " << llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld) - << ", map: " << llformat("%d", self->mMapClicksNew + self->mMapClicksOld) - << ", profile: " << llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld) - << LL_ENDL; - } -} - -// static -std::string LLPanelClassifiedInfo::createLocationText( - const std::string& original_name, - const std::string& sim_name, - const LLVector3d& pos_global) -{ - std::string location_text; - - location_text.append(original_name); - - if (!sim_name.empty()) - { - if (!location_text.empty()) - location_text.append(", "); - location_text.append(sim_name); - } - - if (!location_text.empty()) - location_text.append(" "); - - if (!pos_global.isNull()) - { - S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS; - S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS; - S32 region_z = ll_round((F32)pos_global.mdV[VZ]); - location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); - } - - return location_text; -} - -void LLPanelClassifiedInfo::stretchSnapshot() -{ - // *NOTE dzaporozhan - // Could be moved to LLTextureCtrl - - LLViewerFetchedTexture* texture = mSnapshotCtrl->getTexture(); - - if(!texture) - { - return; - } - - if(0 == texture->getOriginalWidth() || 0 == texture->getOriginalHeight()) - { - // looks like texture is not loaded yet - return; - } - - LLRect rc = mSnapshotRect; - // *HACK dzaporozhan - // LLTextureCtrl uses BTN_HEIGHT_SMALL as bottom for texture which causes - // drawn texture to be smaller than expected. (see LLTextureCtrl::draw()) - // Lets increase texture height to force texture look as expected. - rc.mBottom -= BTN_HEIGHT_SMALL; - - F32 t_width = texture->getFullWidth(); - F32 t_height = texture->getFullHeight(); - - F32 ratio = llmin( (rc.getWidth() / t_width), (rc.getHeight() / t_height) ); - - t_width *= ratio; - t_height *= ratio; - - rc.setCenterAndSize(rc.getCenterX(), rc.getCenterY(), llfloor(t_width), llfloor(t_height)); - mSnapshotCtrl->setShape(rc); - - mSnapshotStreched = true; -} - -LLRect LLPanelClassifiedInfo::getDefaultSnapshotRect() -{ - // Using scroll container makes getting default rect a hard task - // because rect in postBuild() and in first reshape() is not the same. - // Using snapshot_panel makes it easier to reshape snapshot. - return getChild("snapshot_panel")->getLocalRect(); -} - -void LLPanelClassifiedInfo::scrollToTop() -{ - LLScrollContainer* scrollContainer = findChild("profile_scroll"); - if (scrollContainer) - scrollContainer->goToTop(); -} - -// static -// *TODO: move out of the panel -void LLPanelClassifiedInfo::sendClickMessage( - const std::string& type, - bool from_search, - const LLUUID& classified_id, - const LLUUID& parcel_id, - const LLVector3d& global_pos, - const std::string& sim_name) -{ - if (gAgent.getRegion()) - { - // You're allowed to click on your own ads to reassure yourself - // that the system is working. - LLSD body; - body["type"] = type; - body["from_search"] = from_search; - body["classified_id"] = classified_id; - body["parcel_id"] = parcel_id; - body["dest_pos_global"] = global_pos.getValue(); - body["region_name"] = sim_name; - - std::string url = gAgent.getRegion()->getCapability("SearchStatTracking"); - LL_INFOS() << "Sending click msg via capability (url=" << url << ")" << LL_ENDL; - LL_INFOS() << "body: [" << body << "]" << LL_ENDL; - LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, - "SearchStatTracking Click report sent.", "SearchStatTracking Click report NOT sent."); - } -} - -void LLPanelClassifiedInfo::sendClickMessage(const std::string& type) -{ - sendClickMessage( - type, - fromSearch(), - getClassifiedId(), - getParcelId(), - getPosGlobal(), - getSimName()); -} - -void LLPanelClassifiedInfo::onMapClick() -{ - sendClickMessage("map"); - LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); - LLFloaterReg::showInstance("world_map", "center"); -} - -void LLPanelClassifiedInfo::onTeleportClick() -{ - if (!getPosGlobal().isExactlyZero()) - { - sendClickMessage("teleport"); - gAgent.teleportViaLocation(getPosGlobal()); - LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); - } -} - -void LLPanelClassifiedInfo::onExit() -{ - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); - gGenericDispatcher.addHandler("classifiedclickthrough", NULL); // deregister our handler -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -static const S32 CB_ITEM_MATURE = 0; -static const S32 CB_ITEM_PG = 1; - -LLPanelClassifiedEdit::LLPanelClassifiedEdit() - : LLPanelClassifiedInfo() - , mIsNew(false) - , mIsNewWithErrors(false) - , mCanClose(false) - , mPublishFloater(NULL) -{ -} - -LLPanelClassifiedEdit::~LLPanelClassifiedEdit() -{ -} - -//static -LLPanelClassifiedEdit* LLPanelClassifiedEdit::create() -{ - LLPanelClassifiedEdit* panel = new LLPanelClassifiedEdit(); - panel->buildFromFile("panel_edit_classified.xml"); - return panel; -} - -BOOL LLPanelClassifiedEdit::postBuild() -{ - LLPanelClassifiedInfo::postBuild(); - - LLTextureCtrl* snapshot = getChild("classified_snapshot"); - snapshot->setOnSelectCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this)); - - LLUICtrl* edit_icon = getChild("edit_icon"); - snapshot->setMouseEnterCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseEnter, this, edit_icon)); - snapshot->setMouseLeaveCallback(boost::bind(&LLPanelClassifiedEdit::onTexturePickerMouseLeave, this, edit_icon)); - edit_icon->setVisible(false); - - LLLineEditor* line_edit = getChild("classified_name"); - line_edit->setKeystrokeCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL); - - LLTextEditor* text_edit = getChild("classified_desc"); - text_edit->setKeystrokeCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this)); - - LLComboBox* combobox = getChild( "category"); - LLClassifiedInfo::cat_map::iterator iter; - for (iter = LLClassifiedInfo::sCategories.begin(); - iter != LLClassifiedInfo::sCategories.end(); - iter++) - { - combobox->add(LLTrans::getString(iter->second)); - } - - combobox->setCommitCallback(boost::bind(&LLPanelClassifiedEdit::onChange, this)); - - childSetCommitCallback("content_type", boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL); - childSetCommitCallback("price_for_listing", boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL); - childSetCommitCallback("auto_renew", boost::bind(&LLPanelClassifiedEdit::onChange, this), NULL); - - childSetAction("save_changes_btn", boost::bind(&LLPanelClassifiedEdit::onSaveClick, this)); - childSetAction("set_to_curr_location_btn", boost::bind(&LLPanelClassifiedEdit::onSetLocationClick, this)); - - mSnapshotCtrl->setOnSelectCallback(boost::bind(&LLPanelClassifiedEdit::onTextureSelected, this)); - - return TRUE; -} - -void LLPanelClassifiedEdit::fillIn(const LLSD& key) -{ - setAvatarId(gAgent.getID()); - - if(key.isUndefined()) - { - setPosGlobal(gAgent.getPositionGlobal()); - - LLUUID snapshot_id = LLUUID::null; - std::string desc; - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - - if(parcel) - { - desc = parcel->getDesc(); - snapshot_id = parcel->getSnapshotID(); - } - - std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish"); - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - region_name = region->getName(); - } - - getChild("classified_name")->setValue(makeClassifiedName()); - getChild("classified_desc")->setValue(desc); - setSnapshotId(snapshot_id); - setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal())); - // server will set valid parcel id - setParcelId(LLUUID::null); - } - else - { - setClassifiedId(key["classified_id"]); - setClassifiedName(key["name"]); - setDescription(key["desc"]); - setSnapshotId(key["snapshot_id"]); - setCategory((U32)key["category"].asInteger()); - setContentType((U32)key["content_type"].asInteger()); - setClassifiedLocation(key["location_text"]); - getChild("auto_renew")->setValue(key["auto_renew"]); - getChild("price_for_listing")->setValue(key["price_for_listing"].asInteger()); - } -} - -void LLPanelClassifiedEdit::onOpen(const LLSD& key) -{ - mIsNew = key.isUndefined(); - - scrollToTop(); - - // classified is not created yet - bool is_new = isNew() || isNewWithErrors(); - - if(is_new) - { - resetData(); - resetControls(); - - fillIn(key); - - if(isNew()) - { - LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); - } - } - else - { - LLPanelClassifiedInfo::onOpen(key); - } - - std::string save_btn_label = is_new ? getString("publish_label") : getString("save_label"); - getChild("save_changes_btn")->setLabelArg("[LABEL]", save_btn_label); - - enableVerbs(is_new); - enableEditing(is_new); - showEditing(!is_new); - resetDirty(); - setInfoLoaded(false); -} - -void LLPanelClassifiedEdit::processProperties(void* data, EAvatarProcessorType type) -{ - if(APT_CLASSIFIED_INFO == type) - { - LLAvatarClassifiedInfo* c_info = static_cast(data); - if(c_info && getClassifiedId() == c_info->classified_id) - { - // see LLPanelClassifiedEdit::sendUpdate() for notes - mIsNewWithErrors = false; - // for just created classified - panel will probably be closed when we get here. - if(!getVisible()) - { - return; - } - - enableEditing(true); - - setClassifiedName(c_info->name); - setDescription(c_info->description); - setSnapshotId(c_info->snapshot_id); - setPosGlobal(c_info->pos_global); - - setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); - // *HACK see LLPanelClassifiedEdit::sendUpdate() - setCategory(c_info->category - 1); - - bool mature = is_cf_mature(c_info->flags); - bool auto_renew = is_cf_auto_renew(c_info->flags); - - setContentType(mature ? CB_ITEM_MATURE : CB_ITEM_PG); - getChild("auto_renew")->setValue(auto_renew); - getChild("price_for_listing")->setValue(c_info->price_for_listing); - getChildView("price_for_listing")->setEnabled(isNew()); - - resetDirty(); - setInfoLoaded(true); - enableVerbs(false); - - // for just created classified - in case user opened edit panel before processProperties() callback - getChild("save_changes_btn")->setLabelArg("[LABEL]", getString("save_label")); - } - } -} - -BOOL LLPanelClassifiedEdit::isDirty() const -{ - if(mIsNew) - { - return TRUE; - } - - BOOL dirty = false; - - dirty |= LLPanelClassifiedInfo::isDirty(); - dirty |= getChild("classified_snapshot")->isDirty(); - dirty |= getChild("classified_name")->isDirty(); - dirty |= getChild("classified_desc")->isDirty(); - dirty |= getChild("category")->isDirty(); - dirty |= getChild("content_type")->isDirty(); - dirty |= getChild("auto_renew")->isDirty(); - dirty |= getChild("price_for_listing")->isDirty(); - - return dirty; -} - -void LLPanelClassifiedEdit::resetDirty() -{ - LLPanelClassifiedInfo::resetDirty(); - getChild("classified_snapshot")->resetDirty(); - getChild("classified_name")->resetDirty(); - - LLTextEditor* desc = getChild("classified_desc"); - // call blockUndo() to really reset dirty(and make isDirty work as intended) - desc->blockUndo(); - desc->resetDirty(); - - getChild("category")->resetDirty(); - getChild("content_type")->resetDirty(); - getChild("auto_renew")->resetDirty(); - getChild("price_for_listing")->resetDirty(); -} - -void LLPanelClassifiedEdit::setSaveCallback(const commit_signal_t::slot_type& cb) -{ - mSaveButtonClickedSignal.connect(cb); -} - -void LLPanelClassifiedEdit::setCancelCallback(const commit_signal_t::slot_type& cb) -{ - getChild("cancel_btn")->setClickedCallback(cb); -} - -void LLPanelClassifiedEdit::resetControls() -{ - LLPanelClassifiedInfo::resetControls(); - - getChild("category")->setCurrentByIndex(0); - getChild("content_type")->setCurrentByIndex(0); - getChild("auto_renew")->setValue(false); - getChild("price_for_listing")->setValue(MINIMUM_PRICE_FOR_LISTING); - getChildView("price_for_listing")->setEnabled(TRUE); -} - -bool LLPanelClassifiedEdit::canClose() -{ - return mCanClose; -} - -void LLPanelClassifiedEdit::draw() -{ - LLPanel::draw(); - - // Need to re-stretch on every draw because LLTextureCtrl::onSelectCallback - // does not trigger callbacks when user navigates through images. - stretchSnapshot(); -} - -void LLPanelClassifiedEdit::stretchSnapshot() -{ - LLPanelClassifiedInfo::stretchSnapshot(); - - getChild("edit_icon")->setShape(mSnapshotCtrl->getRect()); -} - -U32 LLPanelClassifiedEdit::getContentType() -{ - LLComboBox* ct_cb = getChild("content_type"); - return ct_cb->getCurrentIndex(); -} - -void LLPanelClassifiedEdit::setContentType(U32 content_type) -{ - LLComboBox* ct_cb = getChild("content_type"); - ct_cb->setCurrentByIndex(content_type); - ct_cb->resetDirty(); -} - -bool LLPanelClassifiedEdit::getAutoRenew() -{ - return getChild("auto_renew")->getValue().asBoolean(); -} - -void LLPanelClassifiedEdit::sendUpdate() -{ - LLAvatarClassifiedInfo c_data; - - if(getClassifiedId().isNull()) - { - setClassifiedId(LLUUID::generateNewID()); - } - - c_data.agent_id = gAgent.getID(); - c_data.classified_id = getClassifiedId(); - // *HACK - // Categories on server start with 1 while combo-box index starts with 0 - c_data.category = getCategory() + 1; - c_data.name = getClassifiedName(); - c_data.description = getDescription(); - c_data.parcel_id = getParcelId(); - c_data.snapshot_id = getSnapshotId(); - c_data.pos_global = getPosGlobal(); - c_data.flags = getFlags(); - c_data.price_for_listing = getPriceForListing(); - - LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoUpdate(&c_data); - - if(isNew()) - { - // Lets assume there will be some error. - // Successful sendClassifiedInfoUpdate will trigger processProperties and - // let us know there was no error. - mIsNewWithErrors = true; - } -} - -U32 LLPanelClassifiedEdit::getCategory() -{ - LLComboBox* cat_cb = getChild("category"); - return cat_cb->getCurrentIndex(); -} - -void LLPanelClassifiedEdit::setCategory(U32 category) -{ - LLComboBox* cat_cb = getChild("category"); - cat_cb->setCurrentByIndex(category); - cat_cb->resetDirty(); -} - -U8 LLPanelClassifiedEdit::getFlags() -{ - bool auto_renew = getChild("auto_renew")->getValue().asBoolean(); - - LLComboBox* content_cb = getChild("content_type"); - bool mature = content_cb->getCurrentIndex() == CB_ITEM_MATURE; - - return pack_classified_flags_request(auto_renew, false, mature, false); -} - -void LLPanelClassifiedEdit::enableVerbs(bool enable) -{ - getChildView("save_changes_btn")->setEnabled(enable); -} - -void LLPanelClassifiedEdit::enableEditing(bool enable) -{ - getChildView("classified_snapshot")->setEnabled(enable); - getChildView("classified_name")->setEnabled(enable); - getChildView("classified_desc")->setEnabled(enable); - getChildView("set_to_curr_location_btn")->setEnabled(enable); - getChildView("category")->setEnabled(enable); - getChildView("content_type")->setEnabled(enable); - getChildView("price_for_listing")->setEnabled(enable); - getChildView("auto_renew")->setEnabled(enable); -} - -void LLPanelClassifiedEdit::showEditing(bool show) -{ - getChildView("price_for_listing_label")->setVisible( show); - getChildView("price_for_listing")->setVisible( show); -} - -std::string LLPanelClassifiedEdit::makeClassifiedName() -{ - std::string name; - - LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if(parcel) - { - name = parcel->getName(); - } - - if(!name.empty()) - { - return name; - } - - LLViewerRegion* region = gAgent.getRegion(); - if(region) - { - name = region->getName(); - } - - return name; -} - -S32 LLPanelClassifiedEdit::getPriceForListing() -{ - return getChild("price_for_listing")->getValue().asInteger(); -} - -void LLPanelClassifiedEdit::setPriceForListing(S32 price) -{ - getChild("price_for_listing")->setValue(price); -} - -void LLPanelClassifiedEdit::onSetLocationClick() -{ - setPosGlobal(gAgent.getPositionGlobal()); - setParcelId(LLUUID::null); - - std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish"); - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - region_name = region->getName(); - } - - setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal())); - - // mark classified as dirty - setValue(LLSD()); - - onChange(); -} - -void LLPanelClassifiedEdit::onChange() -{ - enableVerbs(isDirty()); -} - -void LLPanelClassifiedEdit::onSaveClick() -{ - mCanClose = false; - - if(!isValidName()) - { - notifyInvalidName(); - return; - } - if(isNew() || isNewWithErrors()) - { - if(gStatusBar->getBalance() < getPriceForListing()) - { - LLNotificationsUtil::add("ClassifiedInsufficientFunds"); - return; - } - - mPublishFloater = LLFloaterReg::findTypedInstance( - "publish_classified", LLSD()); - - if(!mPublishFloater) - { - mPublishFloater = LLFloaterReg::getTypedInstance( - "publish_classified", LLSD()); - - mPublishFloater->setPublishClickedCallback(boost::bind - (&LLPanelClassifiedEdit::onPublishFloaterPublishClicked, this)); - } - - // set spinner value before it has focus or value wont be set - mPublishFloater->setPrice(getPriceForListing()); - mPublishFloater->openFloater(mPublishFloater->getKey()); - mPublishFloater->center(); - } - else - { - doSave(); - } -} - -void LLPanelClassifiedEdit::doSave() -{ - mCanClose = true; - sendUpdate(); - resetDirty(); - - mSaveButtonClickedSignal(this, LLSD()); -} - -void LLPanelClassifiedEdit::onPublishFloaterPublishClicked() -{ - setPriceForListing(mPublishFloater->getPrice()); - - doSave(); -} - -std::string LLPanelClassifiedEdit::getLocationNotice() -{ - static std::string location_notice = getString("location_notice"); - return location_notice; -} - -bool LLPanelClassifiedEdit::isValidName() -{ - std::string name = getClassifiedName(); - if (name.empty()) - { - return false; - } - if (!isalnum(name[0])) - { - return false; - } - - return true; -} - -void LLPanelClassifiedEdit::notifyInvalidName() -{ - std::string name = getClassifiedName(); - if (name.empty()) - { - LLNotificationsUtil::add("BlankClassifiedName"); - } - else if (!isalnum(name[0])) - { - LLNotificationsUtil::add("ClassifiedMustBeAlphanumeric"); - } -} - -void LLPanelClassifiedEdit::onTexturePickerMouseEnter(LLUICtrl* ctrl) -{ - ctrl->setVisible(TRUE); -} - -void LLPanelClassifiedEdit::onTexturePickerMouseLeave(LLUICtrl* ctrl) -{ - ctrl->setVisible(FALSE); -} - -void LLPanelClassifiedEdit::onTextureSelected() -{ - setSnapshotId(mSnapshotCtrl->getValue().asUUID()); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -LLPublishClassifiedFloater::LLPublishClassifiedFloater(const LLSD& key) - : LLFloater(key) -{ -} - -LLPublishClassifiedFloater::~LLPublishClassifiedFloater() -{ -} - -BOOL LLPublishClassifiedFloater::postBuild() -{ - LLFloater::postBuild(); - - childSetAction("publish_btn", boost::bind(&LLFloater::closeFloater, this, false)); - childSetAction("cancel_btn", boost::bind(&LLFloater::closeFloater, this, false)); - - return TRUE; -} - -void LLPublishClassifiedFloater::setPrice(S32 price) -{ - getChild("price_for_listing")->setValue(price); -} - -S32 LLPublishClassifiedFloater::getPrice() -{ - return getChild("price_for_listing")->getValue().asInteger(); -} - -void LLPublishClassifiedFloater::setPublishClickedCallback(const commit_signal_t::slot_type& cb) -{ - getChild("publish_btn")->setClickedCallback(cb); -} - -void LLPublishClassifiedFloater::setCancelClickedCallback(const commit_signal_t::slot_type& cb) -{ - getChild("cancel_btn")->setClickedCallback(cb); -} - -//EOF diff --git a/indra/newview/llpanelclassified.h b/indra/newview/llpanelclassified.h deleted file mode 100644 index b292782615..0000000000 --- a/indra/newview/llpanelclassified.h +++ /dev/null @@ -1,301 +0,0 @@ -/** - * @file llpanelclassified.h - * @brief LLPanelClassified class definition - * - * $LicenseInfo:firstyear=2005&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$ - */ - -// Display of a classified used both for the global view in the -// Find directory, and also for each individual user's classified in their -// profile. -#ifndef LL_LLPANELCLASSIFIED_H -#define LL_LLPANELCLASSIFIED_H - -#include "llavatarpropertiesprocessor.h" -#include "llclassifiedinfo.h" -#include "llfloater.h" -#include "llpanel.h" -#include "llrect.h" -#include "lluuid.h" -#include "v3dmath.h" -#include "llcoros.h" -#include "lleventcoro.h" - -class LLScrollContainer; -class LLTextureCtrl; -class LLUICtrl; - -class LLPublishClassifiedFloater : public LLFloater -{ -public: - LLPublishClassifiedFloater(const LLSD& key); - virtual ~LLPublishClassifiedFloater(); - - /*virtual*/ BOOL postBuild(); - - void setPrice(S32 price); - S32 getPrice(); - - void setPublishClickedCallback(const commit_signal_t::slot_type& cb); - void setCancelClickedCallback(const commit_signal_t::slot_type& cb); - -private: -}; - -class LLPanelClassifiedInfo : public LLPanel, public LLAvatarPropertiesObserver -{ - LOG_CLASS(LLPanelClassifiedInfo); -public: - - static LLPanelClassifiedInfo* create(); - - virtual ~LLPanelClassifiedInfo(); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; } - - LLUUID& getAvatarId() { return mAvatarId; } - - void setSnapshotId(const LLUUID& id); - - LLUUID getSnapshotId(); - - void setClassifiedId(const LLUUID& id) { mClassifiedId = id; } - - LLUUID& getClassifiedId() { return mClassifiedId; } - - void setClassifiedName(const std::string& name); - - std::string getClassifiedName(); - - void setDescription(const std::string& desc); - - std::string getDescription(); - - void setClassifiedLocation(const std::string& location); - - std::string getClassifiedLocation(); - - void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; } - - LLVector3d& getPosGlobal() { return mPosGlobal; } - - void setParcelId(const LLUUID& id) { mParcelId = id; } - - LLUUID getParcelId() { return mParcelId; } - - void setSimName(const std::string& sim_name) { mSimName = sim_name; } - - std::string getSimName() { return mSimName; } - - void setFromSearch(bool val) { mFromSearch = val; } - - bool fromSearch() { return mFromSearch; } - - bool getInfoLoaded() { return mInfoLoaded; } - - void setInfoLoaded(bool loaded) { mInfoLoaded = loaded; } - - static void setClickThrough( - const LLUUID& classified_id, - S32 teleport, - S32 map, - S32 profile, - bool from_new_table); - - static void sendClickMessage( - const std::string& type, - bool from_search, - const LLUUID& classified_id, - const LLUUID& parcel_id, - const LLVector3d& global_pos, - const std::string& sim_name); - - void setExitCallback(const commit_callback_t& cb); - - void setEditClassifiedCallback(const commit_callback_t& cb); - - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - - /*virtual*/ void draw(); - -protected: - - LLPanelClassifiedInfo(); - - virtual void resetData(); - - virtual void resetControls(); - - static std::string createLocationText( - const std::string& original_name, - const std::string& sim_name, - const LLVector3d& pos_global); - - void stretchSnapshot(); - void sendClickMessage(const std::string& type); - - LLRect getDefaultSnapshotRect(); - - void scrollToTop(); - - void onMapClick(); - void onTeleportClick(); - void onExit(); - - bool mSnapshotStreched; - LLRect mSnapshotRect; - LLTextureCtrl* mSnapshotCtrl; - -private: - - LLUUID mAvatarId; - LLUUID mClassifiedId; - LLVector3d mPosGlobal; - LLUUID mParcelId; - std::string mSimName; - bool mFromSearch; - bool mInfoLoaded; - - LLScrollContainer* mScrollContainer; - LLPanel* mScrollingPanel; - - S32 mScrollingPanelMinHeight; - S32 mScrollingPanelWidth; - - // Needed for stat tracking - S32 mTeleportClicksOld; - S32 mMapClicksOld; - S32 mProfileClicksOld; - S32 mTeleportClicksNew; - S32 mMapClicksNew; - S32 mProfileClicksNew; - - static void handleSearchStatResponse(LLUUID classifiedId, LLSD result); - - - typedef std::list panel_list_t; - static panel_list_t sAllPanels; -}; - -class LLPanelClassifiedEdit : public LLPanelClassifiedInfo -{ - LOG_CLASS(LLPanelClassifiedEdit); -public: - - static LLPanelClassifiedEdit* create(); - - virtual ~LLPanelClassifiedEdit(); - - /*virtual*/ BOOL postBuild(); - - void fillIn(const LLSD& key); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - /*virtual*/ BOOL isDirty() const; - - /*virtual*/ void resetDirty(); - - void setSaveCallback(const commit_signal_t::slot_type& cb); - - void setCancelCallback(const commit_signal_t::slot_type& cb); - - /*virtual*/ void resetControls(); - - bool isNew() { return mIsNew; } - - bool isNewWithErrors() { return mIsNewWithErrors; } - - bool canClose(); - - void draw(); - - void stretchSnapshot(); - - U32 getCategory(); - - void setCategory(U32 category); - - U32 getContentType(); - - void setContentType(U32 content_type); - - bool getAutoRenew(); - - S32 getPriceForListing(); - -protected: - - LLPanelClassifiedEdit(); - - void sendUpdate(); - - void enableVerbs(bool enable); - - void enableEditing(bool enable); - - void showEditing(bool show); - - std::string makeClassifiedName(); - - void setPriceForListing(S32 price); - - U8 getFlags(); - - std::string getLocationNotice(); - - bool isValidName(); - - void notifyInvalidName(); - - void onSetLocationClick(); - void onChange(); - void onSaveClick(); - - void doSave(); - - void onPublishFloaterPublishClicked(); - - void onTexturePickerMouseEnter(LLUICtrl* ctrl); - void onTexturePickerMouseLeave(LLUICtrl* ctrl); - - void onTextureSelected(); - -private: - bool mIsNew; - bool mIsNewWithErrors; - bool mCanClose; - - LLPublishClassifiedFloater* mPublishFloater; - - commit_signal_t mSaveButtonClickedSignal; -}; - -#endif // LL_LLPANELCLASSIFIED_H diff --git a/indra/newview/llpanelexperiences.h b/indra/newview/llpanelexperiences.h index f29fdfdecb..0ce48ca118 100644 --- a/indra/newview/llpanelexperiences.h +++ b/indra/newview/llpanelexperiences.h @@ -29,7 +29,6 @@ #include "llaccordionctrltab.h" #include "llflatlistview.h" -#include "llpanelavatar.h" class LLExperienceItem; class LLPanelProfile; diff --git a/indra/newview/llpanelme.cpp b/indra/newview/llpanelme.cpp deleted file mode 100644 index cedd3025fc..0000000000 --- a/indra/newview/llpanelme.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file llpanelme.cpp - * @brief Side tray "Me" (My Profile) panel - * - * $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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llpanelme.h" - -// Viewer includes -#include "llpanelprofile.h" -#include "llagent.h" -#include "llagentcamera.h" -#include "llagentwearables.h" -#include "llfirstuse.h" -#include "llfloaterreg.h" -#include "llhints.h" -#include "llviewercontrol.h" -#include "llviewerdisplayname.h" - -// Linden libraries -#include "llavatarnamecache.h" // IDEVO -#include "lliconctrl.h" -#include "llnotifications.h" -#include "llnotificationsutil.h" // IDEVO -#include "lltabcontainer.h" -#include "lltexturectrl.h" - -static LLPanelInjector t_panel_me_profile("panel_me"); - -LLPanelMe::LLPanelMe(void) - : LLPanelProfile() -{ - setAvatarId(gAgent.getID()); -} - -BOOL LLPanelMe::postBuild() -{ - LLPanelProfile::postBuild(); - - return TRUE; -} - -void LLPanelMe::onOpen(const LLSD& key) -{ - LLPanelProfile::onOpen(key); -} diff --git a/indra/newview/llpanelme.h b/indra/newview/llpanelme.h deleted file mode 100644 index 60e9d4317d..0000000000 --- a/indra/newview/llpanelme.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @file llpanelme.h - * @brief Side tray "Me" (My Profile) panel - * - * $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$ - */ - -#ifndef LL_LLPANELMEPROFILE_H -#define LL_LLPANELMEPROFILE_H - -#include "llpanel.h" -#include "llpanelprofile.h" - -/** -* Panel for displaying Agent's Picks and Classifieds panel. -* LLPanelMe allows user to edit his picks and classifieds. -*/ -class LLPanelMe : public LLPanelProfile -{ - LOG_CLASS(LLPanelMe); - -public: - - LLPanelMe(); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ BOOL postBuild(); -}; - -#endif // LL_LLPANELMEPROFILE_H diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp deleted file mode 100644 index 77bc99da83..0000000000 --- a/indra/newview/llpanelpicks.cpp +++ /dev/null @@ -1,1454 +0,0 @@ -/** - * @file llpanelpicks.cpp - * @brief LLPanelPicks and related class implementations - * - * $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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llpanelpicks.h" - -#include "llagent.h" -#include "llagentpicksinfo.h" -#include "llcommandhandler.h" -#include "lldispatcher.h" -#include "llflatlistview.h" -#include "llfloaterreg.h" -#include "llfloatersidepanelcontainer.h" -#include "llfloaterworldmap.h" -#include "llnotificationsutil.h" -#include "lltexturectrl.h" -#include "lltoggleablemenu.h" -#include "lltrans.h" -#include "llviewergenericmessage.h" // send_generic_message -#include "llmenugl.h" -#include "llviewermenu.h" -#include "llregistry.h" - -#include "llaccordionctrl.h" -#include "llaccordionctrltab.h" -#include "llavatarpropertiesprocessor.h" -#include "llfloatersidepanelcontainer.h" -#include "llpanelavatar.h" -#include "llpanelprofile.h" -#include "llpanelpick.h" -#include "llpanelclassified.h" - -static const std::string XML_BTN_NEW = "new_btn"; -static const std::string XML_BTN_DELETE = "trash_btn"; -static const std::string XML_BTN_INFO = "info_btn"; -static const std::string XML_BTN_TELEPORT = "teleport_btn"; -static const std::string XML_BTN_SHOW_ON_MAP = "show_on_map_btn"; - -static const std::string PICK_ID("pick_id"); -static const std::string PICK_CREATOR_ID("pick_creator_id"); -static const std::string PICK_NAME("pick_name"); - -static const std::string CLASSIFIED_ID("classified_id"); -static const std::string CLASSIFIED_NAME("classified_name"); - - -static LLPanelInjector t_panel_picks("panel_picks"); - - -class LLPickHandler : public LLCommandHandler, - public LLAvatarPropertiesObserver -{ -public: - - std::set mPickIds; - - // requires trusted browser to trigger - LLPickHandler() : LLCommandHandler("pick", UNTRUSTED_THROTTLE) { } - - bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) - { - if (!LLUI::sSettingGroups["config"]->getBOOL("EnablePicks")) - { - LLNotificationsUtil::add("NoPicks", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); - return true; - } - - // handle app/classified/create urls first - if (params.size() == 1 && params[0].asString() == "create") - { - createPick(); - return true; - } - - // then handle the general app/pick/{UUID}/{CMD} urls - if (params.size() < 2) - { - return false; - } - - // get the ID for the pick_id - LLUUID pick_id; - if (!pick_id.set(params[0], FALSE)) - { - return false; - } - - // edit the pick in the side tray. - // need to ask the server for more info first though... - const std::string verb = params[1].asString(); - if (verb == "edit") - { - mPickIds.insert(pick_id); - LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this); - LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest(gAgent.getID(),pick_id); - return true; - } - else - { - LL_WARNS() << "unknown verb " << verb << LL_ENDL; - return false; - } - } - - void createPick() - { - // open the new pick panel on the Picks floater - LLFloater* picks_floater = LLFloaterReg::showInstance("picks"); - - LLPanelPicks* picks = picks_floater->findChild("panel_picks"); - if (picks) - { - picks->createNewPick(); - } - } - - void editPick(LLPickData* pick_info) - { - LLSD params; - params["open_tab_name"] = "panel_picks"; - params["show_tab_panel"] = "edit_pick"; - params["pick_id"] = pick_info->pick_id; - params["avatar_id"] = pick_info->creator_id; - params["snapshot_id"] = pick_info->snapshot_id; - params["pick_name"] = pick_info->name; - params["pick_desc"] = pick_info->desc; - LLFloaterSidePanelContainer::showPanel("picks", params); - } - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type) - { - if (APT_PICK_INFO != type) - { - return; - } - - // is this the pick that we asked for? - LLPickData* pick_info = static_cast(data); - if (!pick_info || mPickIds.find(pick_info->pick_id) == mPickIds.end()) - { - return; - } - - // open the edit side tray for this pick - if (pick_info->creator_id == gAgent.getID()) - { - editPick(pick_info); - } - else - { - LL_WARNS() << "Can't edit a pick you did not create" << LL_ENDL; - } - - // remove our observer now that we're done - mPickIds.erase(pick_info->pick_id); - LLAvatarPropertiesProcessor::getInstance()->removeObserver(LLUUID(), this); - } -}; - -LLPickHandler gPickHandler; - -class LLClassifiedHandler : - public LLCommandHandler, - public LLAvatarPropertiesObserver -{ -public: - // throttle calls from untrusted browsers - LLClassifiedHandler() : LLCommandHandler("classified", UNTRUSTED_THROTTLE) {} - - std::set mClassifiedIds; - - std::string mRequestVerb; - - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) - { - if (!LLUI::sSettingGroups["config"]->getBOOL("EnableClassifieds")) - { - LLNotificationsUtil::add("NoClassifieds", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); - return true; - } - - // handle app/classified/create urls first - if (params.size() == 1 && params[0].asString() == "create") - { - createClassified(); - return true; - } - - // then handle the general app/classified/{UUID}/{CMD} urls - if (params.size() < 2) - { - return false; - } - - // get the ID for the classified - LLUUID classified_id; - if (!classified_id.set(params[0], FALSE)) - { - return false; - } - - // show the classified in the side tray. - // need to ask the server for more info first though... - const std::string verb = params[1].asString(); - if (verb == "about") - { - mRequestVerb = verb; - mClassifiedIds.insert(classified_id); - LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this); - LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(classified_id); - return true; - } - else if (verb == "edit") - { - mRequestVerb = verb; - mClassifiedIds.insert(classified_id); - LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this); - LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(classified_id); - return true; - } - - return false; - } - - void createClassified() - { - // open the new classified panel on the Picks floater - LLFloater* picks_floater = LLFloaterReg::showInstance("picks"); - - LLPanelPicks* picks = picks_floater->findChild("panel_picks"); - if (picks) - { - picks->createNewClassified(); - } - } - - void openClassified(LLAvatarClassifiedInfo* c_info) - { - if (mRequestVerb == "about") - { - // open the classified info panel on the Me > Picks sidetray - LLSD params; - params["id"] = c_info->creator_id; - params["open_tab_name"] = "panel_picks"; - params["show_tab_panel"] = "classified_details"; - params["classified_id"] = c_info->classified_id; - params["classified_creator_id"] = c_info->creator_id; - params["classified_snapshot_id"] = c_info->snapshot_id; - params["classified_name"] = c_info->name; - params["classified_desc"] = c_info->description; - params["from_search"] = true; - LLFloaterSidePanelContainer::showPanel("picks", params); - } - else if (mRequestVerb == "edit") - { - if (c_info->creator_id == gAgent.getID()) - { - LL_WARNS() << "edit in progress" << LL_ENDL; - // open the new classified panel on the Me > Picks sidetray - LLSD params; - params["id"] = gAgent.getID(); - params["open_tab_name"] = "panel_picks"; - params["show_tab_panel"] = "edit_classified"; - params["classified_id"] = c_info->classified_id; - LLFloaterSidePanelContainer::showPanel("my_profile", params); - } - else - { - LL_WARNS() << "Can't edit a classified you did not create" << LL_ENDL; - } - } - } - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type) - { - if (APT_CLASSIFIED_INFO != type) - { - return; - } - - // is this the classified that we asked for? - LLAvatarClassifiedInfo* c_info = static_cast(data); - if (!c_info || mClassifiedIds.find(c_info->classified_id) == mClassifiedIds.end()) - { - return; - } - - // open the detail side tray for this classified - openClassified(c_info); - - // remove our observer now that we're done - mClassifiedIds.erase(c_info->classified_id); - LLAvatarPropertiesProcessor::getInstance()->removeObserver(LLUUID(), this); - } - -}; -LLClassifiedHandler gClassifiedHandler; - -////////////////////////////////////////////////////////////////////////// - - -//----------------------------------------------------------------------------- -// LLPanelPicks -//----------------------------------------------------------------------------- -LLPanelPicks::LLPanelPicks() -: LLPanelProfileTab(), - mPopupMenu(NULL), - mProfilePanel(NULL), - mPickPanel(NULL), - mPicksList(NULL), - mClassifiedsList(NULL), - mPanelPickInfo(NULL), - mPanelPickEdit(NULL), - mPlusMenu(NULL), - mPicksAccTab(NULL), - mClassifiedsAccTab(NULL), - mPanelClassifiedInfo(NULL), - mNoClassifieds(false), - mNoPicks(false) -{ -} - -LLPanelPicks::~LLPanelPicks() -{ - if(getAvatarId().notNull()) - { - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); - } -} - -void* LLPanelPicks::create(void* data /* = NULL */) -{ - return new LLPanelPicks(); -} - -void LLPanelPicks::updateData() -{ - // Send Picks request only when we need to, not on every onOpen(during tab switch). - if(isDirty()) - { - mNoPicks = false; - mNoClassifieds = false; - - mNoItemsLabel->setValue(LLTrans::getString("PicksClassifiedsLoadingText")); - mNoItemsLabel->setVisible(TRUE); - - mPicksList->clear(); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(getAvatarId()); - - mClassifiedsList->clear(); - LLAvatarPropertiesProcessor::getInstance()->sendAvatarClassifiedsRequest(getAvatarId()); - } -} - -void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type) -{ - if(APT_PICKS == type) - { - LLAvatarPicks* avatar_picks = static_cast(data); - if(avatar_picks && getAvatarId() == avatar_picks->target_id) - { - LLAvatarName av_name; - LLAvatarNameCache::get(getAvatarId(), &av_name); - getChild("pick_title")->setTextArg("[NAME]", av_name.getUserName()); - - // Save selection, to be able to edit same item after saving changes. See EXT-3023. - LLUUID selected_id = mPicksList->getSelectedValue()[PICK_ID]; - - mPicksList->clear(); - - LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin(); - for(; avatar_picks->picks_list.end() != it; ++it) - { - LLUUID pick_id = it->first; - std::string pick_name = it->second; - - LLPickItem* picture = LLPickItem::create(); - picture->childSetAction("info_chevron", boost::bind(&LLPanelPicks::onClickInfo, this)); - picture->setPickName(pick_name); - picture->setPickId(pick_id); - picture->setCreatorId(getAvatarId()); - - LLAvatarPropertiesProcessor::instance().addObserver(getAvatarId(), picture); - picture->update(); - - LLSD pick_value = LLSD(); - pick_value.insert(PICK_ID, pick_id); - pick_value.insert(PICK_NAME, pick_name); - pick_value.insert(PICK_CREATOR_ID, getAvatarId()); - - mPicksList->addItem(picture, pick_value); - - // Restore selection by item id. - if ( pick_id == selected_id ) - mPicksList->selectItemByValue(pick_value); - - picture->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickPickItem, this, _1)); - picture->setRightMouseUpCallback(boost::bind(&LLPanelPicks::onRightMouseUpItem, this, _1, _2, _3, _4)); - picture->setMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); - } - - showAccordion("tab_picks", mPicksList->size()); - - resetDirty(); - updateButtons(); - } - - mNoPicks = !mPicksList->size(); - } - else if((APT_CLASSIFIEDS == type) || (APT_CLASSIFIED_INFO == type)) - { - LLAvatarClassifieds* c_info = static_cast(data); - if(c_info && getAvatarId() == c_info->target_id) - { - // do not clear classified list in case we will receive two or more data packets. - // list has been cleared in updateData(). (fix for EXT-6436) - - LLAvatarClassifieds::classifieds_list_t::const_iterator it = c_info->classifieds_list.begin(); - for(; c_info->classifieds_list.end() != it; ++it) - { - LLAvatarClassifieds::classified_data c_data = *it; - - LLClassifiedItem* c_item = new LLClassifiedItem(getAvatarId(), c_data.classified_id); - c_item->childSetAction("info_chevron", boost::bind(&LLPanelPicks::onClickInfo, this)); - c_item->setClassifiedName(c_data.name); - - LLSD pick_value = LLSD(); - pick_value.insert(CLASSIFIED_ID, c_data.classified_id); - pick_value.insert(CLASSIFIED_NAME, c_data.name); - - if (!findClassifiedById(c_data.classified_id)) - { - mClassifiedsList->addItem(c_item, pick_value); - } - - c_item->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickClassifiedItem, this, _1)); - c_item->setRightMouseUpCallback(boost::bind(&LLPanelPicks::onRightMouseUpItem, this, _1, _2, _3, _4)); - c_item->setMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); - } - - showAccordion("tab_classifieds", mClassifiedsList->size()); - - resetDirty(); - updateButtons(); - } - - mNoClassifieds = !mClassifiedsList->size(); - } - - bool no_data = mNoPicks && mNoClassifieds; - mNoItemsLabel->setVisible(no_data); - if (no_data) - { - if(getAvatarId() == gAgentID) - { - mNoItemsLabel->setValue(LLTrans::getString("NoPicksClassifiedsText")); - } - else - { - mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksClassifiedsText")); - } - } -} - -LLPickItem* LLPanelPicks::getSelectedPickItem() -{ - LLPanel* selected_item = mPicksList->getSelectedItem(); - if (!selected_item) return NULL; - - return dynamic_cast(selected_item); -} - -LLClassifiedItem* LLPanelPicks::getSelectedClassifiedItem() -{ - LLPanel* selected_item = mClassifiedsList->getSelectedItem(); - if (!selected_item) - { - return NULL; - } - return dynamic_cast(selected_item); -} - -BOOL LLPanelPicks::postBuild() -{ - mPicksList = getChild("picks_list"); - mClassifiedsList = getChild("classifieds_list"); - - mPicksList->setCommitOnSelectionChange(true); - mClassifiedsList->setCommitOnSelectionChange(true); - - mPicksList->setCommitCallback(boost::bind(&LLPanelPicks::onListCommit, this, mPicksList)); - mClassifiedsList->setCommitCallback(boost::bind(&LLPanelPicks::onListCommit, this, mClassifiedsList)); - - mPicksList->setNoItemsCommentText(getString("no_picks")); - mClassifiedsList->setNoItemsCommentText(getString("no_classifieds")); - - mNoItemsLabel = getChild("picks_panel_text"); - - childSetAction(XML_BTN_NEW, boost::bind(&LLPanelPicks::onClickPlusBtn, this)); - childSetAction(XML_BTN_DELETE, boost::bind(&LLPanelPicks::onClickDelete, this)); - childSetAction(XML_BTN_TELEPORT, boost::bind(&LLPanelPicks::onClickTeleport, this)); - childSetAction(XML_BTN_SHOW_ON_MAP, boost::bind(&LLPanelPicks::onClickMap, this)); - childSetAction(XML_BTN_INFO, boost::bind(&LLPanelPicks::onClickInfo, this)); - - mPicksAccTab = getChild("tab_picks"); - mPicksAccTab->setDropDownStateChangedCallback(boost::bind(&LLPanelPicks::onAccordionStateChanged, this, mPicksAccTab)); - mPicksAccTab->setDisplayChildren(true); - - mClassifiedsAccTab = getChild("tab_classifieds"); - mClassifiedsAccTab->setDropDownStateChangedCallback(boost::bind(&LLPanelPicks::onAccordionStateChanged, this, mClassifiedsAccTab)); - mClassifiedsAccTab->setDisplayChildren(false); - - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registar; - registar.add("Pick.Info", boost::bind(&LLPanelPicks::onClickInfo, this)); - registar.add("Pick.Edit", boost::bind(&LLPanelPicks::onClickMenuEdit, this)); - registar.add("Pick.Teleport", boost::bind(&LLPanelPicks::onClickTeleport, this)); - registar.add("Pick.Map", boost::bind(&LLPanelPicks::onClickMap, this)); - registar.add("Pick.Delete", boost::bind(&LLPanelPicks::onClickDelete, this)); - LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registar; - enable_registar.add("Pick.Enable", boost::bind(&LLPanelPicks::onEnableMenuItem, this, _2)); - - mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_picks.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - - LLUICtrl::CommitCallbackRegistry::ScopedRegistrar plus_registar; - plus_registar.add("Picks.Plus.Action", boost::bind(&LLPanelPicks::onPlusMenuItemClicked, this, _2)); - mEnableCallbackRegistrar.add("Picks.Plus.Enable", boost::bind(&LLPanelPicks::isActionEnabled, this, _2)); - mPlusMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_picks_plus.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - - return TRUE; -} - -void LLPanelPicks::onPlusMenuItemClicked(const LLSD& param) -{ - std::string value = param.asString(); - - if("new_pick" == value) - { - createNewPick(); - } - else if("new_classified" == value) - { - createNewClassified(); - } -} - -bool LLPanelPicks::isActionEnabled(const LLSD& userdata) const -{ - std::string command_name = userdata.asString(); - - if (command_name == "new_pick" && LLAgentPicksInfo::getInstance()->isPickLimitReached()) - { - return false; - } - - return true; -} - -bool LLPanelPicks::isClassifiedPublished(LLClassifiedItem* c_item) -{ - if(c_item) - { - LLPanelClassifiedEdit* panel = mEditClassifiedPanels[c_item->getClassifiedId()]; - if(panel) - { - return !panel->isNewWithErrors(); - } - - // we've got this classified from server - it's published - return true; - } - return false; -} - -void LLPanelPicks::onAccordionStateChanged(const LLAccordionCtrlTab* acc_tab) -{ - if(!mPicksAccTab->getDisplayChildren()) - { - mPicksList->resetSelection(true); - } - if(!mClassifiedsAccTab->getDisplayChildren()) - { - mClassifiedsList->resetSelection(true); - } - - updateButtons(); -} - -void LLPanelPicks::onOpen(const LLSD& key) -{ - const LLUUID id(key.asUUID()); - BOOL self = (gAgent.getID() == id); - - // only agent can edit her picks - getChildView("edit_panel")->setEnabled(self); - getChildView("edit_panel")->setVisible( self); - - // Disable buttons when viewing profile for first time - if(getAvatarId() != id) - { - getChildView(XML_BTN_INFO)->setEnabled(FALSE); - getChildView(XML_BTN_TELEPORT)->setEnabled(FALSE); - getChildView(XML_BTN_SHOW_ON_MAP)->setEnabled(FALSE); - } - - // and see a special title - set as invisible by default in xml file - if (self) - { - getChildView("pick_title")->setVisible( !self); - getChildView("pick_title_agent")->setVisible( self); - - mPopupMenu->setItemVisible("pick_delete", TRUE); - mPopupMenu->setItemVisible("pick_edit", TRUE); - mPopupMenu->setItemVisible("pick_separator", TRUE); - } - - if(getAvatarId() != id) - { - showAccordion("tab_picks", false); - showAccordion("tab_classifieds", false); - - mPicksList->goToTop(); - // Set dummy value to make panel dirty and make it reload picks - setValue(LLSD()); - } - - LLPanelProfileTab::onOpen(key); -} - -void LLPanelPicks::onClosePanel() -{ - if (mPanelClassifiedInfo) - { - onPanelClassifiedClose(mPanelClassifiedInfo); - } - if (mPanelPickInfo) - { - onPanelPickClose(mPanelPickInfo); - } -} - -void LLPanelPicks::onListCommit(const LLFlatListView* f_list) -{ - // Make sure only one of the lists has selection. - if(f_list == mPicksList) - { - mClassifiedsList->resetSelection(true); - } - else if(f_list == mClassifiedsList) - { - mPicksList->resetSelection(true); - } - else - { - LL_WARNS() << "Unknown list" << LL_ENDL; - } - - updateButtons(); -} - -//static -void LLPanelPicks::onClickDelete() -{ - LLSD value = mPicksList->getSelectedValue(); - if (value.isDefined()) - { - LLSD args; - args["PICK"] = value[PICK_NAME]; - LLNotificationsUtil::add("DeleteAvatarPick", args, LLSD(), boost::bind(&LLPanelPicks::callbackDeletePick, this, _1, _2)); - return; - } - - value = mClassifiedsList->getSelectedValue(); - if(value.isDefined()) - { - LLSD args; - args["NAME"] = value[CLASSIFIED_NAME]; - LLNotificationsUtil::add("DeleteClassified", args, LLSD(), boost::bind(&LLPanelPicks::callbackDeleteClassified, this, _1, _2)); - return; - } -} - -bool LLPanelPicks::callbackDeletePick(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLSD pick_value = mPicksList->getSelectedValue(); - - if (0 == option) - { - LLAvatarPropertiesProcessor::instance().sendPickDelete(pick_value[PICK_ID]); - mPicksList->removeItemByValue(pick_value); - } - updateButtons(); - return false; -} - -bool LLPanelPicks::callbackDeleteClassified(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - LLSD value = mClassifiedsList->getSelectedValue(); - - if (0 == option) - { - LLAvatarPropertiesProcessor::instance().sendClassifiedDelete(value[CLASSIFIED_ID]); - mClassifiedsList->removeItemByValue(value); - } - updateButtons(); - return false; -} - -bool LLPanelPicks::callbackTeleport( const LLSD& notification, const LLSD& response ) -{ - S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - - if (0 == option) - { - onClickTeleport(); - } - return false; -} - -//static -void LLPanelPicks::onClickTeleport() -{ - LLPickItem* pick_item = getSelectedPickItem(); - LLClassifiedItem* c_item = getSelectedClassifiedItem(); - - LLVector3d pos; - if(pick_item) - pos = pick_item->getPosGlobal(); - else if(c_item) - { - pos = c_item->getPosGlobal(); - LLPanelClassifiedInfo::sendClickMessage("teleport", false, - c_item->getClassifiedId(), LLUUID::null, pos, LLStringUtil::null); - } - - if (!pos.isExactlyZero()) - { - gAgent.teleportViaLocation(pos); - LLFloaterWorldMap::getInstance()->trackLocation(pos); - } -} - -//static -void LLPanelPicks::onClickMap() -{ - LLPickItem* pick_item = getSelectedPickItem(); - LLClassifiedItem* c_item = getSelectedClassifiedItem(); - - LLVector3d pos; - if (pick_item) - pos = pick_item->getPosGlobal(); - else if(c_item) - { - LLPanelClassifiedInfo::sendClickMessage("map", false, - c_item->getClassifiedId(), LLUUID::null, pos, LLStringUtil::null); - pos = c_item->getPosGlobal(); - } - - LLFloaterWorldMap::getInstance()->trackLocation(pos); - LLFloaterReg::showInstance("world_map", "center"); -} - - -void LLPanelPicks::onRightMouseUpItem(LLUICtrl* item, S32 x, S32 y, MASK mask) -{ - updateButtons(); - - if (mPopupMenu) - { - mPopupMenu->buildDrawLabels(); - mPopupMenu->updateParent(LLMenuGL::sMenuContainer); - ((LLContextMenu*)mPopupMenu)->show(x, y); - LLMenuGL::showPopup(item, mPopupMenu, x, y); - } -} - -void LLPanelPicks::onDoubleClickPickItem(LLUICtrl* item) -{ - LLSD pick_value = mPicksList->getSelectedValue(); - if (pick_value.isUndefined()) return; - - LLSD args; - args["PICK"] = pick_value[PICK_NAME]; - LLNotificationsUtil::add("TeleportToPick", args, LLSD(), boost::bind(&LLPanelPicks::callbackTeleport, this, _1, _2)); -} - -void LLPanelPicks::onDoubleClickClassifiedItem(LLUICtrl* item) -{ - LLSD value = mClassifiedsList->getSelectedValue(); - if (value.isUndefined()) return; - - LLSD args; - args["CLASSIFIED"] = value[CLASSIFIED_NAME]; - LLNotificationsUtil::add("TeleportToClassified", args, LLSD(), boost::bind(&LLPanelPicks::callbackTeleport, this, _1, _2)); -} - -void LLPanelPicks::updateButtons() -{ - bool has_selected = mPicksList->numSelected() > 0 || mClassifiedsList->numSelected() > 0; - - if (getAvatarId() == gAgentID) - { - getChildView(XML_BTN_DELETE)->setEnabled(has_selected); - } - - getChildView(XML_BTN_INFO)->setEnabled(has_selected); - getChildView(XML_BTN_TELEPORT)->setEnabled(has_selected); - getChildView(XML_BTN_SHOW_ON_MAP)->setEnabled(has_selected); - - LLClassifiedItem* c_item = dynamic_cast(mClassifiedsList->getSelectedItem()); - if(c_item) - { - getChildView(XML_BTN_INFO)->setEnabled(isClassifiedPublished(c_item)); - } -} - -void LLPanelPicks::setProfilePanel(LLPanelProfile* profile_panel) -{ - mProfilePanel = profile_panel; -} - - -void LLPanelPicks::buildPickPanel() -{ -// if (mPickPanel == NULL) -// { -// mPickPanel = new LLPanelPick(); -// mPickPanel->setExitCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, NULL)); -// } -} - -void LLPanelPicks::onClickPlusBtn() -{ - LLRect rect(getChildView(XML_BTN_NEW)->getRect()); - - mPlusMenu->updateParent(LLMenuGL::sMenuContainer); - mPlusMenu->setButtonRect(rect, this); - LLMenuGL::showPopup(this, mPlusMenu, rect.mLeft, rect.mTop); -} - -void LLPanelPicks::createNewPick() -{ - createPickEditPanel(); - - getProfilePanel()->openPanel(mPanelPickEdit, LLSD()); -} - -void LLPanelPicks::createNewClassified() -{ - LLPanelClassifiedEdit* panel = NULL; - createClassifiedEditPanel(&panel); - - getProfilePanel()->openPanel(panel, LLSD()); -} - -void LLPanelPicks::onClickInfo() -{ - if(mPicksList->numSelected() > 0) - { - openPickInfo(); - } - else if(mClassifiedsList->numSelected() > 0) - { - openClassifiedInfo(); - } -} - -void LLPanelPicks::openPickInfo() -{ - LLSD selected_value = mPicksList->getSelectedValue(); - if (selected_value.isUndefined()) return; - - LLPickItem* pick = (LLPickItem*)mPicksList->getSelectedItem(); - - createPickInfoPanel(); - - LLSD params; - params["pick_id"] = pick->getPickId(); - params["avatar_id"] = pick->getCreatorId(); - params["snapshot_id"] = pick->getSnapshotId(); - params["pick_name"] = pick->getPickName(); - params["pick_desc"] = pick->getPickDesc(); - - getProfilePanel()->openPanel(mPanelPickInfo, params); -} - -void LLPanelPicks::openClassifiedInfo() -{ - LLSD selected_value = mClassifiedsList->getSelectedValue(); - if (selected_value.isUndefined()) return; - - LLClassifiedItem* c_item = getSelectedClassifiedItem(); - LLSD params; - params["classified_id"] = c_item->getClassifiedId(); - params["classified_creator_id"] = c_item->getAvatarId(); - params["classified_snapshot_id"] = c_item->getSnapshotId(); - params["classified_name"] = c_item->getClassifiedName(); - params["classified_desc"] = c_item->getDescription(); - params["from_search"] = false; - - openClassifiedInfo(params); -} - -void LLPanelPicks::openClassifiedInfo(const LLSD ¶ms) -{ - createClassifiedInfoPanel(); - getProfilePanel()->openPanel(mPanelClassifiedInfo, params); -} - -void LLPanelPicks::openClassifiedEdit(const LLSD& params) -{ - LLUUID classified_id = params["classified_id"].asUUID();; - LL_INFOS() << "opening classified " << classified_id << " for edit" << LL_ENDL; - editClassified(classified_id); -} - -void LLPanelPicks::showAccordion(const std::string& name, bool show) -{ - LLAccordionCtrlTab* tab = getChild(name); - tab->setVisible(show); - LLAccordionCtrl* acc = getChild("accordion"); - acc->arrange(); -} - -void LLPanelPicks::onPanelPickClose(LLPanel* panel) -{ - getProfilePanel()->closePanel(panel); -} - -void LLPanelPicks::onPanelPickSave(LLPanel* panel) -{ - onPanelPickClose(panel); - updateButtons(); -} - -void LLPanelPicks::onPanelClassifiedSave(LLPanelClassifiedEdit* panel) -{ - if(!panel->canClose()) - { - return; - } - - if(panel->isNew()) - { - mEditClassifiedPanels[panel->getClassifiedId()] = panel; - - LLClassifiedItem* c_item = new LLClassifiedItem(getAvatarId(), panel->getClassifiedId()); - c_item->fillIn(panel); - - LLSD c_value; - c_value.insert(CLASSIFIED_ID, c_item->getClassifiedId()); - c_value.insert(CLASSIFIED_NAME, c_item->getClassifiedName()); - mClassifiedsList->addItem(c_item, c_value, ADD_TOP); - - c_item->setDoubleClickCallback(boost::bind(&LLPanelPicks::onDoubleClickClassifiedItem, this, _1)); - c_item->setRightMouseUpCallback(boost::bind(&LLPanelPicks::onRightMouseUpItem, this, _1, _2, _3, _4)); - c_item->setMouseUpCallback(boost::bind(&LLPanelPicks::updateButtons, this)); - c_item->childSetAction("info_chevron", boost::bind(&LLPanelPicks::onClickInfo, this)); - - // order does matter, showAccordion will invoke arrange for accordions. - mClassifiedsAccTab->changeOpenClose(false); - showAccordion("tab_classifieds", true); - } - else if(panel->isNewWithErrors()) - { - LLClassifiedItem* c_item = dynamic_cast(mClassifiedsList->getSelectedItem()); - llassert(c_item); - if (c_item) - { - c_item->fillIn(panel); - } - } - else - { - onPanelClassifiedClose(panel); - return; - } - - onPanelPickClose(panel); - updateButtons(); -} - -void LLPanelPicks::onPanelClassifiedClose(LLPanelClassifiedInfo* panel) -{ - if(panel->getInfoLoaded() && !panel->isDirty()) - { - std::vector values; - mClassifiedsList->getValues(values); - for(size_t n = 0; n < values.size(); ++n) - { - LLUUID c_id = values[n][CLASSIFIED_ID].asUUID(); - if(panel->getClassifiedId() == c_id) - { - LLClassifiedItem* c_item = dynamic_cast( - mClassifiedsList->getItemByValue(values[n])); - llassert(c_item); - if (c_item) - { - c_item->setClassifiedName(panel->getClassifiedName()); - c_item->setDescription(panel->getDescription()); - c_item->setSnapshotId(panel->getSnapshotId()); - } - } - } - } - - onPanelPickClose(panel); - updateButtons(); -} - -void LLPanelPicks::createPickInfoPanel() -{ - if(!mPanelPickInfo) - { - mPanelPickInfo = LLPanelPickInfo::create(); - mPanelPickInfo->setExitCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, mPanelPickInfo)); - mPanelPickInfo->setEditPickCallback(boost::bind(&LLPanelPicks::onPanelPickEdit, this)); - mPanelPickInfo->setVisible(FALSE); - } -} - -void LLPanelPicks::createClassifiedInfoPanel() -{ - mPanelClassifiedInfo = LLPanelClassifiedInfo::create(); - mPanelClassifiedInfo->setExitCallback(boost::bind(&LLPanelPicks::onPanelClassifiedClose, this, mPanelClassifiedInfo)); - mPanelClassifiedInfo->setEditClassifiedCallback(boost::bind(&LLPanelPicks::onPanelClassifiedEdit, this)); - mPanelClassifiedInfo->setVisible(FALSE); -} - -void LLPanelPicks::createClassifiedEditPanel(LLPanelClassifiedEdit** panel) -{ - if(panel) - { - LLPanelClassifiedEdit* new_panel = LLPanelClassifiedEdit::create(); - new_panel->setExitCallback(boost::bind(&LLPanelPicks::onPanelClassifiedClose, this, new_panel)); - new_panel->setSaveCallback(boost::bind(&LLPanelPicks::onPanelClassifiedSave, this, new_panel)); - new_panel->setCancelCallback(boost::bind(&LLPanelPicks::onPanelClassifiedClose, this, new_panel)); - new_panel->setVisible(FALSE); - *panel = new_panel; - } -} - -void LLPanelPicks::createPickEditPanel() -{ - mPanelPickEdit = LLPanelPickEdit::create(); - mPanelPickEdit->setExitCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, mPanelPickEdit)); - mPanelPickEdit->setSaveCallback(boost::bind(&LLPanelPicks::onPanelPickSave, this, mPanelPickEdit)); - mPanelPickEdit->setCancelCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, mPanelPickEdit)); - mPanelPickEdit->setVisible(FALSE); -} - -// void LLPanelPicks::openPickEditPanel(LLPickItem* pick) -// { -// if(!pick) -// { -// return; -// } -// } - -// void LLPanelPicks::openPickInfoPanel(LLPickItem* pick) -// { -// if(!mPanelPickInfo) -// { -// mPanelPickInfo = LLPanelPickInfo::create(); -// mPanelPickInfo->setExitCallback(boost::bind(&LLPanelPicks::onPanelPickClose, this, mPanelPickInfo)); -// mPanelPickInfo->setEditPickCallback(boost::bind(&LLPanelPicks::onPanelPickEdit, this)); -// mPanelPickInfo->setVisible(FALSE); -// } -// -// LLSD params; -// params["pick_id"] = pick->getPickId(); -// params["avatar_id"] = pick->getCreatorId(); -// params["snapshot_id"] = pick->getSnapshotId(); -// params["pick_name"] = pick->getPickName(); -// params["pick_desc"] = pick->getPickDesc(); -// -// getProfilePanel()->openPanel(mPanelPickInfo, params); -// } - -void LLPanelPicks::openPickEdit(const LLSD& params) -{ - createPickEditPanel(); - getProfilePanel()->openPanel(mPanelPickEdit, params); -} - -void LLPanelPicks::onPanelPickEdit() -{ - LLSD selected_value = mPicksList->getSelectedValue(); - if (selected_value.isUndefined()) return; - - LLPickItem* pick = dynamic_cast(mPicksList->getSelectedItem()); - - createPickEditPanel(); - - LLSD params; - params["pick_id"] = pick->getPickId(); - params["avatar_id"] = pick->getCreatorId(); - params["snapshot_id"] = pick->getSnapshotId(); - params["pick_name"] = pick->getPickName(); - params["pick_desc"] = pick->getPickDesc(); - - getProfilePanel()->openPanel(mPanelPickEdit, params); -} - -void LLPanelPicks::onPanelClassifiedEdit() -{ - LLSD selected_value = mClassifiedsList->getSelectedValue(); - if (selected_value.isUndefined()) - { - return; - } - - LLClassifiedItem* c_item = dynamic_cast(mClassifiedsList->getSelectedItem()); - llassert(c_item); - if (!c_item) - { - return; - } - editClassified(c_item->getClassifiedId()); -} - -LLClassifiedItem *LLPanelPicks::findClassifiedById(const LLUUID& classified_id) -{ - // HACK - find item by classified id. Should be a better way. - std::vector items; - mClassifiedsList->getItems(items); - LLClassifiedItem* c_item = NULL; - for(std::vector::iterator it = items.begin(); it != items.end(); ++it) - { - LLClassifiedItem *test_item = dynamic_cast(*it); - if (test_item && test_item->getClassifiedId() == classified_id) - { - c_item = test_item; - break; - } - } - return c_item; -} - -void LLPanelPicks::editClassified(const LLUUID& classified_id) -{ - LLClassifiedItem* c_item = findClassifiedById(classified_id); - if (!c_item) - { - LL_WARNS() << "item not found for classified_id " << classified_id << LL_ENDL; - return; - } - - LLSD params; - params["classified_id"] = c_item->getClassifiedId(); - params["classified_creator_id"] = c_item->getAvatarId(); - params["snapshot_id"] = c_item->getSnapshotId(); - params["name"] = c_item->getClassifiedName(); - params["desc"] = c_item->getDescription(); - params["category"] = (S32)c_item->getCategory(); - params["content_type"] = (S32)c_item->getContentType(); - params["auto_renew"] = c_item->getAutoRenew(); - params["price_for_listing"] = c_item->getPriceForListing(); - params["location_text"] = c_item->getLocationText(); - - LLPanelClassifiedEdit* panel = mEditClassifiedPanels[c_item->getClassifiedId()]; - if(!panel) - { - createClassifiedEditPanel(&panel); - mEditClassifiedPanels[c_item->getClassifiedId()] = panel; - } - getProfilePanel()->openPanel(panel, params); - panel->setPosGlobal(c_item->getPosGlobal()); -} - -void LLPanelPicks::onClickMenuEdit() -{ - if(getSelectedPickItem()) - { - onPanelPickEdit(); - } - else if(getSelectedClassifiedItem()) - { - onPanelClassifiedEdit(); - } -} - -bool LLPanelPicks::onEnableMenuItem(const LLSD& user_data) -{ - std::string param = user_data.asString(); - - LLClassifiedItem* c_item = dynamic_cast(mClassifiedsList->getSelectedItem()); - if(c_item && "info" == param) - { - // dont show Info panel if classified was not created - return isClassifiedPublished(c_item); - } - - return true; -} - -inline LLPanelProfile* LLPanelPicks::getProfilePanel() -{ - llassert_always(NULL != mProfilePanel); - return mProfilePanel; -} - -//----------------------------------------------------------------------------- -// LLPanelPicks -//----------------------------------------------------------------------------- -LLPickItem::LLPickItem() -: LLPanel() -, mPickID(LLUUID::null) -, mCreatorID(LLUUID::null) -, mParcelID(LLUUID::null) -, mSnapshotID(LLUUID::null) -, mNeedData(true) -{ - buildFromFile("panel_pick_list_item.xml"); -} - -LLPickItem::~LLPickItem() -{ - if (mCreatorID.notNull()) - { - LLAvatarPropertiesProcessor::instance().removeObserver(mCreatorID, this); - } - -} - -LLPickItem* LLPickItem::create() -{ - return new LLPickItem(); -} - -void LLPickItem::init(LLPickData* pick_data) -{ - setPickDesc(pick_data->desc); - setSnapshotId(pick_data->snapshot_id); - mPosGlobal = pick_data->pos_global; - mSimName = pick_data->sim_name; - mPickDescription = pick_data->desc; - mUserName = pick_data->user_name; - mOriginalName = pick_data->original_name; - - LLTextureCtrl* picture = getChild("picture"); - picture->setImageAssetID(pick_data->snapshot_id); -} - -void LLPickItem::setPickName(const std::string& name) -{ - mPickName = name; - getChild("picture_name")->setValue(name); - -} - -const std::string& LLPickItem::getPickName() -{ - return mPickName; -} - -const LLUUID& LLPickItem::getCreatorId() -{ - return mCreatorID; -} - -const LLUUID& LLPickItem::getSnapshotId() -{ - return mSnapshotID; -} - -void LLPickItem::setPickDesc(const std::string& descr) -{ - getChild("picture_descr")->setValue(descr); -} - -void LLPickItem::setPickId(const LLUUID& id) -{ - mPickID = id; -} - -const LLUUID& LLPickItem::getPickId() -{ - return mPickID; -} - -const LLVector3d& LLPickItem::getPosGlobal() -{ - return mPosGlobal; -} - -const std::string LLPickItem::getDescription() -{ - return getChild("picture_descr")->getValue().asString(); -} - -void LLPickItem::update() -{ - setNeedData(true); - LLAvatarPropertiesProcessor::instance().sendPickInfoRequest(mCreatorID, mPickID); -} - -void LLPickItem::processProperties(void *data, EAvatarProcessorType type) -{ - if (APT_PICK_INFO != type) - { - return; - } - - LLPickData* pick_data = static_cast(data); - if (!pick_data || mPickID != pick_data->pick_id) - { - return; - } - - init(pick_data); - setNeedData(false); - LLAvatarPropertiesProcessor::instance().removeObserver(mCreatorID, this); -} - -void set_child_visible(LLView* parent, const std::string& child_name, bool visible) -{ - parent->getChildView(child_name)->setVisible(visible); -} - -BOOL LLPickItem::postBuild() -{ - setMouseEnterCallback(boost::bind(&set_child_visible, this, "hovered_icon", true)); - setMouseLeaveCallback(boost::bind(&set_child_visible, this, "hovered_icon", false)); - return TRUE; -} - -void LLPickItem::setValue(const LLSD& value) -{ - if (!value.isMap()) return;; - if (!value.has("selected")) return; - getChildView("selected_icon")->setVisible( value["selected"]); -} - -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////// - -LLClassifiedItem::LLClassifiedItem(const LLUUID& avatar_id, const LLUUID& classified_id) - : LLPanel() - , mAvatarId(avatar_id) - , mClassifiedId(classified_id) -{ - buildFromFile("panel_classifieds_list_item.xml"); - - LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); - LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId()); -} - -LLClassifiedItem::~LLClassifiedItem() -{ - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); -} - -void LLClassifiedItem::processProperties(void* data, EAvatarProcessorType type) -{ - if(APT_CLASSIFIED_INFO != type) - { - return; - } - - LLAvatarClassifiedInfo* c_info = static_cast(data); - if( !c_info || c_info->classified_id != getClassifiedId() ) - { - return; - } - - setClassifiedName(c_info->name); - setDescription(c_info->description); - setSnapshotId(c_info->snapshot_id); - setPosGlobal(c_info->pos_global); - - LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); -} - -BOOL LLClassifiedItem::postBuild() -{ - setMouseEnterCallback(boost::bind(&set_child_visible, this, "hovered_icon", true)); - setMouseLeaveCallback(boost::bind(&set_child_visible, this, "hovered_icon", false)); - return TRUE; -} - -void LLClassifiedItem::setValue(const LLSD& value) -{ - if (!value.isMap()) return;; - if (!value.has("selected")) return; - getChildView("selected_icon")->setVisible( value["selected"]); -} - -void LLClassifiedItem::fillIn(LLPanelClassifiedEdit* panel) -{ - if(!panel) - { - return; - } - - setClassifiedName(panel->getClassifiedName()); - setDescription(panel->getDescription()); - setSnapshotId(panel->getSnapshotId()); - setCategory(panel->getCategory()); - setContentType(panel->getContentType()); - setAutoRenew(panel->getAutoRenew()); - setPriceForListing(panel->getPriceForListing()); - setPosGlobal(panel->getPosGlobal()); - setLocationText(panel->getClassifiedLocation()); -} - -void LLClassifiedItem::setClassifiedName(const std::string& name) -{ - getChild("name")->setValue(name); -} - -void LLClassifiedItem::setDescription(const std::string& desc) -{ - getChild("description")->setValue(desc); -} - -void LLClassifiedItem::setSnapshotId(const LLUUID& snapshot_id) -{ - getChild("picture")->setValue(snapshot_id); -} - -LLUUID LLClassifiedItem::getSnapshotId() -{ - return getChild("picture")->getValue(); -} - -//EOF diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h deleted file mode 100644 index 3bb7413ac3..0000000000 --- a/indra/newview/llpanelpicks.h +++ /dev/null @@ -1,314 +0,0 @@ -/** - * @file llpanelpicks.h - * @brief LLPanelPicks and related class definitions - * - * $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$ - */ - -#ifndef LL_LLPANELPICKS_H -#define LL_LLPANELPICKS_H - -#include "llpanel.h" -#include "v3dmath.h" -#include "lluuid.h" -#include "llavatarpropertiesprocessor.h" -#include "llpanelavatar.h" -#include "llregistry.h" - -class LLAccordionCtrlTab; -class LLPanelProfile; -class LLMessageSystem; -class LLVector3d; -class LLPanelProfileTab; -class LLAgent; -class LLMenuGL; -class LLPickItem; -class LLClassifiedItem; -class LLFlatListView; -class LLPanelPickInfo; -class LLPanelPickEdit; -class LLToggleableMenu; -class LLPanelClassifiedInfo; -class LLPanelClassifiedEdit; - -// *TODO -// Panel Picks has been consolidated with Classifieds (EXT-2095), give LLPanelPicks -// and corresponding files (cpp, h, xml) a new name. (new name is TBD at the moment) - -class LLPanelPicks - : public LLPanelProfileTab -{ -public: - LLPanelPicks(); - ~LLPanelPicks(); - - static void* create(void* data); - - /*virtual*/ BOOL postBuild(void); - - /*virtual*/ void onOpen(const LLSD& key); - - /*virtual*/ void onClosePanel(); - - void processProperties(void* data, EAvatarProcessorType type); - - void updateData(); - - // returns the selected pick item - LLPickItem* getSelectedPickItem(); - LLClassifiedItem* getSelectedClassifiedItem(); - LLClassifiedItem* findClassifiedById(const LLUUID& classified_id); - - //*NOTE top down approch when panel toggling is done only by - // parent panels failed to work (picks related code was in my profile panel) - void setProfilePanel(LLPanelProfile* profile_panel); - - void createNewPick(); - void createNewClassified(); - -protected: - /*virtual*/void updateButtons(); - -private: - void onClickDelete(); - void onClickTeleport(); - void onClickMap(); - - void onPlusMenuItemClicked(const LLSD& param); - bool isActionEnabled(const LLSD& userdata) const; - - bool isClassifiedPublished(LLClassifiedItem* c_item); - - void onListCommit(const LLFlatListView* f_list); - void onAccordionStateChanged(const LLAccordionCtrlTab* acc_tab); - - //------------------------------------------------ - // Callbacks which require panel toggling - //------------------------------------------------ - void onClickPlusBtn(); - void onClickInfo(); - void onPanelPickClose(LLPanel* panel); - void onPanelPickSave(LLPanel* panel); - void onPanelClassifiedSave(LLPanelClassifiedEdit* panel); - void onPanelClassifiedClose(LLPanelClassifiedInfo* panel); - void openPickEdit(const LLSD& params); - void onPanelPickEdit(); - void onPanelClassifiedEdit(); - void editClassified(const LLUUID& classified_id); - void onClickMenuEdit(); - - bool onEnableMenuItem(const LLSD& user_data); - - void openPickInfo(); - void openClassifiedInfo(); - void openClassifiedInfo(const LLSD& params); - void openClassifiedEdit(const LLSD& params); - friend class LLPanelProfile; - - void showAccordion(const std::string& name, bool show); - - void buildPickPanel(); - - bool callbackDeletePick(const LLSD& notification, const LLSD& response); - bool callbackDeleteClassified(const LLSD& notification, const LLSD& response); - bool callbackTeleport(const LLSD& notification, const LLSD& response); - - - virtual void onDoubleClickPickItem(LLUICtrl* item); - virtual void onDoubleClickClassifiedItem(LLUICtrl* item); - virtual void onRightMouseUpItem(LLUICtrl* item, S32 x, S32 y, MASK mask); - - LLPanelProfile* getProfilePanel(); - - void createPickInfoPanel(); - void createPickEditPanel(); - void createClassifiedInfoPanel(); - void createClassifiedEditPanel(LLPanelClassifiedEdit** panel); - - LLMenuGL* mPopupMenu; - LLPanelProfile* mProfilePanel; - LLPanelPickInfo* mPickPanel; - LLFlatListView* mPicksList; - LLFlatListView* mClassifiedsList; - LLPanelPickInfo* mPanelPickInfo; - LLPanelClassifiedInfo* mPanelClassifiedInfo; - LLPanelPickEdit* mPanelPickEdit; - LLToggleableMenu* mPlusMenu; - LLUICtrl* mNoItemsLabel; - - // - typedef std::map panel_classified_edit_map_t; - - // This map is needed for newly created classifieds. The purpose of panel is to - // sit in this map and listen to LLPanelClassifiedEdit::processProperties callback. - panel_classified_edit_map_t mEditClassifiedPanels; - - LLAccordionCtrlTab* mPicksAccTab; - LLAccordionCtrlTab* mClassifiedsAccTab; - - //true if picks list is empty after processing picks - bool mNoPicks; - //true if classifieds list is empty after processing classifieds - bool mNoClassifieds; -}; - -class LLPickItem : public LLPanel, public LLAvatarPropertiesObserver -{ -public: - - LLPickItem(); - - static LLPickItem* create(); - - void init(LLPickData* pick_data); - - void setPickName(const std::string& name); - - void setPickDesc(const std::string& descr); - - void setPickId(const LLUUID& id); - - void setCreatorId(const LLUUID& id) {mCreatorID = id;}; - - void setSnapshotId(const LLUUID& id) {mSnapshotID = id;}; - - void setNeedData(bool need){mNeedData = need;}; - - const LLUUID& getPickId(); - - const std::string& getPickName(); - - const LLUUID& getCreatorId(); - - const LLUUID& getSnapshotId(); - - const LLVector3d& getPosGlobal(); - - const std::string getDescription(); - - const std::string& getSimName() { return mSimName; } - - const std::string& getUserName() { return mUserName; } - - const std::string& getOriginalName() { return mOriginalName; } - - const std::string& getPickDesc() { return mPickDescription; } - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - void update(); - - ~LLPickItem(); - - /*virtual*/ BOOL postBuild(); - - /** setting on/off background icon to indicate selected state */ - /*virtual*/ void setValue(const LLSD& value); - -protected: - - LLUUID mPickID; - LLUUID mCreatorID; - LLUUID mParcelID; - LLUUID mSnapshotID; - LLVector3d mPosGlobal; - bool mNeedData; - - std::string mPickName; - std::string mUserName; - std::string mOriginalName; - std::string mPickDescription; - std::string mSimName; -}; - -class LLClassifiedItem : public LLPanel, public LLAvatarPropertiesObserver -{ -public: - - LLClassifiedItem(const LLUUID& avatar_id, const LLUUID& classified_id); - - virtual ~LLClassifiedItem(); - - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - - /*virtual*/ BOOL postBuild(); - - /*virtual*/ void setValue(const LLSD& value); - - void fillIn(LLPanelClassifiedEdit* panel); - - LLUUID getAvatarId() {return mAvatarId;} - - void setAvatarId(const LLUUID& avatar_id) {mAvatarId = avatar_id;} - - LLUUID getClassifiedId() {return mClassifiedId;} - - void setClassifiedId(const LLUUID& classified_id) {mClassifiedId = classified_id;} - - void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; } - - const LLVector3d getPosGlobal() { return mPosGlobal; } - - void setLocationText(const std::string location) { mLocationText = location; } - - std::string getLocationText() { return mLocationText; } - - void setClassifiedName (const std::string& name); - - std::string getClassifiedName() { return getChild("name")->getValue().asString(); } - - void setDescription(const std::string& desc); - - std::string getDescription() { return getChild("description")->getValue().asString(); } - - void setSnapshotId(const LLUUID& snapshot_id); - - LLUUID getSnapshotId(); - - void setCategory(U32 cat) { mCategory = cat; } - - U32 getCategory() { return mCategory; } - - void setContentType(U32 ct) { mContentType = ct; } - - U32 getContentType() { return mContentType; } - - void setAutoRenew(U32 renew) { mAutoRenew = renew; } - - bool getAutoRenew() { return mAutoRenew; } - - void setPriceForListing(S32 price) { mPriceForListing = price; } - - S32 getPriceForListing() { return mPriceForListing; } - -private: - LLUUID mAvatarId; - LLUUID mClassifiedId; - LLVector3d mPosGlobal; - std::string mLocationText; - U32 mCategory; - U32 mContentType; - bool mAutoRenew; - S32 mPriceForListing; -}; - -#endif // LL_LLPANELPICKS_H diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 8afa35efa0..94169fd06f 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,65 @@ #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" //gClipboard +#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 "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 t_panel_profile_secondlife("panel_profile_secondlife"); +static LLPanelInjector t_panel_web("panel_profile_web"); +static LLPanelInjector t_panel_interests("panel_profile_interests"); +static LLPanelInjector t_panel_picks("panel_profile_picks"); +static LLPanelInjector t_panel_firstlife("panel_profile_firstlife"); +static LLPanelInjector t_panel_notes("panel_profile_notes"); +static LLPanelInjector 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 +107,10 @@ public: }; LLProfileHandler gProfileHandler; + +////////////////////////////////////////////////////////////////////////// +// LLAgentHandler + class LLAgentHandler : public LLCommandHandler { public: @@ -184,273 +222,1269 @@ 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("status"); + mGroupList = getChild("group_list"); + mShowInSearchCheckbox = getChild("show_in_search_checkbox"); + mSecondLifePic = getChild("2nd_life_pic"); + mDescriptionEdit = getChild("sl_description_edit"); + mTeleportButton = getChild("teleport"); + mShowOnMapButton = getChild("show_on_map_btn"); + mBlockButton = getChild("block"); + mUnblockButton = getChild("unblock"); + mNameLabel = getChild("name_label"); + mDisplayNameButton = getChild("set_name"); + mAddFriendButton = getChild("add_friend"); + mGroupInviteButton = getChild("group_invite"); + mPayButton = getChild("pay"); + mIMButton = getChild("im"); + + mStatusText->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::toggleBlock,this)); + mUnblockButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::toggleBlock,this)); + mGroupInviteButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onGroupInvite,this)); + mDisplayNameButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onClickSetName, this)); + + 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); + + 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(); - mStack.push_back(vlist); - dump(); - return true; + 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); + + 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("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); + } +} - mStack.pop_back(); - dump(); - return true; +void LLPanelProfileSecondLife::updateData() +{ + LLUUID avatar_id = getAvatarId(); + if (!getIsLoading() && avatar_id.notNull() && !(getSelfProfile() && !getEmbedded())) + { + setIsLoading(); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarGroupsRequest(avatar_id); + } } -/// Temporarily add all saved children back. -void LLPanelProfile::ChildStack::preParentReshape() +void LLPanelProfileSecondLife::processProperties(void* data, EAvatarProcessorType type) { - mSavedStack = mStack; - while(mStack.size() > 0) - { - pop(); - } + + if (APT_PROPERTIES == type) + { + const LLAvatarData* avatar_data = static_cast(data); + if(avatar_data && getAvatarId() == avatar_data->avatar_id) + { + processProfileProperties(avatar_data); + updateButtons(); + } + } + else if (APT_GROUPS == type) + { + LLAvatarGroups* avatar_groups = static_cast(data); + if(avatar_groups && getAvatarId() == avatar_groups->avatar_id) + { + processGroupProperties(avatar_groups); + } + } } -/// Add the temporarily saved children back. -void LLPanelProfile::ChildStack::postParentReshape() +void LLPanelProfileSecondLife::resetData() { - mStack = mSavedStack; - mSavedStack = stack_t(); + resetLoading(); + getChild("complete_name")->setValue(LLStringUtil::null); + getChild("register_date")->setValue(LLStringUtil::null); + getChild("acc_status_text")->setValue(LLStringUtil::null); + getChild("partner_text")->setValue(LLStringUtil::null); + mSecondLifePic->setValue(mSecondLifePic->getDefaultImageAssetID()); + mDescriptionEdit->setValue(LLStringUtil::null); + mStatusText->setVisible(FALSE); + mGroups.clear(); + mGroupList->setGroups(mGroups); +} - 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); - } - } +void LLPanelProfileSecondLife::processProfileProperties(const LLAvatarData* avatar_data) +{ + LLUUID avatar_id = getAvatarId(); + if (!LLAvatarActions::isFriend(avatar_id) && !getSelfProfile()) + { + // this is non-friend avatar. Status will be updated from LLAvatarPropertiesProcessor. + // in LLPanelProfileSecondLife::processOnlineStatus() + + // 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("complete_name")->setValue( av_name.getCompleteName() ); } -BOOL LLPanelProfile::postBuild() +void LLPanelProfileSecondLife::fillCommonData(const LLAvatarData* avatar_data) { - LLPanelPicks* panel_picks = findChild(PANEL_PICKS); - panel_picks->setProfilePanel(this); + //remove avatar id from cache to get fresh info + LLAvatarIconIDCache::getInstance()->remove(avatar_data->avatar_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("register_date")->setValue(register_date ); + mDescriptionEdit->setValue(avatar_data->about_text); + mSecondLifePic->setValue(avatar_data->image_id); - return TRUE; + 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(); + LLTextBox* partner_text = getChild("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(getTabContainer()[PANEL_PICKS]); - if (picks) - { - picks->createNewClassified(); - } - } - else if (panel == "classified_details") - { - LLPanelPicks* picks = dynamic_cast(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(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(getTabContainer()[PANEL_PICKS]); - if (picks) - { - picks->createNewPick(); - } - } - else if (panel == "edit_pick") - { - LLPanelPicks* picks = dynamic_cast(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("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 LLPanelProfile::openPanel(LLPanel* panel, const LLSD& params) +void LLPanelProfileSecondLife::pay() { - // Hide currently visible panel (STORM-690). - mChildStack.push(); + LLAvatarActions::pay(getAvatarId()); +} - // Add the panel or bring it to front. - if (panel->getParent() != this) - { - addChild(panel); - } - else - { - sendChildToFront(panel); - } +void LLPanelProfileSecondLife::toggleBlock() +{ + LLAvatarActions::toggleBlock(getAvatarId()); - panel->setVisible(TRUE); - panel->setFocus(TRUE); // prevent losing focus by the floater - panel->onOpen(params); + updateButtons(); +} - 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); +void LLPanelProfileSecondLife::onAddFriendButtonClick() +{ + LLAvatarActions::requestFriendshipDialog(getAvatarId()); } -void LLPanelProfile::closePanel(LLPanel* panel) +void LLPanelProfileSecondLife::onIMButtonClick() { - panel->setVisible(FALSE); + LLAvatarActions::startIM(getAvatarId()); +} - if (panel->getParent() == this) - { - removeChild(panel); +void LLPanelProfileSecondLife::onTeleportButtonClick() +{ + LLAvatarActions::offerTeleport(getAvatarId()); +} - // Make the underlying panel visible. - mChildStack.pop(); +void LLPanelProfileSecondLife::onGroupInvite() +{ + LLAvatarActions::inviteToGroup(getAvatarId()); +} - // 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; - } - } +// virtual, called by LLAvatarTracker +void LLPanelProfileSecondLife::changed(U32 mask) +{ + updateOnlineStatus(); + updateButtons(); } -S32 LLPanelProfile::notifyParent(const LLSD& info) +// virtual, called by LLVoiceClient +void LLPanelProfileSecondLife::onChange(EStatusType status, const std::string &channelURI, bool proximal) { - std::string action = info["action"]; - // lets update Picks list after Pick was saved - if("save_new_pick" == action) - { - onOpen(info); - return 1; - } + 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); +} - return LLPanel::notifyParent(info); +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); + mSecondLifePic->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::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() +{ + mUrlEdit = getChild("url_edit"); + mLoadButton = getChild("load"); + mWebProfileButton = getChild("web_profile_popout_btn"); + + mLoadButton->setCommitCallback(boost::bind(&LLPanelProfileWeb::onCommitLoad, this, _1)); + mWebProfileButton->setCommitCallback(boost::bind(&LLPanelProfileWeb::onCommitWebProfile, this)); + + mWebBrowser = getChild("profile_html"); + mWebBrowser->addObserver(this); + mWebBrowser->setHomePageUrl("about:blank"); + + mUrlEdit->setEnabled(FALSE); + + return TRUE; +} + +void LLPanelProfileWeb::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_PROPERTIES == type) + { + const LLAvatarData* avatar_data = static_cast(data); + if (avatar_data && getAvatarId() == avatar_data->avatar_id) + { + mURLHome = avatar_data->profile_url; + mUrlEdit->setValue(mURLHome); + mLoadButton->setEnabled(mURLHome.length() > 0); + updateButtons(); + } + } +} + +void LLPanelProfileWeb::resetData() +{ + mURLHome = LLStringUtil::null; + mUrlEdit->setValue(mURLHome); + mWebBrowser->navigateHome(); +} + +void LLPanelProfileWeb::apply(LLAvatarData* data) +{ + data->profile_url = mUrlEdit->getValue().asString(); +} + +void LLPanelProfileWeb::updateData() +{ + LLUUID avatar_id = getAvatarId(); + if (!getIsLoading() && avatar_id.notNull()) + { + setIsLoading(); + + if (!mURLWebProfile.empty()) + { + 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); + if (mURLWebProfile.empty()) + { + return; + } + + //if the tab was opened before name was resolved, load the panel now + if (getIsLoading()) + { + 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::onCommitWebProfile() +{ + // open the web profile floater + LLAvatarActions::showProfileWeb(getAvatarId()); +} + +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_LOCATION_CHANGED: + // don't set this or user will set there url to profile url + // when clicking ok on there own profile. + // childSetText("url_edit", self->getLocation() ); + 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(); + + if (getSelfProfile() && !getEmbedded()) + { + mUrlEdit->setEnabled(TRUE); + } +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +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("want_to_edit"); + mSkillsEditor = getChild("skills_edit"); + mLanguagesEditor = getChild("languages_edit"); + + for (S32 i = 0; i < WANT_CHECKS; ++i) + { + std::string check_name = llformat("chk%d", i); + mWantChecks[i] = getChild(check_name); + } + + for (S32 i = 0; i < SKILL_CHECKS; ++i) + { + std::string check_name = llformat("schk%d", i); + mSkillChecks[i] = getChild(check_name); + } + + return TRUE; +} + + +void LLPanelProfileInterests::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_INTERESTS_INFO == type) + { + const LLInterestsData* interests_data = static_cast(data); + if (interests_data && getAvatarId() == interests_data->avatar_id) + { + for (S32 i = 0; i < WANT_CHECKS; ++i) + { + if (interests_data->want_to_mask & (1<setValue(TRUE); + } + else + { + mWantChecks[i]->setValue(FALSE); + } + } + + for (S32 i = 0; i < SKILL_CHECKS; ++i) + { + if (interests_data->skills_mask & (1<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("fl_description_edit"); + mPicture = getChild("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(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 LLPanelProfileFirstLife::updateButtons() +{ + LLPanelProfileTab::updateButtons(); + + if (getSelfProfile() && !getEmbedded()) + { + mDescriptionEdit->setEnabled(TRUE); + mPicture->setEnabled(TRUE); + } +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLPanelProfileNotes::LLPanelProfileNotes() +: LLPanelProfileTab() +{ + +} + +void LLPanelProfileNotes::updateData() +{ + LLUUID avatar_id = getAvatarId(); + if (!getIsLoading() && avatar_id.notNull()) + { + setIsLoading(); + LLAvatarPropertiesProcessor::getInstance()->sendAvatarNotesRequest(avatar_id); + } +} + +BOOL LLPanelProfileNotes::postBuild() +{ + mOnlineStatus = getChild("status_check"); + mMapRights = getChild("map_check"); + mEditObjectRights = getChild("objects_check"); + mNotesEditor = getChild("notes_edit"); + + mOnlineStatus->setCommitCallback(boost::bind(&LLPanelProfileNotes::onCommitRights, this)); + mMapRights->setCommitCallback(boost::bind(&LLPanelProfileNotes::onCommitRights, this)); + mEditObjectRights->setCommitCallback(boost::bind(&LLPanelProfileNotes::onCommitRights, this)); + + mNotesEditor->setCommitCallback(boost::bind(&LLPanelProfileNotes::onCommitNotes,this)); + mNotesEditor->setCommitOnFocusLost(TRUE); + + return TRUE; +} + +void LLPanelProfileNotes::onOpen(const LLSD& key) +{ + LLPanelProfileTab::onOpen(key); + + resetData(); + + fillRightsData(); +} + +void LLPanelProfileNotes::apply() +{ + onCommitNotes(); +} + +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 rights) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option == 0) + { + LLAvatarPropertiesProcessor::getInstance()->sendFriendRights(getAvatarId(), rights); + } + else + { + mEditObjectRights->setValue(mEditObjectRights->getValue().asBoolean() ? FALSE : TRUE); + } +} + +void LLPanelProfileNotes::confirmModifyRights(bool grant, S32 rights) +{ + LLSD args; + args["NAME"] = LLSLURL("agent", getAvatarId(), "completename").getSLURLString(); + + if (grant) + { + LLNotificationsUtil::add("GrantModifyRights", args, LLSD(), + boost::bind(&LLPanelProfileNotes::rightsConfirmationCallback, this, + _1, _2, rights)); + } + else + { + LLNotificationsUtil::add("RevokeModifyRights", args, LLSD(), + boost::bind(&LLPanelProfileNotes::rightsConfirmationCallback, this, + _1, _2, rights)); + } +} + +void LLPanelProfileNotes::onCommitRights() +{ + const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); + + 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; + } + + 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; + } + + bool allow_modify_objects = mEditObjectRights->getValue().asBoolean(); + + // if modify objects checkbox clicked + if (buddy_relationship->isRightGrantedTo( + LLRelationship::GRANT_MODIFY_OBJECTS) != allow_modify_objects) + { + confirmModifyRights(allow_modify_objects, rights); + } + // only one checkbox can trigger commit, so store the rest of rights + else + { + LLAvatarPropertiesProcessor::getInstance()->sendFriendRights( + getAvatarId(), rights); + } +} + +void LLPanelProfileNotes::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_NOTES == type) + { + LLAvatarNotes* avatar_notes = static_cast(data); + if (avatar_notes && getAvatarId() == avatar_notes->target_id) + { + mNotesEditor->setValue(avatar_notes->notes); + mNotesEditor->setEnabled(TRUE); + updateButtons(); + + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); + } + } +} + +void LLPanelProfileNotes::resetData() +{ + resetLoading(); + mNotesEditor->setValue(LLStringUtil::null); + mOnlineStatus->setValue(FALSE); + mMapRights->setValue(FALSE); + mEditObjectRights->setValue(FALSE); +} + +void LLPanelProfileNotes::enableCheckboxes(bool enable) +{ + mOnlineStatus->setEnabled(enable); + mMapRights->setEnabled(enable); + mEditObjectRights->setEnabled(enable); +} + +LLPanelProfileNotes::~LLPanelProfileNotes() +{ + if (getAvatarId().notNull()) + { + LLAvatarTracker::instance().removeParticularFriendObserver(getAvatarId(), this); + } +} + +// 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); + } +} + + +////////////////////////////////////////////////////////////////////////// +// 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(mTabContainer->getCurrentPanel()); + if (active_panel) + { + active_panel->updateData(); + } +} + +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("panel_profile_tabs"); + mPanelSecondlife = findChild(PANEL_SECONDLIFE); + mPanelWeb = findChild(PANEL_WEB); + mPanelInterests = findChild(PANEL_INTERESTS); + mPanelPicks = findChild(PANEL_PICKS); + mPanelClassifieds = findChild(PANEL_CLASSIFIEDS); + mPanelFirstlife = findChild(PANEL_FIRSTLIFE); + mPanelNotes = findChild(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(); + + // Only show commit buttons on own profile on floater version + if (getSelfProfile() && !getEmbedded()) + { + getChild("ok_btn")->setVisible(TRUE); + getChild("cancel_btn")->setVisible(TRUE); + } + + // 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(); + + //KC - Classifieds handles this itself + } +} + +void LLPanelProfile::showPick(const LLUUID& pick_id) +{ + if (pick_id.notNull()) + { + mPanelPicks->selectPick(pick_id); + } + mTabContainer->selectTabPanel(mPanelPicks); +} + +void LLPanelProfile::showClassified(const LLUUID& classified_id, bool edit) +{ + if (classified_id.notNull()) + { + mPanelClassifieds->selectClassified(classified_id, edit); + } + mTabContainer->selectTabPanel(mPanelClassifieds); +} + + + diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index d97f60ed22..72f913b522 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -1,25 +1,25 @@ -/** +/** * @file llpanelprofile.h * @brief Profile panel * * $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,76 +27,386 @@ #ifndef LL_LLPANELPROFILE_H #define LL_LLPANELPROFILE_H +#include "llavatarpropertiesprocessor.h" +#include "llcallingcard.h" +#include "llfloater.h" #include "llpanel.h" #include "llpanelavatar.h" +#include "llmediactrl.h" +#include "llvoiceclient.h" + +// class LLPanelProfileClassifieds; +// class LLTabContainer; +// class LLPanelProfileSecondLife; +// class LLPanelProfileWeb; +// class LLPanelProfileInterests; +// class LLPanelProfilePicks; +// class LLPanelProfileFirstLife; +// class LLPanelProfileNotes; + +class LLAvatarName; +class LLCheckBoxCtrl; class LLTabContainer; +class LLTextBox; +class LLTextureCtrl; +class LLMediaCtrl; +class LLGroupList; +class LLTextBase; +class LLMenuButton; +class LLLineEditor; +class LLTextEditor; +class LLPanelProfileClassifieds; +class LLPanelProfilePicks; + + +/** +* Panel for displaying Avatar's second life related info. +*/ +class LLPanelProfileSecondLife + : public LLPanelProfileTab + , public LLFriendObserver + , public LLVoiceClientStatusObserver +{ +public: + LLPanelProfileSecondLife(); + /*virtual*/ ~LLPanelProfileSecondLife(); + + /*virtual*/ void onOpen(const LLSD& key); + + /** + * Saves changes. + */ + void apply(LLAvatarData* data); + + /** + * LLFriendObserver trigger + */ + virtual void changed(U32 mask); + + // Implements LLVoiceClientStatusObserver::onChange() to enable the call + // button when voice is available + /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + + /*virtual*/ void setAvatarId(const LLUUID& avatar_id); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + void resetData(); + + /** + * Sends update data request to server. + */ + /*virtual*/ void updateData(); + + void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); + +protected: + /** + * Process profile related data received from server. + */ + virtual void processProfileProperties(const LLAvatarData* avatar_data); + + /** + * Processes group related data received from server. + */ + virtual void processGroupProperties(const LLAvatarGroups* avatar_groups); + + /** + * Fills common for Avatar profile and My Profile fields. + */ + virtual void fillCommonData(const LLAvatarData* avatar_data); + + /** + * Fills partner data. + */ + virtual void fillPartnerData(const LLAvatarData* avatar_data); + + /** + * Fills account status. + */ + virtual void fillAccountStatus(const LLAvatarData* avatar_data); + + void onMapButtonClick(); + + /** + * Opens "Pay Resident" dialog. + */ + void pay(); + + /** + * Add/remove resident to/from your block list. + */ + void toggleBlock(); + + void onAddFriendButtonClick(); + void onIMButtonClick(); + void onTeleportButtonClick(); + + void onGroupInvite(); + + bool isGrantedToSeeOnlineStatus(); + + /** + * Displays avatar's online status if possible. + * + * Requirements from EXT-3880: + * For friends: + * - Online when online and privacy settings allow to show + * - Offline when offline and privacy settings allow to show + * - Else: nothing + * For other avatars: + * - Online when online and was not set in Preferences/"Only Friends & Groups can see when I am online" + * - Else: Offline + */ + void updateOnlineStatus(); + void processOnlineStatus(bool online); + +private: + /*virtual*/ void updateButtons(); + void onClickSetName(); + void onAvatarNameCacheSetName(const LLUUID& id, const LLAvatarName& av_name); + +private: + typedef std::map group_map_t; + group_map_t mGroups; + void openGroupProfile(); + + LLTextBox* mStatusText; + LLGroupList* mGroupList; + LLCheckBoxCtrl* mShowInSearchCheckbox; + LLTextureCtrl* mSecondLifePic; + LLTextBase* mDescriptionEdit; + LLButton* mTeleportButton; + LLButton* mShowOnMapButton; + LLButton* mBlockButton; + LLButton* mUnblockButton; + LLUICtrl* mNameLabel; + LLButton* mDisplayNameButton; + LLButton* mAddFriendButton; + LLButton* mGroupInviteButton; + LLButton* mPayButton; + LLButton* mIMButton; + + bool mVoiceStatus; + + boost::signals2::connection mAvatarNameCacheConnection; +}; + + +/** +* Panel for displaying Avatar's web profile and home page. +*/ +class LLPanelProfileWeb + : public LLPanelProfileTab + , public LLViewerMediaObserver +{ +public: + LLPanelProfileWeb(); + /*virtual*/ ~LLPanelProfileWeb(); + + /*virtual*/ void onOpen(const LLSD& key); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + void resetData(); -std::string getProfileURL(const std::string& agent_name); + /** + * Saves changes. + */ + void apply(LLAvatarData* data); + + /** + * Loads web profile. + */ + /*virtual*/ void updateData(); + + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + + void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); + +protected: + /*virtual*/ void updateButtons(); + void onCommitLoad(LLUICtrl* ctrl); + void onCommitWebProfile(); + +private: + std::string mURLHome; + std::string mURLWebProfile; + LLMediaCtrl* mWebBrowser; + LLButton* mWebProfileButton; + LLUICtrl* mLoadButton; + LLLineEditor* mUrlEdit; + + LLFrameTimer mPerformanceTimer; + bool mFirstNavigate; + + boost::signals2::connection mAvatarNameCacheConnection; +}; /** -* Base class for Profile View and My Profile. +* Panel for displaying Avatar's interests. */ -class LLPanelProfile : public LLPanel +class LLPanelProfileInterests + : public LLPanelProfileTab { - LOG_CLASS(LLPanelProfile); +public: + LLPanelProfileInterests(); + /*virtual*/ ~LLPanelProfileInterests(); + + /*virtual*/ void onOpen(const LLSD& key); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + void resetData(); + + /** + * Saves changes. + */ + virtual void apply(); + +protected: + /*virtual*/ void updateButtons(); + +private: + LLCheckBoxCtrl* mWantChecks[8]; + LLCheckBoxCtrl* mSkillChecks[6]; + LLLineEditor* mWantToEditor; + LLLineEditor* mSkillsEditor; + LLLineEditor* mLanguagesEditor; +}; + + +/** +* Panel for displaying Avatar's first life related info. +*/ +class LLPanelProfileFirstLife + : public LLPanelProfileTab +{ public: + LLPanelProfileFirstLife(); + /*virtual*/ ~LLPanelProfileFirstLife(); + + /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ BOOL postBuild(); - /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + void resetData(); + + /** + * Saves changes. + */ + void apply(LLAvatarData* data); + +protected: + /*virtual*/ void updateButtons(); + void onDescriptionFocusReceived(); + + LLTextEditor* mDescriptionEdit; + LLTextureCtrl* mPicture; + + bool mIsEditing; + std::string mCurrentDescription; +}; + +/** + * Panel for displaying Avatar's notes and modifying friend's rights. + */ +class LLPanelProfileNotes + : public LLPanelProfileTab + , public LLFriendObserver +{ +public: + LLPanelProfileNotes(); + /*virtual*/ ~LLPanelProfileNotes(); + + virtual void setAvatarId(const LLUUID& avatar_id); + + /** + * LLFriendObserver trigger + */ + virtual void changed(U32 mask); + /*virtual*/ void onOpen(const LLSD& key); - virtual void openPanel(LLPanel* panel, const LLSD& params); + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + void resetData(); - virtual void closePanel(LLPanel* panel); + /*virtual*/ void updateData(); - S32 notifyParent(const LLSD& info); + /** + * Saves changes. + */ + virtual void apply(); protected: + /** + * Fills rights data for friends. + */ + void fillRightsData(); + + void rightsConfirmationCallback(const LLSD& notification, const LLSD& response, S32 rights); + void confirmModifyRights(bool grant, S32 rights); + void onCommitRights(); + void onCommitNotes(); + void enableCheckboxes(bool enable); + + LLCheckBoxCtrl* mOnlineStatus; + LLCheckBoxCtrl* mMapRights; + LLCheckBoxCtrl* mEditObjectRights; + LLTextEditor* mNotesEditor; +}; + + +/** +* Container panel for the profile tabs +*/ +class LLPanelProfile + : public LLPanelProfileTab +{ +public: + LLPanelProfile(); + /*virtual*/ ~LLPanelProfile(); + + /*virtual*/ BOOL postBuild(); - LLPanelProfile(); + /*virtual*/ void updateData(); - virtual void onTabSelected(const LLSD& param); + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); - const LLUUID& getAvatarId() { return mAvatarId; } + /*virtual*/ void onOpen(const LLSD& key); - void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; } + /** + * Saves changes. + */ + void apply(); - typedef std::map profile_tabs_t; + void showPick(const LLUUID& pick_id = LLUUID::null); - profile_tabs_t& getTabContainer() { return mTabContainer; } + void showClassified(const LLUUID& classified_id = LLUUID::null, bool edit = false); private: + void onTabChange(); - //-- ChildStack begins ---------------------------------------------------- - class ChildStack - { - LOG_CLASS(LLPanelProfile::ChildStack); - public: - ChildStack(); - ~ChildStack(); - void setParent(LLPanel* parent); - - bool push(); - bool pop(); - void preParentReshape(); - void postParentReshape(); - - private: - void dump(); - - typedef LLView::child_list_t view_list_t; - typedef std::list stack_t; - - stack_t mStack; - stack_t mSavedStack; - LLPanel* mParent; - }; - //-- ChildStack ends ------------------------------------------------------ - - profile_tabs_t mTabContainer; - ChildStack mChildStack; - LLUUID mAvatarId; + LLPanelProfileSecondLife* mPanelSecondlife; + LLPanelProfileWeb* mPanelWeb; + LLPanelProfileInterests* mPanelInterests; + LLPanelProfilePicks* mPanelPicks; + LLPanelProfileClassifieds* mPanelClassifieds; + LLPanelProfileFirstLife* mPanelFirstlife; + LLPanelProfileNotes* mPanelNotes; + LLTabContainer* mTabContainer; }; #endif //LL_LLPANELPROFILE_H diff --git a/indra/newview/llpanelprofileclassifieds.cpp b/indra/newview/llpanelprofileclassifieds.cpp new file mode 100644 index 0000000000..49f347dbda --- /dev/null +++ b/indra/newview/llpanelprofileclassifieds.cpp @@ -0,0 +1,1331 @@ +/** + * @file llpanelprofileclassifieds.cpp + * @brief LLPanelProfileClassifieds and related class implementations + * + * $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$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelprofileclassifieds.h" + +#include "llagent.h" +#include "llavataractions.h" +#include "llavatarpropertiesprocessor.h" +#include "llclassifiedflags.h" +#include "llcombobox.h" +#include "llcommandhandler.h" // for classified HTML detail page click tracking +#include "llcorehttputil.h" +#include "lldispatcher.h" +#include "llfloaterreg.h" +#include "llfloaterworldmap.h" +#include "lliconctrl.h" +#include "lllineeditor.h" +#include "llnotifications.h" +#include "llnotificationsutil.h" +#include "llpanelavatar.h" +#include "llparcel.h" +#include "llregistry.h" +#include "llscrollcontainer.h" +#include "llstatusbar.h" +#include "lltabcontainer.h" +#include "lltexteditor.h" +#include "lltexturectrl.h" +#include "lltrans.h" +#include "llviewergenericmessage.h" // send_generic_message +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewertexture.h" +#include "llviewertexture.h" + + +//*TODO: verify this limit +const S32 MAX_AVATAR_CLASSIFIEDS = 100; + +const S32 MINIMUM_PRICE_FOR_LISTING = 50; // L$ + +//static +LLPanelProfileClassified::panel_list_t LLPanelProfileClassified::sAllPanels; + +static LLPanelInjector t_panel_profile_classifieds("panel_profile_classifieds"); +static LLPanelInjector t_panel_profile_classified("panel_profile_classified"); + +class LLClassifiedHandler : public LLCommandHandler +{ +public: + // throttle calls from untrusted browsers + LLClassifiedHandler() : LLCommandHandler("classified", UNTRUSTED_THROTTLE) {} + + bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + { + if (!LLUI::sSettingGroups["config"]->getBOOL("EnableClassifieds")) + { + LLNotificationsUtil::add("NoClassifieds", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); + return true; + } + + // handle app/classified/create urls first + if (params.size() == 1 && params[0].asString() == "create") + { + LLAvatarActions::showClassifieds(gAgent.getID()); + return true; + } + + // then handle the general app/classified/{UUID}/{CMD} urls + if (params.size() < 2) + { + return false; + } + + // get the ID for the classified + LLUUID classified_id; + if (!classified_id.set(params[0], FALSE)) + { + return false; + } + + // show the classified in the side tray. + // need to ask the server for more info first though... + const std::string verb = params[1].asString(); + if (verb == "about") + { + LLAvatarActions::showClassified(gAgent.getID(), classified_id, false); + return true; + } + else if (verb == "edit") + { + LLAvatarActions::showClassified(gAgent.getID(), classified_id, true); + return true; + } + + return false; + } +}; +LLClassifiedHandler gClassifiedHandler; + +////////////////////////////////////////////////////////////////////////// + + +//----------------------------------------------------------------------------- +// LLPanelProfileClassifieds +//----------------------------------------------------------------------------- + +LLPanelProfileClassifieds::LLPanelProfileClassifieds() + : LLPanelProfileTab() + , mClassifiedToSelectOnLoad(LLUUID::null) + , mClassifiedEditOnLoad(false) +{ +} + +LLPanelProfileClassifieds::~LLPanelProfileClassifieds() +{ +} + +void LLPanelProfileClassifieds::onOpen(const LLSD& key) +{ + LLPanelProfileTab::onOpen(key); + + resetData(); + + if (getSelfProfile() && !getEmbedded()) + { + mNewButton->setVisible(TRUE); + mNewButton->setEnabled(FALSE); + + mDeleteButton->setVisible(TRUE); + mDeleteButton->setEnabled(FALSE); + } +} + +void LLPanelProfileClassifieds::selectClassified(const LLUUID& classified_id, bool edit) +{ + if (getIsLoaded()) + { + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfileClassified* classified_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (classified_panel) + { + if (classified_panel->getClassifiedId() == classified_id) + { + mTabContainer->selectTabPanel(classified_panel); + if (edit) + { + classified_panel->setEditMode(TRUE); + } + break; + } + } + } + } + else + { + mClassifiedToSelectOnLoad = classified_id; + mClassifiedEditOnLoad = edit; + } +} + +BOOL LLPanelProfileClassifieds::postBuild() +{ + mTabContainer = getChild("tab_classifieds"); + mNoItemsLabel = getChild("classifieds_panel_text"); + mNewButton = getChild("new_btn"); + mDeleteButton = getChild("delete_btn"); + + mNewButton->setCommitCallback(boost::bind(&LLPanelProfileClassifieds::onClickNewBtn, this)); + mDeleteButton->setCommitCallback(boost::bind(&LLPanelProfileClassifieds::onClickDelete, this)); + + return TRUE; +} + +void LLPanelProfileClassifieds::onClickNewBtn() +{ + mNoItemsLabel->setVisible(FALSE); + LLPanelProfileClassified* classified_panel = LLPanelProfileClassified::create(); + classified_panel->onOpen(LLSD()); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(classified_panel). + select_tab(true). + label(classified_panel->getClassifiedName())); + updateButtons(); +} + +void LLPanelProfileClassifieds::onClickDelete() +{ + LLPanelProfileClassified* classified_panel = dynamic_cast(mTabContainer->getCurrentPanel()); + if (classified_panel) + { + LLUUID classified_id = classified_panel->getClassifiedId(); + LLSD args; + args["PICK"] = classified_panel->getClassifiedName(); + LLSD payload; + payload["classified_id"] = classified_id; + payload["tab_idx"] = mTabContainer->getCurrentPanelIndex(); + LLNotificationsUtil::add("DeleteAvatarPick", args, payload, + boost::bind(&LLPanelProfileClassifieds::callbackDeleteClassified, this, _1, _2)); + } +} + +void LLPanelProfileClassifieds::callbackDeleteClassified(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (0 == option) + { + LLUUID classified_id = notification["payload"]["classified_id"].asUUID(); + S32 tab_idx = notification["payload"]["tab_idx"].asInteger(); + + LLPanelProfileClassified* classified_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (classified_panel && classified_panel->getClassifiedId() == classified_id) + { + mTabContainer->removeTabPanel(classified_panel); + } + + if (classified_id.notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedDelete(classified_id); + } + + updateButtons(); + } +} + +void LLPanelProfileClassifieds::processProperties(void* data, EAvatarProcessorType type) +{ + if ((APT_CLASSIFIEDS == type) || (APT_CLASSIFIED_INFO == type)) + { + LLUUID avatar_id = getAvatarId(); + + LLAvatarClassifieds* c_info = static_cast(data); + if (c_info && getAvatarId() == c_info->target_id) + { + // do not clear classified list in case we will receive two or more data packets. + // list has been cleared in updateData(). (fix for EXT-6436) + LLUUID selected_id = mClassifiedToSelectOnLoad; + + LLAvatarClassifieds::classifieds_list_t::const_iterator it = c_info->classifieds_list.begin(); + for (; c_info->classifieds_list.end() != it; ++it) + { + LLAvatarClassifieds::classified_data c_data = *it; + + LLPanelProfileClassified* classified_panel = LLPanelProfileClassified::create(); + + LLSD params; + params["classified_creator_id"] = avatar_id; + params["classified_id"] = c_data.classified_id; + params["classified_name"] = c_data.name; + params["from_search"] = (selected_id == c_data.classified_id); //SLURL handling and stats tracking + params["edit"] = (selected_id == c_data.classified_id) && mClassifiedEditOnLoad; + classified_panel->onOpen(params); + + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(classified_panel). + select_tab(selected_id == c_data.classified_id). + label(c_data.name)); + + if (selected_id == c_data.classified_id) + { + mClassifiedToSelectOnLoad = LLUUID::null; + mClassifiedEditOnLoad = false; + } + } + + BOOL no_data = !mTabContainer->getTabCount(); + mNoItemsLabel->setVisible(no_data); + if (no_data) + { + if(getSelfProfile()) + { + mNoItemsLabel->setValue(LLTrans::getString("NoClassifiedsText")); + } + else + { + mNoItemsLabel->setValue(LLTrans::getString("NoAvatarClassifiedsText")); + } + } + else if (selected_id.isNull()) + { + mTabContainer->selectFirstTab(); + } + + updateButtons(); + } + } +} + +void LLPanelProfileClassifieds::resetData() +{ + resetLoading(); + mTabContainer->deleteAllTabs(); +} + +void LLPanelProfileClassifieds::updateButtons() +{ + LLPanelProfileTab::updateButtons(); + + if (getSelfProfile() && !getEmbedded()) + { + mNewButton->setEnabled(canAddNewClassified()); + mDeleteButton->setEnabled(canDeleteClassified()); + } +} + +void LLPanelProfileClassifieds::updateData() +{ + // Send picks request only once + LLUUID avatar_id = getAvatarId(); + if (!getIsLoading() && avatar_id.notNull()) + { + setIsLoading(); + mNoItemsLabel->setValue(LLTrans::getString("PicksClassifiedsLoadingText")); + mNoItemsLabel->setVisible(TRUE); + + LLAvatarPropertiesProcessor::getInstance()->sendAvatarClassifiedsRequest(avatar_id); + } +} + +bool LLPanelProfileClassifieds::canAddNewClassified() +{ + return (mTabContainer->getTabCount() < MAX_AVATAR_CLASSIFIEDS); +} + +bool LLPanelProfileClassifieds::canDeleteClassified() +{ + return (mTabContainer->getTabCount() > 0); +} + + +//----------------------------------------------------------------------------- +// LLDispatchClassifiedClickThrough +//----------------------------------------------------------------------------- + +// "classifiedclickthrough" +// strings[0] = classified_id +// strings[1] = teleport_clicks +// strings[2] = map_clicks +// strings[3] = profile_clicks +class LLDispatchClassifiedClickThrough : public LLDispatchHandler +{ +public: + virtual bool operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) + { + if (strings.size() != 4) return false; + LLUUID classified_id(strings[0]); + S32 teleport_clicks = atoi(strings[1].c_str()); + S32 map_clicks = atoi(strings[2].c_str()); + S32 profile_clicks = atoi(strings[3].c_str()); + + LLPanelProfileClassified::setClickThrough( + classified_id, teleport_clicks, map_clicks, profile_clicks, false); + + return true; + } +}; +static LLDispatchClassifiedClickThrough sClassifiedClickThrough; + + +//----------------------------------------------------------------------------- +// LLPanelProfileClassified +//----------------------------------------------------------------------------- + +static const S32 CB_ITEM_MATURE = 0; +static const S32 CB_ITEM_PG = 1; + +LLPanelProfileClassified::LLPanelProfileClassified() + : LLPanelProfileTab() + , mInfoLoaded(false) + , mTeleportClicksOld(0) + , mMapClicksOld(0) + , mProfileClicksOld(0) + , mTeleportClicksNew(0) + , mMapClicksNew(0) + , mProfileClicksNew(0) + , mSnapshotCtrl(NULL) + , mPublishFloater(NULL) + , mIsNew(false) + , mIsNewWithErrors(false) + , mCanClose(false) + , mEditMode(false) + , mEditOnLoad(false) +{ + sAllPanels.push_back(this); +} + +LLPanelProfileClassified::~LLPanelProfileClassified() +{ + sAllPanels.remove(this); + gGenericDispatcher.addHandler("classifiedclickthrough", NULL); // deregister our handler +} + +//static +LLPanelProfileClassified* LLPanelProfileClassified::create() +{ + LLPanelProfileClassified* panel = new LLPanelProfileClassified(); + panel->buildFromFile("panel_profile_classified.xml"); + return panel; +} + +BOOL LLPanelProfileClassified::postBuild() +{ + mScrollContainer = getChild("profile_scroll"); + mInfoPanel = getChild("info_panel"); + mEditPanel = getChild("edit_panel"); + + mSnapshotCtrl = getChild("classified_snapshot"); + mEditIcon = getChild("edit_icon"); + + //info + mClassifiedNameText = getChild("classified_name"); + mClassifiedDescText = getChild("classified_desc"); + mLocationText = getChild("classified_location"); + mCategoryText = getChild("category"); + mContentTypeText = getChild("content_type"); + mContentTypeM = getChild("content_type_moderate"); + mContentTypeG = getChild("content_type_general"); + mPriceText = getChild("price_for_listing"); + mAutoRenewText = getChild("auto_renew"); + + mMapButton = getChild("show_on_map_btn"); + mTeleportButton = getChild("teleport_btn"); + mEditButton = getChild("edit_btn"); + + //edit + mClassifiedNameEdit = getChild("classified_name_edit"); + mClassifiedDescEdit = getChild("classified_desc_edit"); + mLocationEdit = getChild("classified_location_edit"); + mCategoryCombo = getChild("category_edit"); + mContentTypeCombo = getChild("content_type_edit"); + mPriceEdit = getChild("price_for_listing_edit"); + mPricelabel = getChild("price_for_listing_edit_label"); + mAutoRenewEdit = getChild("auto_renew_edit"); + + mSaveButton = getChild("save_changes_btn"); + mSetLocationButton = getChild("set_to_curr_location_btn"); + mCancelButton = getChild("cancel_btn"); + + mSnapshotCtrl->setOnSelectCallback(boost::bind(&LLPanelProfileClassified::onTextureSelected, this)); + mSnapshotCtrl->setMouseEnterCallback(boost::bind(&LLPanelProfileClassified::onTexturePickerMouseEnter, this)); + mSnapshotCtrl->setMouseLeaveCallback(boost::bind(&LLPanelProfileClassified::onTexturePickerMouseLeave, this)); + mEditIcon->setVisible(false); + + mMapButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onMapClick, this)); + mTeleportButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onTeleportClick, this)); + mEditButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onEditClick, this)); + mSaveButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onSaveClick, this)); + mSetLocationButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onSetLocationClick, this)); + mCancelButton->setCommitCallback(boost::bind(&LLPanelProfileClassified::onCancelClick, this)); + + LLClassifiedInfo::cat_map::iterator iter; + for (iter = LLClassifiedInfo::sCategories.begin(); + iter != LLClassifiedInfo::sCategories.end(); + iter++) + { + mCategoryCombo->add(LLTrans::getString(iter->second)); + } + + mClassifiedNameEdit->setKeystrokeCallback(boost::bind(&LLPanelProfileClassified::onChange, this), NULL); + mClassifiedDescEdit->setKeystrokeCallback(boost::bind(&LLPanelProfileClassified::onChange, this)); + mCategoryCombo->setCommitCallback(boost::bind(&LLPanelProfileClassified::onChange, this)); + mContentTypeCombo->setCommitCallback(boost::bind(&LLPanelProfileClassified::onChange, this)); + mPriceEdit->setCommitCallback(boost::bind(&LLPanelProfileClassified::onChange, this)); + mAutoRenewEdit->setCommitCallback(boost::bind(&LLPanelProfileClassified::onChange, this)); + + return TRUE; +} + +void LLPanelProfileClassified::onOpen(const LLSD& key) +{ + mIsNew = key.isUndefined(); + + resetData(); + resetControls(); + scrollToTop(); + + // classified is not created yet + bool is_new = isNew() || isNewWithErrors(); + + if(is_new) + { + LLPanelProfileTab::setAvatarId(gAgent.getID()); + + setPosGlobal(gAgent.getPositionGlobal()); + + LLUUID snapshot_id = LLUUID::null; + std::string desc; + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if(parcel) + { + desc = parcel->getDesc(); + snapshot_id = parcel->getSnapshotID(); + } + + std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish"); + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + region_name = region->getName(); + } + + setClassifiedName(makeClassifiedName()); + setDescription(desc); + setSnapshotId(snapshot_id); + setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal())); + // server will set valid parcel id + setParcelId(LLUUID::null); + + mSaveButton->setLabelArg("[LABEL]", getString("publish_label")); + + setEditMode(TRUE); + enableSave(true); + enableEditing(true); + resetDirty(); + setInfoLoaded(false); + } + else + { + LLUUID avatar_id = key["classified_creator_id"]; + if(avatar_id.isNull()) + { + return; + } + LLPanelProfileTab::setAvatarId(avatar_id); + + setClassifiedId(key["classified_id"]); + setClassifiedName(key["classified_name"]); + setFromSearch(key["from_search"]); + mEditOnLoad = key["edit"]; + + LL_INFOS() << "Opening classified [" << getClassifiedName() << "] (" << getClassifiedId() << ")" << LL_ENDL; + + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId()); + + gGenericDispatcher.addHandler("classifiedclickthrough", &sClassifiedClickThrough); + + if (gAgent.getRegion()) + { + // While we're at it let's get the stats from the new table if that + // capability exists. + std::string url = gAgent.getRegion()->getCapability("SearchStatRequest"); + if (!url.empty()) + { + LL_INFOS() << "Classified stat request via capability" << LL_ENDL; + LLSD body; + LLUUID classifiedId = getClassifiedId(); + body["classified_id"] = classifiedId; + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body, + boost::bind(&LLPanelProfileClassified::handleSearchStatResponse, classifiedId, _1)); + } + } + // Update classified click stats. + // *TODO: Should we do this when opening not from search? + if (!fromSearch() ) + { + sendClickMessage("profile"); + } + + setInfoLoaded(false); + } + + + mPricelabel->setVisible(is_new); + mPriceEdit->setVisible(is_new); + + bool is_self = getSelfProfile(); + getChildView("auto_renew_layout_panel")->setVisible(is_self); + getChildView("clickthrough_layout_panel")->setVisible(is_self); + + updateButtons(); +} + +void LLPanelProfileClassified::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_CLASSIFIED_INFO != type) + { + return; + } + + LLAvatarClassifiedInfo* c_info = static_cast(data); + if(c_info && getClassifiedId() == c_info->classified_id) + { + // see LLPanelProfileClassified::sendUpdate() for notes + mIsNewWithErrors = false; + + setClassifiedName(c_info->name); + setDescription(c_info->description); + setSnapshotId(c_info->snapshot_id); + setParcelId(c_info->parcel_id); + setPosGlobal(c_info->pos_global); + setSimName(c_info->sim_name); + + setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); + + mCategoryText->setValue(LLClassifiedInfo::sCategories[c_info->category]); + // *HACK see LLPanelProfileClassified::sendUpdate() + setCategory(c_info->category - 1); + + bool mature = is_cf_mature(c_info->flags); + setContentType(mature); + + bool auto_renew = is_cf_auto_renew(c_info->flags); + std::string auto_renew_str = auto_renew ? getString("auto_renew_on") : getString("auto_renew_off"); + mAutoRenewText->setValue(auto_renew_str); + mAutoRenewEdit->setValue(auto_renew); + + static LLUIString price_str = getString("l$_price"); + price_str.setArg("[PRICE]", llformat("%d", c_info->price_for_listing)); + mPriceText->setValue(LLSD(price_str)); + mPriceEdit->setValue(c_info->price_for_listing); + mPriceEdit->setEnabled(isNew()); + + static std::string date_fmt = getString("date_fmt"); + std::string date_str = date_fmt; + LLStringUtil::format(date_str, LLSD().with("datetime", (S32) c_info->creation_date)); + getChild("creation_date")->setValue(date_str); + + resetDirty(); + setInfoLoaded(true); + enableSave(false); + enableEditing(true); + + // for just created classified - in case user opened edit panel before processProperties() callback + mSaveButton->setLabelArg("[LABEL]", getString("save_label")); + + updateButtons(); + + if (mEditOnLoad) + { + setEditMode(TRUE); + } + } + +} + +void LLPanelProfileClassified::setEditMode(BOOL edit_mode) +{ + mEditMode = edit_mode; + + mInfoPanel->setVisible(!edit_mode); + mEditPanel->setVisible(edit_mode); + + // snapshot control is common between info and edit, + // enable it only when in edit mode + mSnapshotCtrl->setEnabled(edit_mode); + + scrollToTop(); + updateButtons(); +} + +void LLPanelProfileClassified::updateButtons() +{ + bool edit_mode = getEditMode(); + mMapButton->setVisible(!edit_mode); + mTeleportButton->setVisible(!edit_mode); + mSaveButton->setVisible(edit_mode); + mCancelButton->setVisible(edit_mode); + mEditButton->setVisible(!edit_mode && getSelfProfile()); +} + +void LLPanelProfileClassified::enableEditing(bool enable) +{ + mEditButton->setEnabled(enable); + mClassifiedNameEdit->setEnabled(enable); + mClassifiedDescEdit->setEnabled(enable); + mSetLocationButton->setEnabled(enable); + mCategoryCombo->setEnabled(enable); + mContentTypeCombo->setEnabled(enable); + mPriceEdit->setEnabled(enable); + mAutoRenewEdit->setEnabled(enable); +} + +void LLPanelProfileClassified::resetControls() +{ + updateButtons(); + + mCategoryCombo->setCurrentByIndex(0); + mContentTypeCombo->setCurrentByIndex(0); + mAutoRenewEdit->setValue(false); + mPriceEdit->setValue(MINIMUM_PRICE_FOR_LISTING); + mPriceEdit->setEnabled(TRUE); +} + +void LLPanelProfileClassified::onEditClick() +{ + setEditMode(TRUE); +} + +void LLPanelProfileClassified::onCancelClick() +{ + // Reload data to undo changes to forms + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId()); + + setInfoLoaded(false); + + setEditMode(FALSE); +} + +void LLPanelProfileClassified::onSaveClick() +{ + mCanClose = false; + + if(!isValidName()) + { + notifyInvalidName(); + return; + } + if(isNew() || isNewWithErrors()) + { + if(gStatusBar->getBalance() < getPriceForListing()) + { + LLNotificationsUtil::add("ClassifiedInsufficientFunds"); + return; + } + + mPublishFloater = LLFloaterReg::findTypedInstance( + "publish_classified", LLSD()); + + if(!mPublishFloater) + { + mPublishFloater = LLFloaterReg::getTypedInstance( + "publish_classified", LLSD()); + + mPublishFloater->setPublishClickedCallback(boost::bind + (&LLPanelProfileClassified::onPublishFloaterPublishClicked, this)); + } + + // set spinner value before it has focus or value wont be set + mPublishFloater->setPrice(getPriceForListing()); + mPublishFloater->openFloater(mPublishFloater->getKey()); + mPublishFloater->center(); + } + else + { + doSave(); + } +} + +/*static*/ +void LLPanelProfileClassified::handleSearchStatResponse(LLUUID classifiedId, LLSD result) +{ + S32 teleport = result["teleport_clicks"].asInteger(); + S32 map = result["map_clicks"].asInteger(); + S32 profile = result["profile_clicks"].asInteger(); + S32 search_teleport = result["search_teleport_clicks"].asInteger(); + S32 search_map = result["search_map_clicks"].asInteger(); + S32 search_profile = result["search_profile_clicks"].asInteger(); + + LLPanelProfileClassified::setClickThrough(classifiedId, + teleport + search_teleport, + map + search_map, + profile + search_profile, + true); +} + +void LLPanelProfileClassified::resetData() +{ + setClassifiedName(LLStringUtil::null); + setDescription(LLStringUtil::null); + setClassifiedLocation(LLStringUtil::null); + setClassifiedId(LLUUID::null); + setSnapshotId(LLUUID::null); + setPosGlobal(LLVector3d::zero); + setParcelId(LLUUID::null); + setSimName(LLStringUtil::null); + setFromSearch(false); + + // reset click stats + mTeleportClicksOld = 0; + mMapClicksOld = 0; + mProfileClicksOld = 0; + mTeleportClicksNew = 0; + mMapClicksNew = 0; + mProfileClicksNew = 0; + + mCategoryText->setValue(LLStringUtil::null); + mContentTypeText->setValue(LLStringUtil::null); + getChild("click_through_text")->setValue(LLStringUtil::null); + mPriceEdit->setValue(LLStringUtil::null); + mEditButton->setValue(LLStringUtil::null); + getChild("creation_date")->setValue(LLStringUtil::null); + mContentTypeM->setVisible(FALSE); + mContentTypeG->setVisible(FALSE); +} + +void LLPanelProfileClassified::setClassifiedName(const std::string& name) +{ + mClassifiedNameText->setValue(name); + mClassifiedNameEdit->setValue(name); +} + +std::string LLPanelProfileClassified::getClassifiedName() +{ + return mClassifiedNameEdit->getValue().asString(); +} + +void LLPanelProfileClassified::setDescription(const std::string& desc) +{ + mClassifiedDescText->setValue(desc); + mClassifiedDescEdit->setValue(desc); +} + +std::string LLPanelProfileClassified::getDescription() +{ + return mClassifiedDescEdit->getValue().asString(); +} + +void LLPanelProfileClassified::setClassifiedLocation(const std::string& location) +{ + mLocationText->setValue(location); + mLocationEdit->setValue(location); +} + +std::string LLPanelProfileClassified::getClassifiedLocation() +{ + return mLocationText->getValue().asString(); +} + +void LLPanelProfileClassified::setSnapshotId(const LLUUID& id) +{ + mSnapshotCtrl->setValue(id); +} + +LLUUID LLPanelProfileClassified::getSnapshotId() +{ + return mSnapshotCtrl->getValue().asUUID(); +} + +// static +void LLPanelProfileClassified::setClickThrough( + const LLUUID& classified_id, + S32 teleport, + S32 map, + S32 profile, + bool from_new_table) +{ + LL_INFOS() << "Click-through data for classified " << classified_id << " arrived: [" + << teleport << ", " << map << ", " << profile << "] (" + << (from_new_table ? "new" : "old") << ")" << LL_ENDL; + + for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) + { + LLPanelProfileClassified* self = *iter; + if (self->getClassifiedId() != classified_id) + { + continue; + } + + // *HACK: Skip LLPanelProfileClassified instances: they don't display clicks data. + // Those instances should not be in the list at all. + if (typeid(*self) != typeid(LLPanelProfileClassified)) + { + continue; + } + + LL_INFOS() << "Updating classified info panel" << LL_ENDL; + + // We need to check to see if the data came from the new stat_table + // or the old classified table. We also need to cache the data from + // the two separate sources so as to display the aggregate totals. + + if (from_new_table) + { + self->mTeleportClicksNew = teleport; + self->mMapClicksNew = map; + self->mProfileClicksNew = profile; + } + else + { + self->mTeleportClicksOld = teleport; + self->mMapClicksOld = map; + self->mProfileClicksOld = profile; + } + + static LLUIString ct_str = self->getString("click_through_text_fmt"); + + ct_str.setArg("[TELEPORT]", llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld)); + ct_str.setArg("[MAP]", llformat("%d", self->mMapClicksNew + self->mMapClicksOld)); + ct_str.setArg("[PROFILE]", llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld)); + + self->getChild("click_through_text")->setValue(ct_str.getString()); + // *HACK: remove this when there is enough room for click stats in the info panel + self->getChildView("click_through_text")->setToolTip(ct_str.getString()); + + LL_INFOS() << "teleport: " << llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld) + << ", map: " << llformat("%d", self->mMapClicksNew + self->mMapClicksOld) + << ", profile: " << llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld) + << LL_ENDL; + } +} + +// static +std::string LLPanelProfileClassified::createLocationText( + const std::string& original_name, + const std::string& sim_name, + const LLVector3d& pos_global) +{ + std::string location_text; + + location_text.append(original_name); + + if (!sim_name.empty()) + { + if (!location_text.empty()) + location_text.append(", "); + location_text.append(sim_name); + } + + if (!location_text.empty()) + location_text.append(" "); + + if (!pos_global.isNull()) + { + S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = ll_round((F32)pos_global.mdV[VZ]); + location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); + } + + return location_text; +} + +void LLPanelProfileClassified::scrollToTop() +{ + if (mScrollContainer) + { + mScrollContainer->goToTop(); + } +} + +//info +// static +// *TODO: move out of the panel +void LLPanelProfileClassified::sendClickMessage( + const std::string& type, + bool from_search, + const LLUUID& classified_id, + const LLUUID& parcel_id, + const LLVector3d& global_pos, + const std::string& sim_name) +{ + if (gAgent.getRegion()) + { + // You're allowed to click on your own ads to reassure yourself + // that the system is working. + LLSD body; + body["type"] = type; + body["from_search"] = from_search; + body["classified_id"] = classified_id; + body["parcel_id"] = parcel_id; + body["dest_pos_global"] = global_pos.getValue(); + body["region_name"] = sim_name; + + std::string url = gAgent.getRegion()->getCapability("SearchStatTracking"); + LL_INFOS() << "Sending click msg via capability (url=" << url << ")" << LL_ENDL; + LL_INFOS() << "body: [" << body << "]" << LL_ENDL; + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, + "SearchStatTracking Click report sent.", "SearchStatTracking Click report NOT sent."); + } +} + +void LLPanelProfileClassified::sendClickMessage(const std::string& type) +{ + sendClickMessage( + type, + fromSearch(), + getClassifiedId(), + getParcelId(), + getPosGlobal(), + getSimName()); +} + +void LLPanelProfileClassified::onMapClick() +{ + sendClickMessage("map"); + LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); + LLFloaterReg::showInstance("world_map", "center"); +} + +void LLPanelProfileClassified::onTeleportClick() +{ + if (!getPosGlobal().isExactlyZero()) + { + sendClickMessage("teleport"); + gAgent.teleportViaLocation(getPosGlobal()); + LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); + } +} + +BOOL LLPanelProfileClassified::isDirty() const +{ + if(mIsNew) + { + return TRUE; + } + + BOOL dirty = false; + dirty |= mSnapshotCtrl->isDirty(); + dirty |= mClassifiedNameEdit->isDirty(); + dirty |= mClassifiedDescEdit->isDirty(); + dirty |= mCategoryCombo->isDirty(); + dirty |= mContentTypeCombo->isDirty(); + dirty |= mAutoRenewEdit->isDirty(); + dirty |= mPriceEdit->isDirty(); + + return dirty; +} + +void LLPanelProfileClassified::resetDirty() +{ + mSnapshotCtrl->resetDirty(); + mClassifiedNameEdit->resetDirty(); + + // call blockUndo() to really reset dirty(and make isDirty work as intended) + mClassifiedDescEdit->blockUndo(); + mClassifiedDescEdit->resetDirty(); + + mCategoryCombo->resetDirty(); + mContentTypeCombo->resetDirty(); + mAutoRenewEdit->resetDirty(); + mPriceEdit->resetDirty(); +} + +bool LLPanelProfileClassified::canClose() +{ + return mCanClose; +} + +U32 LLPanelProfileClassified::getContentType() +{ + return mContentTypeCombo->getCurrentIndex(); +} + +void LLPanelProfileClassified::setContentType(bool mature) +{ + static std::string mature_str = getString("type_mature"); + static std::string pg_str = getString("type_pg"); + mContentTypeText->setValue(mature ? mature_str : pg_str); + mContentTypeM->setVisible(mature); + mContentTypeG->setVisible(!mature); + mContentTypeCombo->setCurrentByIndex(mature ? CB_ITEM_MATURE : CB_ITEM_PG); + mContentTypeCombo->resetDirty(); +} + +bool LLPanelProfileClassified::getAutoRenew() +{ + return mAutoRenewEdit->getValue().asBoolean(); +} + +void LLPanelProfileClassified::sendUpdate() +{ + LLAvatarClassifiedInfo c_data; + + if(getClassifiedId().isNull()) + { + setClassifiedId(LLUUID::generateNewID()); + } + + c_data.agent_id = gAgent.getID(); + c_data.classified_id = getClassifiedId(); + // *HACK + // Categories on server start with 1 while combo-box index starts with 0 + c_data.category = getCategory() + 1; + c_data.name = getClassifiedName(); + c_data.description = getDescription(); + c_data.parcel_id = getParcelId(); + c_data.snapshot_id = getSnapshotId(); + c_data.pos_global = getPosGlobal(); + c_data.flags = getFlags(); + c_data.price_for_listing = getPriceForListing(); + + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoUpdate(&c_data); + + if(isNew()) + { + // Lets assume there will be some error. + // Successful sendClassifiedInfoUpdate will trigger processProperties and + // let us know there was no error. + mIsNewWithErrors = true; + } +} + +U32 LLPanelProfileClassified::getCategory() +{ + return mCategoryCombo->getCurrentIndex(); +} + +void LLPanelProfileClassified::setCategory(U32 category) +{ + mCategoryCombo->setCurrentByIndex(category); + mCategoryCombo->resetDirty(); +} + +U8 LLPanelProfileClassified::getFlags() +{ + bool auto_renew = mAutoRenewEdit->getValue().asBoolean(); + + bool mature = mContentTypeCombo->getCurrentIndex() == CB_ITEM_MATURE; + + return pack_classified_flags_request(auto_renew, false, mature, false); +} + +void LLPanelProfileClassified::enableSave(bool enable) +{ + mSaveButton->setEnabled(enable); +} + +std::string LLPanelProfileClassified::makeClassifiedName() +{ + std::string name; + + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if(parcel) + { + name = parcel->getName(); + } + + if(!name.empty()) + { + return name; + } + + LLViewerRegion* region = gAgent.getRegion(); + if(region) + { + name = region->getName(); + } + + return name; +} + +S32 LLPanelProfileClassified::getPriceForListing() +{ + return mPriceEdit->getValue().asInteger(); +} + +void LLPanelProfileClassified::setPriceForListing(S32 price) +{ + mPriceEdit->setValue(price); +} + +void LLPanelProfileClassified::onSetLocationClick() +{ + setPosGlobal(gAgent.getPositionGlobal()); + setParcelId(LLUUID::null); + + std::string region_name = LLTrans::getString("ClassifiedUpdateAfterPublish"); + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + region_name = region->getName(); + } + + setClassifiedLocation(createLocationText(getLocationNotice(), region_name, getPosGlobal())); + + // mark classified as dirty + setValue(LLSD()); + + onChange(); +} + +void LLPanelProfileClassified::onChange() +{ + enableSave(isDirty()); +} + +void LLPanelProfileClassified::doSave() +{ + //*TODO: Fix all of this + + mCanClose = true; + sendUpdate(); + updateTabLabel(getClassifiedName()); + resetDirty(); + + if (!canClose()) + { + return; + } + + if (!isNew() && !isNewWithErrors()) + { + setEditMode(FALSE); + return; + } + + updateButtons(); +} + +void LLPanelProfileClassified::onPublishFloaterPublishClicked() +{ + setPriceForListing(mPublishFloater->getPrice()); + + doSave(); +} + +std::string LLPanelProfileClassified::getLocationNotice() +{ + static std::string location_notice = getString("location_notice"); + return location_notice; +} + +bool LLPanelProfileClassified::isValidName() +{ + std::string name = getClassifiedName(); + if (name.empty()) + { + return false; + } + if (!isalnum(name[0])) + { + return false; + } + + return true; +} + +void LLPanelProfileClassified::notifyInvalidName() +{ + std::string name = getClassifiedName(); + if (name.empty()) + { + LLNotificationsUtil::add("BlankClassifiedName"); + } + else if (!isalnum(name[0])) + { + LLNotificationsUtil::add("ClassifiedMustBeAlphanumeric"); + } +} + +void LLPanelProfileClassified::onTexturePickerMouseEnter() +{ + mEditIcon->setVisible(TRUE); +} + +void LLPanelProfileClassified::onTexturePickerMouseLeave() +{ + mEditIcon->setVisible(FALSE); +} + +void LLPanelProfileClassified::onTextureSelected() +{ + setSnapshotId(mSnapshotCtrl->getValue().asUUID()); + onChange(); +} + +void LLPanelProfileClassified::updateTabLabel(const std::string& title) +{ + setLabel(title); + LLTabContainer* parent = dynamic_cast(getParent()); + if (parent) + { + parent->setCurrentTabName(title); + } +} + + +//----------------------------------------------------------------------------- +// LLPublishClassifiedFloater +//----------------------------------------------------------------------------- + +LLPublishClassifiedFloater::LLPublishClassifiedFloater(const LLSD& key) + : LLFloater(key) +{ +} + +LLPublishClassifiedFloater::~LLPublishClassifiedFloater() +{ +} + +BOOL LLPublishClassifiedFloater::postBuild() +{ + LLFloater::postBuild(); + + childSetAction("publish_btn", boost::bind(&LLFloater::closeFloater, this, false)); + childSetAction("cancel_btn", boost::bind(&LLFloater::closeFloater, this, false)); + + return TRUE; +} + +void LLPublishClassifiedFloater::setPrice(S32 price) +{ + getChild("price_for_listing")->setValue(price); +} + +S32 LLPublishClassifiedFloater::getPrice() +{ + return getChild("price_for_listing")->getValue().asInteger(); +} + +void LLPublishClassifiedFloater::setPublishClickedCallback(const commit_signal_t::slot_type& cb) +{ + getChild("publish_btn")->setClickedCallback(cb); +} + +void LLPublishClassifiedFloater::setCancelClickedCallback(const commit_signal_t::slot_type& cb) +{ + getChild("cancel_btn")->setClickedCallback(cb); +} diff --git a/indra/newview/llpanelprofileclassifieds.h b/indra/newview/llpanelprofileclassifieds.h new file mode 100644 index 0000000000..592007305b --- /dev/null +++ b/indra/newview/llpanelprofileclassifieds.h @@ -0,0 +1,366 @@ +/** + * @file llpanelprofileclassifieds.h + * @brief LLPanelProfileClassifieds and related class implementations + * + * $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$ + */ + +#ifndef LL_PANELPROFILECLASSIFIEDS_H +#define LL_PANELPROFILECLASSIFIEDS_H + +#include "llavatarpropertiesprocessor.h" +#include "llclassifiedinfo.h" +#include "llfloater.h" +#include "llpanel.h" +#include "llpanelavatar.h" +#include "llrect.h" +#include "lluuid.h" +#include "v3dmath.h" +#include "llcoros.h" +#include "lleventcoro.h" + +class LLCheckBoxCtrl; +class LLLineEditor; +class LLMediaCtrl; +class LLScrollContainer; +class LLTabContainer; +class LLTextEditor; +class LLTextureCtrl; +class LLUICtrl; + + +class LLPublishClassifiedFloater : public LLFloater +{ +public: + LLPublishClassifiedFloater(const LLSD& key); + virtual ~LLPublishClassifiedFloater(); + + /*virtual*/ BOOL postBuild(); + + void setPrice(S32 price); + S32 getPrice(); + + void setPublishClickedCallback(const commit_signal_t::slot_type& cb); + void setCancelClickedCallback(const commit_signal_t::slot_type& cb); +}; + + +/** +* Panel for displaying Avatar's picks. +*/ +class LLPanelProfileClassifieds + : public LLPanelProfileTab +{ +public: + LLPanelProfileClassifieds(); + /*virtual*/ ~LLPanelProfileClassifieds(); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void onOpen(const LLSD& key); + + void selectClassified(const LLUUID& classified_id, bool edit); + + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + /*virtual*/ void resetData(); + + /*virtual*/ void updateButtons(); + + /*virtual*/ void updateData(); + +private: + void onClickNewBtn(); + void onClickDelete(); + void callbackDeleteClassified(const LLSD& notification, const LLSD& response); + + bool canAddNewClassified(); + bool canDeleteClassified(); + + LLTabContainer* mTabContainer; + LLUICtrl* mNoItemsLabel; + LLButton* mNewButton; + LLButton* mDeleteButton; + + LLUUID mClassifiedToSelectOnLoad; + bool mClassifiedEditOnLoad; +}; + + +class LLPanelProfileClassified + : public LLPanelProfileTab +{ +public: + + static LLPanelProfileClassified* create(); + + LLPanelProfileClassified(); + + /*virtual*/ ~LLPanelProfileClassified(); + + /*virtual*/ BOOL postBuild(); + + void onOpen(const LLSD& key); + + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + void setSnapshotId(const LLUUID& id); + + LLUUID getSnapshotId(); + + void setClassifiedId(const LLUUID& id) { mClassifiedId = id; } + + LLUUID& getClassifiedId() { return mClassifiedId; } + + void setClassifiedName(const std::string& name); + + std::string getClassifiedName(); + + void setDescription(const std::string& desc); + + std::string getDescription(); + + void setClassifiedLocation(const std::string& location); + + std::string getClassifiedLocation(); + + void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; } + + LLVector3d& getPosGlobal() { return mPosGlobal; } + + void setParcelId(const LLUUID& id) { mParcelId = id; } + + LLUUID getParcelId() { return mParcelId; } + + void setSimName(const std::string& sim_name) { mSimName = sim_name; } + + std::string getSimName() { return mSimName; } + + void setFromSearch(bool val) { mFromSearch = val; } + + bool fromSearch() { return mFromSearch; } + + bool getInfoLoaded() { return mInfoLoaded; } + + void setInfoLoaded(bool loaded) { mInfoLoaded = loaded; } + + /*virtual*/ BOOL isDirty() const; + + /*virtual*/ void resetDirty(); + + bool isNew() { return mIsNew; } + + bool isNewWithErrors() { return mIsNewWithErrors; } + + bool canClose(); + + U32 getCategory(); + + void setCategory(U32 category); + + U32 getContentType(); + + void setContentType(bool mature); + + bool getAutoRenew(); + + S32 getPriceForListing(); + + void setEditMode(BOOL edit_mode); + bool getEditMode() {return mEditMode;} + + static void setClickThrough( + const LLUUID& classified_id, + S32 teleport, + S32 map, + S32 profile, + bool from_new_table); + + static void sendClickMessage( + const std::string& type, + bool from_search, + const LLUUID& classified_id, + const LLUUID& parcel_id, + const LLVector3d& global_pos, + const std::string& sim_name); + +protected: + + /*virtual*/ void resetData(); + + void resetControls(); + + /*virtual*/ void updateButtons(); + + static std::string createLocationText( + const std::string& original_name, + const std::string& sim_name, + const LLVector3d& pos_global); + + void sendClickMessage(const std::string& type); + + void scrollToTop(); + + void onEditClick(); + void onCancelClick(); + void onSaveClick(); + void onMapClick(); + void onTeleportClick(); + + void sendUpdate(); + + void enableSave(bool enable); + + void enableEditing(bool enable); + + std::string makeClassifiedName(); + + void setPriceForListing(S32 price); + + U8 getFlags(); + + std::string getLocationNotice(); + + bool isValidName(); + + void notifyInvalidName(); + + void onSetLocationClick(); + void onChange(); + + void doSave(); + + void onPublishFloaterPublishClicked(); + + void onTexturePickerMouseEnter(); + void onTexturePickerMouseLeave(); + + void onTextureSelected(); + + + + + /** + * Callback for "Map" button, opens Map + */ + void onClickMap(); + + /** + * Callback for "Teleport" button, teleports user to Pick location. + */ + void onClickTeleport(); + + /** + * Enables/disables "Save" button + */ + void enableSaveButton(BOOL enable); + + /** + * Called when snapshot image changes. + */ + void onSnapshotChanged(); + + /** + * Callback for Pick snapshot, name and description changed event. + */ + void onPickChanged(LLUICtrl* ctrl); + + /** + * Callback for "Set Location" button click + */ + void onClickSetLocation(); + + /** + * Callback for "Save" button click + */ + void onClickSave(); + + void onDescriptionFocusReceived(); + + void updateTabLabel(const std::string& title); + +private: + + LLTextureCtrl* mSnapshotCtrl; + LLUICtrl* mEditIcon; + LLUICtrl* mClassifiedNameText; + LLUICtrl* mClassifiedDescText; + LLLineEditor* mClassifiedNameEdit; + LLTextEditor* mClassifiedDescEdit; + LLUICtrl* mLocationText; + LLUICtrl* mLocationEdit; + LLUICtrl* mCategoryText; + LLComboBox* mCategoryCombo; + LLUICtrl* mContentTypeText; + LLIconCtrl* mContentTypeM; + LLIconCtrl* mContentTypeG; + LLComboBox* mContentTypeCombo; + LLUICtrl* mPriceText; + LLUICtrl* mPriceEdit; + LLUICtrl* mPricelabel; + LLUICtrl* mAutoRenewText; + LLUICtrl* mAutoRenewEdit; + + LLButton* mMapButton; + LLButton* mTeleportButton; + LLButton* mEditButton; + LLButton* mSaveButton; + LLButton* mSetLocationButton; + LLButton* mCancelButton; + + LLScrollContainer* mScrollContainer; + LLPanel* mInfoPanel; + LLPanel* mEditPanel; + + + LLUUID mClassifiedId; + LLVector3d mPosGlobal; + LLUUID mParcelId; + std::string mSimName; + bool mFromSearch; + bool mInfoLoaded; + bool mEditMode; + + // Needed for stat tracking + S32 mTeleportClicksOld; + S32 mMapClicksOld; + S32 mProfileClicksOld; + S32 mTeleportClicksNew; + S32 mMapClicksNew; + S32 mProfileClicksNew; + + + static void handleSearchStatResponse(LLUUID classifiedId, LLSD result); + + typedef std::list panel_list_t; + static panel_list_t sAllPanels; + + + bool mIsNew; + bool mIsNewWithErrors; + bool mCanClose; + bool mEditOnLoad; + + LLPublishClassifiedFloater* mPublishFloater; +}; + +#endif // LL_PANELPROFILECLASSIFIEDS_H diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp new file mode 100644 index 0000000000..49d22f5518 --- /dev/null +++ b/indra/newview/llpanelprofilepicks.cpp @@ -0,0 +1,774 @@ +/** + * @file llpanelprofilepicks.cpp + * @brief LLPanelProfilePicks and related class implementations + * + * $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$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelprofilepicks.h" + +#include "llagent.h" +#include "llagentpicksinfo.h" +#include "llavataractions.h" +#include "llavatarpropertiesprocessor.h" +#include "llcommandhandler.h" +#include "lldispatcher.h" +#include "llfloaterreg.h" +#include "llfloaterworldmap.h" +#include "lllineeditor.h" +#include "llnotificationsutil.h" +#include "llpanelavatar.h" +#include "llpanelprofile.h" +#include "llparcel.h" +#include "lltabcontainer.h" +#include "lltextbox.h" +#include "lltexteditor.h" +#include "lltexturectrl.h" +#include "lltexturectrl.h" +#include "lltrans.h" +#include "llviewergenericmessage.h" // send_generic_message +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" + +static LLPanelInjector t_panel_profile_picks("panel_profile_picks"); +static LLPanelInjector t_panel_profile_pick("panel_profile_pick"); + + +class LLPickHandler : public LLCommandHandler +{ +public: + + // requires trusted browser to trigger + LLPickHandler() : LLCommandHandler("pick", UNTRUSTED_THROTTLE) { } + + bool handle(const LLSD& params, const LLSD& query_map, + LLMediaCtrl* web) + { + if (!LLUI::sSettingGroups["config"]->getBOOL("EnablePicks")) + { + LLNotificationsUtil::add("NoPicks", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); + return true; + } + + // handle app/classified/create urls first + if (params.size() == 1 && params[0].asString() == "create") + { + LLAvatarActions::showPicks(gAgent.getID()); + return true; + } + + // then handle the general app/pick/{UUID}/{CMD} urls + if (params.size() < 2) + { + return false; + } + + // get the ID for the pick_id + LLUUID pick_id; + if (!pick_id.set(params[0], FALSE)) + { + return false; + } + + // edit the pick in the side tray. + // need to ask the server for more info first though... + const std::string verb = params[1].asString(); + if (verb == "edit") + { + LLAvatarActions::showPick(gAgent.getID(), pick_id); + return true; + } + else + { + LL_WARNS() << "unknown verb " << verb << LL_ENDL; + return false; + } + } +}; +LLPickHandler gPickHandler; + + +//----------------------------------------------------------------------------- +// LLPanelProfilePicks +//----------------------------------------------------------------------------- + +LLPanelProfilePicks::LLPanelProfilePicks() + : LLPanelProfileTab() + , mPickToSelectOnLoad(LLUUID::null) +{ +} + +LLPanelProfilePicks::~LLPanelProfilePicks() +{ +} + +void LLPanelProfilePicks::onOpen(const LLSD& key) +{ + LLPanelProfileTab::onOpen(key); + + resetData(); + + if (getSelfProfile() && !getEmbedded()) + { + mNewButton->setVisible(TRUE); + mNewButton->setEnabled(FALSE); + + mDeleteButton->setVisible(TRUE); + mDeleteButton->setEnabled(FALSE); + } +} + +void LLPanelProfilePicks::selectPick(const LLUUID& pick_id) +{ + if (getIsLoaded()) + { + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfilePick* pick_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (pick_panel) + { + if (pick_panel->getPickId() == pick_id) + { + mTabContainer->selectTabPanel(pick_panel); + break; + } + } + } + } + else + { + mPickToSelectOnLoad = pick_id; + } +} + +BOOL LLPanelProfilePicks::postBuild() +{ + mTabContainer = getChild("tab_picks"); + mNoItemsLabel = getChild("picks_panel_text"); + mNewButton = getChild("new_btn"); + mDeleteButton = getChild("delete_btn"); + + mNewButton->setCommitCallback(boost::bind(&LLPanelProfilePicks::onClickNewBtn, this)); + mDeleteButton->setCommitCallback(boost::bind(&LLPanelProfilePicks::onClickDelete, this)); + + return TRUE; +} + +void LLPanelProfilePicks::onClickNewBtn() +{ + mNoItemsLabel->setVisible(FALSE); + LLPanelProfilePick* pick_panel = LLPanelProfilePick::create(); + pick_panel->setAvatarId(getAvatarId()); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(pick_panel). + select_tab(true). + label(pick_panel->getPickName())); + updateButtons(); +} + +void LLPanelProfilePicks::onClickDelete() +{ + LLPanelProfilePick* pick_panel = dynamic_cast(mTabContainer->getCurrentPanel()); + if (pick_panel) + { + LLUUID pick_id = pick_panel->getPickId(); + LLSD args; + args["PICK"] = pick_panel->getPickName(); + LLSD payload; + payload["pick_id"] = pick_id; + payload["tab_idx"] = mTabContainer->getCurrentPanelIndex(); + LLNotificationsUtil::add("DeleteAvatarPick", args, payload, + boost::bind(&LLPanelProfilePicks::callbackDeletePick, this, _1, _2)); + } +} + +void LLPanelProfilePicks::callbackDeletePick(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + + if (0 == option) + { + LLUUID pick_id = notification["payload"]["pick_id"].asUUID(); + S32 tab_idx = notification["payload"]["tab_idx"].asInteger(); + + LLPanelProfilePick* pick_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (pick_panel && pick_panel->getPickId() == pick_id) + { + mTabContainer->removeTabPanel(pick_panel); + } + + if (pick_id.notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->sendPickDelete(pick_id); + } + + updateButtons(); + } +} + +void LLPanelProfilePicks::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_PICKS == type) + { + LLAvatarPicks* avatar_picks = static_cast(data); + if (avatar_picks && getAvatarId() == avatar_picks->target_id) + { + LLUUID selected_id = mPickToSelectOnLoad; + if (mPickToSelectOnLoad.isNull()) + { + if (mTabContainer->getTabCount() > 0) + { + LLPanelProfilePick* active_pick_panel = dynamic_cast(mTabContainer->getCurrentPanel()); + if (active_pick_panel) + { + selected_id = active_pick_panel->getPickId(); + } + } + } + + mTabContainer->deleteAllTabs(); + + LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin(); + for (; avatar_picks->picks_list.end() != it; ++it) + { + LLUUID pick_id = it->first; + std::string pick_name = it->second; + + LLPanelProfilePick* pick_panel = LLPanelProfilePick::create(); + + pick_panel->setPickId(pick_id); + pick_panel->setPickName(pick_name); + pick_panel->setAvatarId(getAvatarId()); + + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(pick_panel). + select_tab(selected_id == pick_id). + label(pick_name)); + + if (selected_id == pick_id) + { + mPickToSelectOnLoad = LLUUID::null; + } + } + + BOOL no_data = !mTabContainer->getTabCount(); + mNoItemsLabel->setVisible(no_data); + if (no_data) + { + if(getSelfProfile()) + { + mNoItemsLabel->setValue(LLTrans::getString("NoPicksText")); + } + else + { + mNoItemsLabel->setValue(LLTrans::getString("NoAvatarPicksText")); + } + } + else if (selected_id.isNull()) + { + mTabContainer->selectFirstTab(); + } + + updateButtons(); + } + } +} + +void LLPanelProfilePicks::resetData() +{ + resetLoading(); + mTabContainer->deleteAllTabs(); +} + +void LLPanelProfilePicks::updateButtons() +{ + LLPanelProfileTab::updateButtons(); + + if (getSelfProfile() && !getEmbedded()) + { + mNewButton->setEnabled(canAddNewPick()); + mDeleteButton->setEnabled(canDeletePick()); + } +} + +void LLPanelProfilePicks::apply() +{ + if (getIsLoaded()) + { + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfilePick* pick_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (pick_panel) + { + pick_panel->apply(); + } + } + } +} + +void LLPanelProfilePicks::updateData() +{ + // Send picks request only once + LLUUID avatar_id = getAvatarId(); + if (!getIsLoading() && avatar_id.notNull()) + { + setIsLoading(); + mNoItemsLabel->setValue(LLTrans::getString("PicksClassifiedsLoadingText")); + mNoItemsLabel->setVisible(TRUE); + + LLAvatarPropertiesProcessor::getInstance()->sendAvatarPicksRequest(avatar_id); + } +} + +bool LLPanelProfilePicks::canAddNewPick() +{ + return (!LLAgentPicksInfo::getInstance()->isPickLimitReached() && + mTabContainer->getTabCount() < LLAgentPicksInfo::getInstance()->getMaxNumberOfPicks()); +} + +bool LLPanelProfilePicks::canDeletePick() +{ + return (mTabContainer->getTabCount() > 0); +} + + +//----------------------------------------------------------------------------- +// LLPanelProfilePick +//----------------------------------------------------------------------------- + +LLPanelProfilePick::LLPanelProfilePick() + : LLPanelProfileTab() + , LLRemoteParcelInfoObserver() + , mSnapshotCtrl(NULL) + , mPickId(LLUUID::null) + , mParcelId(LLUUID::null) + , mRequestedId(LLUUID::null) + , mLocationChanged(false) + , mNewPick(false) + , mCurrentPickDescription("") + , mIsEditing(false) +{ +} + +//static +LLPanelProfilePick* LLPanelProfilePick::create() +{ + LLPanelProfilePick* panel = new LLPanelProfilePick(); + panel->buildFromFile("panel_profile_pick.xml"); + return panel; +} + +LLPanelProfilePick::~LLPanelProfilePick() +{ + if (mParcelId.notNull()) + { + LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this); + } +} + +void LLPanelProfilePick::setAvatarId(const LLUUID& avatar_id) +{ + if (avatar_id.isNull()) + { + return; + } + LLPanelProfileTab::setAvatarId(avatar_id); + + // creating new Pick + if (getPickId().isNull() && getSelfProfile()) + { + mNewPick = true; + + setPosGlobal(gAgent.getPositionGlobal()); + + LLUUID parcel_id = LLUUID::null, snapshot_id = LLUUID::null; + std::string pick_name, pick_desc, region_name; + + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (parcel) + { + parcel_id = parcel->getID(); + pick_name = parcel->getName(); + pick_desc = parcel->getDesc(); + snapshot_id = parcel->getSnapshotID(); + } + + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + region_name = region->getName(); + } + + setParcelID(parcel_id); + setPickName(pick_name.empty() ? region_name : pick_name); + setPickDesc(pick_desc); + setSnapshotId(snapshot_id); + setPickLocation(createLocationText(getLocationNotice(), pick_name, region_name, getPosGlobal())); + + enableSaveButton(TRUE); + } + else + { + LLAvatarPropertiesProcessor::getInstance()->sendPickInfoRequest(getAvatarId(), getPickId()); + + enableSaveButton(FALSE); + } + + resetDirty(); + + if (getSelfProfile() && !getEmbedded()) + { + mPickName->setEnabled(TRUE); + mPickDescription->setEnabled(TRUE); + mSetCurrentLocationButton->setVisible(TRUE); + } + else + { + mSnapshotCtrl->setEnabled(FALSE); + } +} + +BOOL LLPanelProfilePick::postBuild() +{ + mPickName = getChild("pick_name"); + mPickDescription = getChild("pick_desc"); + mSaveButton = getChild("save_changes_btn"); + mSetCurrentLocationButton = getChild("set_to_curr_location_btn"); + + mSnapshotCtrl = getChild("pick_snapshot"); + mSnapshotCtrl->setCommitCallback(boost::bind(&LLPanelProfilePick::onSnapshotChanged, this)); + + childSetAction("teleport_btn", boost::bind(&LLPanelProfilePick::onClickTeleport, this)); + childSetAction("show_on_map_btn", boost::bind(&LLPanelProfilePick::onClickMap, this)); + + mSaveButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSave, this)); + mSetCurrentLocationButton->setCommitCallback(boost::bind(&LLPanelProfilePick::onClickSetLocation, this)); + + mPickName->setKeystrokeCallback(boost::bind(&LLPanelProfilePick::onPickChanged, this, _1), NULL); + mPickName->setEnabled(FALSE); + + mPickDescription->setKeystrokeCallback(boost::bind(&LLPanelProfilePick::onPickChanged, this, _1)); + mPickDescription->setFocusReceivedCallback(boost::bind(&LLPanelProfilePick::onDescriptionFocusReceived, this)); + + getChild("pick_location")->setEnabled(FALSE); + + return TRUE; +} + +void LLPanelProfilePick::onDescriptionFocusReceived() +{ + if (!mIsEditing && getSelfProfile()) + { + mIsEditing = true; + mPickDescription->setParseHTML(false); + setPickDesc(mCurrentPickDescription); + } +} + +void LLPanelProfilePick::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_PICK_INFO != type) + { + return; + } + + LLPickData* pick_info = static_cast(data); + if (!pick_info + || pick_info->creator_id != getAvatarId() + || pick_info->pick_id != getPickId()) + { + return; + } + + mIsEditing = false; + mPickDescription->setParseHTML(true); + mParcelId = pick_info->parcel_id; + setSnapshotId(pick_info->snapshot_id); + if (!getSelfProfile() || getEmbedded()) + { + mSnapshotCtrl->setEnabled(FALSE); + } + setPickName(pick_info->name); + setPickDesc(pick_info->desc); + setPosGlobal(pick_info->pos_global); + mCurrentPickDescription = pick_info->desc; + + // Send remote parcel info request to get parcel name and sim (region) name. + sendParcelInfoRequest(); + + // *NOTE dzaporozhan + // We want to keep listening to APT_PICK_INFO because user may + // edit the Pick and we have to update Pick info panel. + // revomeObserver is called from onClickBack + + updateButtons(); +} + +void LLPanelProfilePick::apply() +{ + if ((mNewPick || getIsLoaded()) && isDirty()) + { + sendUpdate(); + } +} + +void LLPanelProfilePick::setSnapshotId(const LLUUID& id) +{ + mSnapshotCtrl->setImageAssetID(id); + mSnapshotCtrl->setValid(TRUE); +} + +void LLPanelProfilePick::setPickName(const std::string& name) +{ + mPickName->setValue(name); +} + +const std::string LLPanelProfilePick::getPickName() +{ + return mPickName->getValue().asString(); +} + +void LLPanelProfilePick::setPickDesc(const std::string& desc) +{ + mPickDescription->setValue(desc); +} + +void LLPanelProfilePick::setPickLocation(const std::string& location) +{ + getChild("pick_location")->setValue(location); +} + +void LLPanelProfilePick::onClickMap() +{ + LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); + LLFloaterReg::showInstance("world_map", "center"); +} + +void LLPanelProfilePick::onClickTeleport() +{ + if (!getPosGlobal().isExactlyZero()) + { + gAgent.teleportViaLocation(getPosGlobal()); + LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); + } +} + +void LLPanelProfilePick::enableSaveButton(BOOL enable) +{ + mSaveButton->setEnabled(enable); + mSaveButton->setVisible(enable); +} + +void LLPanelProfilePick::onSnapshotChanged() +{ + enableSaveButton(TRUE); +} + +void LLPanelProfilePick::onPickChanged(LLUICtrl* ctrl) +{ + if (ctrl && ctrl == mPickName) + { + updateTabLabel(mPickName->getText()); + } + + enableSaveButton(isDirty()); +} + +void LLPanelProfilePick::resetDirty() +{ + LLPanel::resetDirty(); + + mPickName->resetDirty(); + mPickDescription->resetDirty(); + mSnapshotCtrl->resetDirty(); + mLocationChanged = false; +} + +BOOL LLPanelProfilePick::isDirty() const +{ + if (mNewPick + || LLPanel::isDirty() + || mLocationChanged + || mSnapshotCtrl->isDirty() + || mPickName->isDirty() + || mPickDescription->isDirty()) + { + return TRUE; + } + return FALSE; +} + +void LLPanelProfilePick::onClickSetLocation() +{ + // Save location for later use. + setPosGlobal(gAgent.getPositionGlobal()); + + std::string parcel_name, region_name; + + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (parcel) + { + mParcelId = parcel->getID(); + parcel_name = parcel->getName(); + } + + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + region_name = region->getName(); + } + + setPickLocation(createLocationText(getLocationNotice(), parcel_name, region_name, getPosGlobal())); + + mLocationChanged = true; + enableSaveButton(TRUE); +} + +void LLPanelProfilePick::onClickSave() +{ + sendUpdate(); + + mLocationChanged = false; +} + +std::string LLPanelProfilePick::getLocationNotice() +{ + static const std::string notice = getString("location_notice"); + return notice; +} + +void LLPanelProfilePick::sendParcelInfoRequest() +{ + if (mParcelId != mRequestedId) + { + if (mRequestedId.notNull()) + { + LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mRequestedId, this); + } + LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelId, this); + LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelId); + + mRequestedId = mParcelId; + } +} + +void LLPanelProfilePick::processParcelInfo(const LLParcelData& parcel_data) +{ + setPickLocation(createLocationText(LLStringUtil::null, parcel_data.name, parcel_data.sim_name, getPosGlobal())); + + // We have received parcel info for the requested ID so clear it now. + mRequestedId.setNull(); + + if (mParcelId.notNull()) + { + LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this); + } +} + +void LLPanelProfilePick::sendUpdate() +{ + 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 (getPickId().isNull()) + { + getPickId().generate(); + } + + pick_data.agent_id = gAgentID; + pick_data.session_id = gAgent.getSessionID(); + pick_data.pick_id = getPickId(); + pick_data.creator_id = gAgentID;; + + //legacy var need to be deleted + pick_data.top_pick = FALSE; + pick_data.parcel_id = mParcelId; + pick_data.name = getPickName(); + pick_data.desc = mPickDescription->getValue().asString(); + pick_data.snapshot_id = mSnapshotCtrl->getImageAssetID(); + pick_data.pos_global = getPosGlobal(); + pick_data.sort_order = 0; + pick_data.enabled = TRUE; + + LLAvatarPropertiesProcessor::getInstance()->sendPickInfoUpdate(&pick_data); + + if(mNewPick) + { + // Assume a successful create pick operation, make new number of picks + // available immediately. Actual number of picks will be requested in + // LLAvatarPropertiesProcessor::sendPickInfoUpdate and updated upon server respond. + LLAgentPicksInfo::getInstance()->incrementNumberOfPicks(); + } +} + +// static +std::string LLPanelProfilePick::createLocationText(const std::string& owner_name, const std::string& original_name, const std::string& sim_name, const LLVector3d& pos_global) +{ + std::string location_text(owner_name); + if (!original_name.empty()) + { + if (!location_text.empty()) + { + location_text.append(", "); + } + location_text.append(original_name); + + } + + if (!sim_name.empty()) + { + if (!location_text.empty()) + { + location_text.append(", "); + } + location_text.append(sim_name); + } + + if (!location_text.empty()) + { + location_text.append(" "); + } + + if (!pos_global.isNull()) + { + S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = ll_round((F32)pos_global.mdV[VZ]); + location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); + } + return location_text; +} + +void LLPanelProfilePick::updateTabLabel(const std::string& title) +{ + setLabel(title); + LLTabContainer* parent = dynamic_cast(getParent()); + if (parent) + { + parent->setCurrentTabName(title); + } +} \ No newline at end of file diff --git a/indra/newview/llpanelprofilepicks.h b/indra/newview/llpanelprofilepicks.h new file mode 100644 index 0000000000..aeaa25bf8b --- /dev/null +++ b/indra/newview/llpanelprofilepicks.h @@ -0,0 +1,234 @@ +/** + * @file llpanelprofilepicks.h + * @brief LLPanelProfilePicks and related class definitions + * + * $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$ + */ + +#ifndef LL_LLPANELPICKS_H +#define LL_LLPANELPICKS_H + +#include "llpanel.h" +#include "lluuid.h" +#include "llavatarpropertiesprocessor.h" +#include "llpanelavatar.h" +#include "llremoteparcelrequest.h" + +class LLTabContainer; +class LLTextureCtrl; +class LLMediaCtrl; +class LLLineEditor; +class LLTextEditor; + + +/** +* Panel for displaying Avatar's picks. +*/ +class LLPanelProfilePicks + : public LLPanelProfileTab +{ +public: + LLPanelProfilePicks(); + /*virtual*/ ~LLPanelProfilePicks(); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void onOpen(const LLSD& key); + + void selectPick(const LLUUID& pick_id); + + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + /*virtual*/ void resetData(); + + /*virtual*/ void updateButtons(); + + /** + * Saves changes. + */ + virtual void apply(); + + /** + * Sends update data request to server. + */ + /*virtual*/ void updateData(); + +private: + void onClickNewBtn(); + void onClickDelete(); + void callbackDeletePick(const LLSD& notification, const LLSD& response); + + bool canAddNewPick(); + bool canDeletePick(); + + LLTabContainer* mTabContainer; + LLUICtrl* mNoItemsLabel; + LLButton* mNewButton; + LLButton* mDeleteButton; + + LLUUID mPickToSelectOnLoad; +}; + + +class LLPanelProfilePick + : public LLPanelProfileTab + , public LLRemoteParcelInfoObserver +{ +public: + + // Creates new panel + static LLPanelProfilePick* create(); + + LLPanelProfilePick(); + + /*virtual*/ ~LLPanelProfilePick(); + + /*virtual*/ BOOL postBuild(); + + void setAvatarId(const LLUUID& avatar_id); + + void setPickId(const LLUUID& id) { mPickId = id; } + virtual LLUUID& getPickId() { return mPickId; } + + virtual void setPickName(const std::string& name); + const std::string getPickName(); + + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + /** + * Saves changes. + */ + virtual void apply(); + + void updateTabLabel(const std::string& title); + + //This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing + /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); + /*virtual*/ void setParcelID(const LLUUID& parcel_id) { mParcelId = parcel_id; } + /*virtual*/ void setErrorStatus(S32 status, const std::string& reason) {}; + +protected: + + /** + * Sends remote parcel info request to resolve parcel name from its ID. + */ + void sendParcelInfoRequest(); + + /** + * "Location text" is actually the owner name, the original + * name that owner gave the parcel, and the location. + */ + static std::string createLocationText( + const std::string& owner_name, + const std::string& original_name, + const std::string& sim_name, + const LLVector3d& pos_global); + + /** + * Sets snapshot id. + * + * Will mark snapshot control as valid if id is not null. + * Will mark snapshot control as invalid if id is null. If null id is a valid value, + * you have to manually mark snapshot is valid. + */ + virtual void setSnapshotId(const LLUUID& id); + virtual void setPickDesc(const std::string& desc); + virtual void setPickLocation(const std::string& location); + + virtual void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; } + virtual LLVector3d& getPosGlobal() { return mPosGlobal; } + + /** + * Callback for "Map" button, opens Map + */ + void onClickMap(); + + /** + * Callback for "Teleport" button, teleports user to Pick location. + */ + void onClickTeleport(); + + /** + * Enables/disables "Save" button + */ + void enableSaveButton(BOOL enable); + + /** + * Called when snapshot image changes. + */ + void onSnapshotChanged(); + + /** + * Callback for Pick snapshot, name and description changed event. + */ + void onPickChanged(LLUICtrl* ctrl); + + /** + * Resets panel and all cantrols to unedited state + */ + /*virtual*/ void resetDirty(); + + /** + * Returns true if any of Pick properties was changed by user. + */ + /*virtual*/ BOOL isDirty() const; + + /** + * Callback for "Set Location" button click + */ + void onClickSetLocation(); + + /** + * Callback for "Save" button click + */ + void onClickSave(); + + std::string getLocationNotice(); + + /** + * Sends Pick properties to server. + */ + void sendUpdate(); + +protected: + + LLTextureCtrl* mSnapshotCtrl; + LLLineEditor* mPickName; + LLTextEditor* mPickDescription; + LLButton* mSetCurrentLocationButton; + LLButton* mSaveButton; + + LLVector3d mPosGlobal; + LLUUID mParcelId; + LLUUID mPickId; + LLUUID mRequestedId; + + bool mLocationChanged; + bool mNewPick; + bool mIsEditing; + + std::string mCurrentPickDescription; + + void onDescriptionFocusReceived(); +}; + +#endif // LL_LLPANELPICKS_H diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index e0e86bd597..7e4e9a8b10 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -106,6 +106,7 @@ #include "llfloaterpostprocess.h" #include "llfloaterpreference.h" #include "llfloaterpreviewtrash.h" +#include "llfloaterprofile.h" #include "llfloaterproperties.h" #include "llfloaterregiondebugconsole.h" #include "llfloaterregioninfo.h" @@ -150,7 +151,7 @@ #include "llmoveview.h" #include "llfloaterimnearbychat.h" #include "llpanelblockedlist.h" -#include "llpanelclassified.h" +#include "llpanelprofileclassifieds.h" #include "llpreviewanim.h" #include "llpreviewgesture.h" #include "llpreviewnotecard.h" @@ -347,8 +348,9 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("snapshot", "floater_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("outfit_snapshot", "floater_outfit_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("search", "floater_search.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); - LLFloaterReg::add("my_profile", "floater_my_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create); - LLFloaterReg::add("profile", "floater_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create); + LLFloaterReg::add("my_profile_web", "floater_my_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create); + LLFloaterReg::add("profile_web", "floater_web_profile.xml", (LLFloaterBuildFunc)&LLFloaterWebProfile::create); + LLFloaterReg::add("profile", "floater_profile.xml",(LLFloaterBuildFunc)&LLFloaterReg::build); LLFloaterReg::add("how_to", "floater_how_to.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); LLFloaterReg::add("fbc_web", "floater_fbc_web.xml", (LLFloaterBuildFunc)&LLFloaterWebContent::create); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 22a21c9ca3..dd49dcccc2 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -47,7 +47,7 @@ #include "llmutelist.h" #include "llnotifications.h" #include "llnotificationsutil.h" -#include "llpanelprofile.h" +#include "llavataractions.h" #include "llparcel.h" #include "llpluginclassmedia.h" #include "llurldispatcher.h" diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 6c52f118ad..40c9e65823 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -6521,6 +6521,15 @@ class LLShowAgentProfile : public view_listener_t } }; +class LLShowAgentProfilePicks : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLAvatarActions::showPicks(gAgent.getID()); + return true; + } +}; + class LLToggleAgentProfile : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -9251,6 +9260,7 @@ void initialize_menus() view_listener_t::addMenu(new LLToggleSpeak(), "ToggleSpeak"); view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL"); view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); + view_listener_t::addMenu(new LLShowAgentProfilePicks(), "ShowAgentProfilePicks"); view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile"); view_listener_t::addMenu(new LLToggleControl(), "ToggleControl"); view_listener_t::addMenu(new LLCheckControl(), "CheckControl"); diff --git a/indra/newview/llwebprofile.cpp b/indra/newview/llwebprofile.cpp index 81d4e30a7a..c3bdb4b4d0 100644 --- a/indra/newview/llwebprofile.cpp +++ b/indra/newview/llwebprofile.cpp @@ -35,7 +35,7 @@ #include "llsdserialize.h" // newview -#include "llpanelprofile.h" // for getProfileURL(). FIXME: move the method to LLAvatarActions +#include "llavataractions.h" // for getProfileURL() #include "llviewermedia.h" // FIXME: don't use LLViewerMedia internals #include "llcorehttputil.h" diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index e0da7f5d9e..7869eb7267 100644 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -877,6 +877,22 @@ name="PanelNotificationListItem" value="0.3 0.3 0.3 .3" /> + + + + + + + + - - - - - - diff --git a/indra/newview/skins/default/xui/da/panel_side_tray.xml b/indra/newview/skins/default/xui/da/panel_side_tray.xml deleted file mode 100644 index 66c3e69904..0000000000 --- a/indra/newview/skins/default/xui/da/panel_side_tray.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/default/xui/de/floater_picks.xml b/indra/newview/skins/default/xui/de/floater_picks.xml deleted file mode 100644 index 2521920e83..0000000000 --- a/indra/newview/skins/default/xui/de/floater_picks.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/indra/newview/skins/default/xui/de/panel_me.xml b/indra/newview/skins/default/xui/de/panel_me.xml deleted file mode 100644 index f49446fbbf..0000000000 --- a/indra/newview/skins/default/xui/de/panel_me.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/indra/newview/skins/default/xui/en/floater_picks.xml b/indra/newview/skins/default/xui/en/floater_picks.xml deleted file mode 100644 index 984894b016..0000000000 --- a/indra/newview/skins/default/xui/en/floater_picks.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - diff --git a/indra/newview/skins/default/xui/en/floater_profile.xml b/indra/newview/skins/default/xui/en/floater_profile.xml new file mode 100644 index 0000000000..af70ba66f0 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_profile.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + Date: Thu, 11 Apr 2019 01:49:46 -0700 Subject: Added remaining physical properies to copy/paste --- indra/newview/llpanelobject.cpp | 63 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index c8a12f1d38..1e462876ee 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -33,6 +33,7 @@ #include "lleconomy.h" #include "llerror.h" #include "llfontgl.h" +#include "material_codes.h" // LL_MCODE_MASK #include "llpermissionsflags.h" #include "llstring.h" #include "llvolume.h" @@ -2261,7 +2262,29 @@ void LLPanelObject::onCopyParams(const LLSD& data) } // Physics - mParamsClipboard["physics_shape"] = objectp->getPhysicsShapeType(); + { + mParamsClipboard["physics_shape"] = objectp->getPhysicsShapeType(); + mParamsClipboard["physics_gravity"] = objectp->getPhysicsGravity(); + mParamsClipboard["physics_friction"] = objectp->getPhysicsFriction(); + mParamsClipboard["physics_density"] = objectp->getPhysicsDensity(); + mParamsClipboard["physics_restitution"] = objectp->getPhysicsRestitution(); + + U8 material_code = 0; + struct f : public LLSelectedTEGetFunctor + { + U8 get(LLViewerObject* object, S32 te) + { + return object->getMaterial(); + } + } func; + bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_code ); + // This should always be true since material should be per object. + if (material_same) + { + mParamsClipboard["physics_material"] = material_code; + } + } + } void LLPanelObject::onPasteParams(const LLSD& data) @@ -2335,9 +2358,43 @@ void LLPanelObject::onPasteParams(const LLSD& data) } // Physics - if (mParamsClipboard.has("physics_shape")) { - objectp->setPhysicsShapeType((U8)mParamsClipboard["physics_shape"].asInteger()); + if (mParamsClipboard.has("physics_shape")) + { + objectp->setPhysicsShapeType((U8)mParamsClipboard["physics_shape"].asInteger()); + } + if (mParamsClipboard.has("physics_material")) + { + U8 cur_material = objectp->getMaterial(); + U8 material = (U8)mParamsClipboard["physics_material"].asInteger() | (cur_material & ~LL_MCODE_MASK); + objectp->setMaterial(material); + objectp->sendMaterialUpdate(); + } + bool phys_update_flags = false; + if (mParamsClipboard.has("physics_gravity")) + { + objectp->setPhysicsGravity(mParamsClipboard["physics_gravity"].asReal()); + phys_update_flags = true; + } + if (mParamsClipboard.has("physics_friction")) + { + objectp->setPhysicsFriction(mParamsClipboard["physics_friction"].asReal()); + phys_update_flags = true; + } + if (mParamsClipboard.has("physics_density")) + { + objectp->setPhysicsDensity(mParamsClipboard["physics_density"].asReal()); + phys_update_flags = true; + } + if (mParamsClipboard.has("physics_restitution")) + { + objectp->setPhysicsRestitution(mParamsClipboard["physics_restitution"].asReal()); + phys_update_flags = true; + } + if (phys_update_flags) + { + objectp->updateFlags(TRUE); + } } // Parametrics -- cgit v1.2.3 From 41f5801aae25931b8e1a2db1b2eb9623efbc1f3e Mon Sep 17 00:00:00 2001 From: Kadah_Coba Date: Tue, 16 Apr 2019 03:51:05 -0700 Subject: Added spotlight and phantom support to copy/paste Added paste options menu --- indra/newview/llpanelobject.cpp | 431 +++++++++++++-------- indra/newview/llpanelobject.h | 15 +- .../newview/skins/default/xui/en/floater_tools.xml | 23 +- 3 files changed, 290 insertions(+), 179 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 1e462876ee..1809392ad0 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -50,6 +50,7 @@ #include "llinventoryfunctions.h" #include "llinventorymodel.h" #include "llmanipscale.h" +#include "llmenubutton.h" #include "llpreviewscript.h" #include "llresmgr.h" #include "llselectmgr.h" @@ -158,13 +159,13 @@ BOOL LLPanelObject::postBuild() mBtnCopyPos->setCommitCallback( boost::bind(&LLPanelObject::onCopyPos, this, _2 )); mBtnPastePos = getChild("paste_pos_btn"); mBtnPastePos->setCommitCallback( boost::bind(&LLPanelObject::onPastePos, this, _2 )); - + // Copy/paste size mBtnCopySize = getChild("copy_size_btn"); mBtnCopySize->setCommitCallback( boost::bind(&LLPanelObject::onCopySize, this, _2 )); mBtnPasteSize = getChild("paste_size_btn"); mBtnPasteSize->setCommitCallback( boost::bind(&LLPanelObject::onPasteSize, this, _2 )); - + // Copy/paste rot mBtnCopyRot = getChild("copy_rot_btn"); mBtnCopyRot->setCommitCallback( boost::bind(&LLPanelObject::onCopyRot, this, _2 )); @@ -176,6 +177,7 @@ BOOL LLPanelObject::postBuild() mBtnCopyParams->setCommitCallback( boost::bind(&LLPanelObject::onCopyParams, this, _2 )); mBtnPasteParams = getChild("paste_params_btn"); mBtnPasteParams->setCommitCallback( boost::bind(&LLPanelObject::onPasteParams, this, _2 )); + mBtnPasteMenu = getChild("patse_gear_btn"); //-------------------------------------------------------- @@ -316,8 +318,14 @@ LLPanelObject::LLPanelObject() mSizeChanged(FALSE), mHasPosClipboard(FALSE), mHasSizeClipboard(FALSE), - mHasRotClipboard(FALSE) + mHasRotClipboard(FALSE), + mPasteParametric(TRUE), + mPastePhysics(TRUE), + mPasteLight(TRUE) { + mEnableCallbackRegistrar.add("BuildObject.PasteCheckItem", boost::bind(&LLPanelObject::pasteCheckMenuItem, this, _2)); + mCommitCallbackRegistrar.add("BuildObject.PasteDoToSelected", boost::bind(&LLPanelObject::pasteDoMenuItem, this, _2)); + mEnableCallbackRegistrar.add("BuildObject.PasteEnable", boost::bind(&LLPanelObject::pasteEnabletMenuItem, this, _2)); } @@ -474,6 +482,7 @@ void LLPanelObject::getState( ) mBtnCopyParams->setEnabled( single_volume && enable_modify ); mBtnPasteParams->setEnabled( single_volume && enable_modify ); + mBtnPasteMenu->setEnabled( single_volume && enable_modify ); LLUUID owner_id; std::string owner_name; @@ -2136,9 +2145,13 @@ void LLPanelObject::onCopyParams(const LLSD& data) return; } + mParamsClipboard.clear(); + + mParamsClipboard["is_phantom"] = objectp->flagPhantom(); + mParamsClipboard["is_physical"] = objectp->flagUsePhysics(); + // Parametrics getVolumeParams(mClipboardVolumeParams); - mHasParamsClipboard = TRUE; LLVOVolume *volobjp = NULL; if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) @@ -2152,122 +2165,72 @@ void LLPanelObject::onCopyParams(const LLSD& data) LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); if (attributes) { - mParamsClipboard["lod"] = attributes->getSimulateLOD(); - mParamsClipboard["gav"] = attributes->getGravity(); - mParamsClipboard["ten"] = attributes->getTension(); - mParamsClipboard["fri"] = attributes->getAirFriction(); - mParamsClipboard["sen"] = attributes->getWindSensitivity(); + mParamsClipboard["flex"]["lod"] = attributes->getSimulateLOD(); + mParamsClipboard["flex"]["gav"] = attributes->getGravity(); + mParamsClipboard["flex"]["ten"] = attributes->getTension(); + mParamsClipboard["flex"]["fri"] = attributes->getAirFriction(); + mParamsClipboard["flex"]["sen"] = attributes->getWindSensitivity(); LLVector3 force = attributes->getUserForce(); - mParamsClipboard["forx"] = force.mV[0]; - mParamsClipboard["fory"] = force.mV[1]; - mParamsClipboard["forz"] = force.mV[2]; - mHasFlexiParam = TRUE; + mParamsClipboard["flex"]["forx"] = force.mV[0]; + mParamsClipboard["flex"]["fory"] = force.mV[1]; + mParamsClipboard["flex"]["forz"] = force.mV[2]; } } - else - { - mHasFlexiParam = FALSE; - } // Sculpted Prim - // User is allowed to copy if they could otherwise recreate it manually - // ie. User has full perm copy of the sculpted texture in their inventory, - // or is a default texture or library asset. if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) { LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLUUID image_id = sculpt_params->getSculptTexture(); - BOOL allow_texture = FALSE; - if (gInventory.isObjectDescendentOf(image_id, gInventory.getLibraryRootFolderID()) - || image_id == LLUUID(gSavedSettings.getString( "DefaultObjectTexture" )) - || image_id == LLUUID(gSavedSettings.getString( "UIImgWhiteUUID" )) - || image_id == LLUUID(gSavedSettings.getString( "UIImgInvisibleUUID" )) - || image_id == LLUUID(SCULPT_DEFAULT_TEXTURE)) + LLUUID texture_id = sculpt_params->getSculptTexture(); + if (canCopyTexture(texture_id)) { - allow_texture = TRUE; + LL_INFOS() << "copu texture " << LL_ENDL; + mParamsClipboard["sculpt"]["id"] = texture_id; } else { - LLUUID inventory_item_id; - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - LLAssetIDMatches asset_id_matches(image_id); - gInventory.collectDescendentsIf(LLUUID::null, - cats, - items, - LLInventoryModel::INCLUDE_TRASH, - asset_id_matches); - - if (items.size()) - { - // search for copyable version first - for (S32 i = 0; i < items.size(); i++) - { - LLInventoryItem* itemp = items[i]; - LLPermissions item_permissions = itemp->getPermissions(); - if (item_permissions.allowCopyBy(gAgent.getID(), gAgent.getGroupID())) - { - inventory_item_id = itemp->getUUID(); - break; - } - } - } - if (inventory_item_id.notNull()) - { - LLInventoryItem* itemp = gInventory.getItem(inventory_item_id); - if (itemp) - { - LLPermissions perm = itemp->getPermissions(); - if ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) - { - allow_texture = TRUE; - } - } - } - } - if (allow_texture) - { - mParamsClipboard["sculptid"] = image_id; - } - else - { - mParamsClipboard["sculptid"] = LLUUID(SCULPT_DEFAULT_TEXTURE); + mParamsClipboard["sculpt"]["id"] = LLUUID(SCULPT_DEFAULT_TEXTURE); } - mParamsClipboard["sculpt_type"] = sculpt_params->getSculptType(); - mHasSculptParam = TRUE; - } - else - { - mHasSculptParam = FALSE; + mParamsClipboard["sculpt"]["type"] = sculpt_params->getSculptType(); } // Light Source - // only captures basic settings if (volobjp && volobjp->getIsLight()) { - mParamsClipboard["Light Intensity"] = volobjp->getLightIntensity(); - mParamsClipboard["Light Radius"] = volobjp->getLightRadius(); - mParamsClipboard["Light Falloff"] = volobjp->getLightFalloff(); + mParamsClipboard["light"]["intensity"] = volobjp->getLightIntensity(); + mParamsClipboard["light"]["radius"] = volobjp->getLightRadius(); + mParamsClipboard["light"]["falloff"] = volobjp->getLightFalloff(); LLColor3 color = volobjp->getLightColor(); - mParamsClipboard["r"] = color.mV[0]; - mParamsClipboard["g"] = color.mV[1]; - mParamsClipboard["b"] = color.mV[2]; - mHasLightParam = TRUE; - } - else - { - mHasLightParam = FALSE; + mParamsClipboard["light"]["r"] = color.mV[0]; + mParamsClipboard["light"]["g"] = color.mV[1]; + mParamsClipboard["light"]["b"] = color.mV[2]; + + // Spotlight + if (volobjp->isLightSpotlight()) + { + LLUUID id = volobjp->getLightTextureID(); + if (id.notNull() && canCopyTexture(id)) + { + mParamsClipboard["spot"]["id"] = id; + LLVector3 spot_params = volobjp->getSpotLightParams(); + mParamsClipboard["spot"]["fov"] = spot_params.mV[0]; + mParamsClipboard["spot"]["focus"] = spot_params.mV[1]; + mParamsClipboard["spot"]["ambiance"] = spot_params.mV[2]; + } + } } + + // Physics { - mParamsClipboard["physics_shape"] = objectp->getPhysicsShapeType(); - mParamsClipboard["physics_gravity"] = objectp->getPhysicsGravity(); - mParamsClipboard["physics_friction"] = objectp->getPhysicsFriction(); - mParamsClipboard["physics_density"] = objectp->getPhysicsDensity(); - mParamsClipboard["physics_restitution"] = objectp->getPhysicsRestitution(); + mParamsClipboard["physics"]["shape"] = objectp->getPhysicsShapeType(); + mParamsClipboard["physics"]["gravity"] = objectp->getPhysicsGravity(); + mParamsClipboard["physics"]["friction"] = objectp->getPhysicsFriction(); + mParamsClipboard["physics"]["density"] = objectp->getPhysicsDensity(); + mParamsClipboard["physics"]["restitution"] = objectp->getPhysicsRestitution(); U8 material_code = 0; struct f : public LLSelectedTEGetFunctor @@ -2281,125 +2244,251 @@ void LLPanelObject::onCopyParams(const LLSD& data) // This should always be true since material should be per object. if (material_same) { - mParamsClipboard["physics_material"] = material_code; + mParamsClipboard["physics"]["material"] = material_code; } } - + + mHasParamsClipboard = TRUE; } void LLPanelObject::onPasteParams(const LLSD& data) { LLViewerObject* objectp = mObject; - if (!objectp) + if (!objectp || !mHasParamsClipboard) { return; } - // Flexi Prim - if (mHasFlexiParam && (objectp->getPCode() == LL_PCODE_VOLUME)) + LLVOVolume *volobjp = NULL; + if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) { - LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); - if (attributes) - { - LLFlexibleObjectData new_attributes; - new_attributes = *attributes; - - new_attributes.setSimulateLOD(mParamsClipboard["lod"].asInteger()); - new_attributes.setGravity(mParamsClipboard["gav"].asReal()); - new_attributes.setTension(mParamsClipboard["ten"].asReal()); - new_attributes.setAirFriction(mParamsClipboard["fri"].asReal()); - new_attributes.setWindSensitivity(mParamsClipboard["sen"].asReal()); - F32 fx = (F32)mParamsClipboard["forx"].asReal(); - F32 fy = (F32)mParamsClipboard["fory"].asReal(); - F32 fz = (F32)mParamsClipboard["forz"].asReal(); - LLVector3 force(fx,fy,fz); - new_attributes.setUserForce(force); - objectp->setParameterEntry(LLNetworkData::PARAMS_FLEXIBLE, new_attributes, true); - } + volobjp = (LLVOVolume *)objectp; } - // Sculpted Prim - if (mHasSculptParam) + // Light Source + if (mPasteLight && volobjp) { - LLSculptParams sculpt_params; - - if (mParamsClipboard.has("sculptid")) + if (mParamsClipboard.has("light")) { - sculpt_params.setSculptTexture(mParamsClipboard["sculptid"].asUUID(), (U8)mParamsClipboard["sculpt_type"].asInteger()); + volobjp->setIsLight(TRUE); + volobjp->setLightIntensity((F32)mParamsClipboard["light"]["intensity"].asReal()); + volobjp->setLightRadius((F32)mParamsClipboard["light"]["radius"].asReal()); + volobjp->setLightFalloff((F32)mParamsClipboard["light"]["falloff"].asReal()); + F32 r = (F32)mParamsClipboard["light"]["r"].asReal(); + F32 g = (F32)mParamsClipboard["light"]["g"].asReal(); + F32 b = (F32)mParamsClipboard["light"]["b"].asReal(); + volobjp->setLightColor(LLColor3(r,g,b)); } - objectp->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE); - } - else - { - LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); - if (sculpt_params) + if (mParamsClipboard.has("spot")) { - objectp->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE); + volobjp->setLightTextureID(mParamsClipboard["spot"]["id"]); + LLVector3 spot_params; + spot_params.mV[0] = (F32)mParamsClipboard["spot"]["fov"].asReal(); + spot_params.mV[1] = (F32)mParamsClipboard["spot"]["focus"].asReal(); + spot_params.mV[2] = (F32)mParamsClipboard["spot"]["ambiance"].asReal(); + volobjp->setSpotLightParams(spot_params); } } - // Light Source - if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) + // Physics + if (mPastePhysics) { - LLVOVolume *volobjp = (LLVOVolume *)objectp; + bool is_root = objectp->isRoot(); - if (volobjp && mHasLightParam) - { - volobjp->setIsLight(TRUE); - volobjp->setLightIntensity((F32)mParamsClipboard["Light Intensity"].asReal()); - volobjp->setLightRadius((F32)mParamsClipboard["Light Radius"].asReal()); - volobjp->setLightFalloff((F32)mParamsClipboard["Light Falloff"].asReal()); - F32 r = (F32)mParamsClipboard["r"].asReal(); - F32 g = (F32)mParamsClipboard["g"].asReal(); - F32 b = (F32)mParamsClipboard["b"].asReal(); - volobjp->setLightColor(LLColor3(r,g,b)); - } - } + // Not sure if phantom should go under physics, but doesn't fit elsewhere + BOOL is_phantom = mParamsClipboard["is_phantom"].asBoolean() && is_root; + LLSelectMgr::getInstance()->selectionUpdatePhantom(is_phantom); - // Physics - { - if (mParamsClipboard.has("physics_shape")) - { - objectp->setPhysicsShapeType((U8)mParamsClipboard["physics_shape"].asInteger()); - } - if (mParamsClipboard.has("physics_material")) + BOOL is_physical = mParamsClipboard["is_physical"].asBoolean() && is_root; + LLSelectMgr::getInstance()->selectionUpdatePhysics(is_physical); + + if (mParamsClipboard.has("physics")) { + objectp->setPhysicsShapeType((U8)mParamsClipboard["physics"]["shape"].asInteger()); U8 cur_material = objectp->getMaterial(); U8 material = (U8)mParamsClipboard["physics_material"].asInteger() | (cur_material & ~LL_MCODE_MASK); + objectp->setMaterial(material); objectp->sendMaterialUpdate(); + objectp->setPhysicsGravity(mParamsClipboard["physics"]["gravity"].asReal()); + objectp->setPhysicsFriction(mParamsClipboard["physics"]["friction"].asReal()); + objectp->setPhysicsDensity(mParamsClipboard["physics"]["density"].asReal()); + objectp->setPhysicsRestitution(mParamsClipboard["physics"]["restitution"].asReal()); + objectp->updateFlags(TRUE); } - bool phys_update_flags = false; - if (mParamsClipboard.has("physics_gravity")) + } + + // Parametrics + if(mPasteParametric) + { + // Sculpted Prim + if (mParamsClipboard.has("sculpt")) { - objectp->setPhysicsGravity(mParamsClipboard["physics_gravity"].asReal()); - phys_update_flags = true; + LLSculptParams sculpt_params; + LLUUID sculpt_id = mParamsClipboard["sculpt"]["id"].asUUID(); + U8 sculpt_type = (U8)mParamsClipboard["sculpt"]["type"].asInteger(); + sculpt_params.setSculptTexture(sculpt_id, sculpt_type); + objectp->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE); } - if (mParamsClipboard.has("physics_friction")) + else { - objectp->setPhysicsFriction(mParamsClipboard["physics_friction"].asReal()); - phys_update_flags = true; + LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + if (sculpt_params) + { + objectp->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE); + } } - if (mParamsClipboard.has("physics_density")) + + // Flexi Params + if (mParamsClipboard.has("flex")) + { + if (objectp->getClickAction() == CLICK_ACTION_SIT) + { + objectp->setClickAction(CLICK_ACTION_NONE); + } + + LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); + if (attributes) + { + LLFlexibleObjectData new_attributes; + new_attributes = *attributes; + new_attributes.setSimulateLOD(mParamsClipboard["flex"]["lod"].asInteger()); + new_attributes.setGravity(mParamsClipboard["flex"]["gav"].asReal()); + new_attributes.setTension(mParamsClipboard["flex"]["ten"].asReal()); + new_attributes.setAirFriction(mParamsClipboard["flex"]["fri"].asReal()); + new_attributes.setWindSensitivity(mParamsClipboard["flex"]["sen"].asReal()); + F32 fx = (F32)mParamsClipboard["flex"]["forx"].asReal(); + F32 fy = (F32)mParamsClipboard["flex"]["fory"].asReal(); + F32 fz = (F32)mParamsClipboard["flex"]["forz"].asReal(); + LLVector3 force(fx,fy,fz); + new_attributes.setUserForce(force); + objectp->setParameterEntry(LLNetworkData::PARAMS_FLEXIBLE, new_attributes, true); + } + } + + objectp->updateVolume(mClipboardVolumeParams); + } +} + +bool LLPanelObject::pasteCheckMenuItem(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + if ("Parametric" == command) + { + return mPasteParametric; + } + if ("Physics" == command) + { + return mPastePhysics; + } + if ("Light" == command) + { + return mPasteLight; + } + + return false; +} + +void LLPanelObject::pasteDoMenuItem(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + if ("Parametric" == command) + { + mPasteParametric = !mPasteParametric; + } + if ("Physics" == command) + { + mPastePhysics = !mPastePhysics; + } + if ("Light" == command) + { + mPasteLight = !mPasteLight; + } +} + +bool LLPanelObject::pasteEnabletMenuItem(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + // Keep at least one option enabled + if (mPasteParametric + mPastePhysics + mPasteLight == 1) + { + if ("Parametric" == command && mPasteParametric) { - objectp->setPhysicsDensity(mParamsClipboard["physics_density"].asReal()); - phys_update_flags = true; + return false; } - if (mParamsClipboard.has("physics_restitution")) + if ("Physics" == command && mPastePhysics) { - objectp->setPhysicsRestitution(mParamsClipboard["physics_restitution"].asReal()); - phys_update_flags = true; + return false; } - if (phys_update_flags) + if ("Light" == command && mPasteLight) { - objectp->updateFlags(TRUE); + return false; } } - // Parametrics - if(mHasParamsClipboard) + return true; +} + +// User is allowed to copy if they could otherwise recreate it manually +// ie. User has full perm copy of the sculpted texture in their inventory, +// or is a default texture or library asset. +bool LLPanelObject::canCopyTexture(LLUUID image_id) +{ + // Library asset or default texture + if (gInventory.isObjectDescendentOf(image_id, gInventory.getLibraryRootFolderID()) + || image_id == LLUUID(gSavedSettings.getString( "DefaultObjectTexture" )) + || image_id == LLUUID(gSavedSettings.getString( "UIImgWhiteUUID" )) + || image_id == LLUUID(gSavedSettings.getString( "UIImgInvisibleUUID" )) + || image_id == LLUUID(SCULPT_DEFAULT_TEXTURE)) { - objectp->updateVolume(mClipboardVolumeParams); + return true; + } + + // LLUUID inventory_item_id; + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(image_id); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + if (items.size()) + { + // search for copyable version first + for (S32 i = 0; i < items.size(); i++) + { + LLInventoryItem* itemp = items[i]; + LLPermissions item_permissions = itemp->getPermissions(); + // if (item_permissions.allowCopyBy(gAgent.getID(), gAgent.getGroupID())) + if (item_permissions.allowCopyBy(gAgent.getID())) + { + // inventory_item_id = itemp->getUUID(); + // break; + return true; + } + } } + + // if (inventory_item_id.notNull()) + // { + // LLInventoryItem* itemp = gInventory.getItem(inventory_item_id); + // if (itemp) + // { + // if (itemp && !itemp->getPermissions().allowCopyBy(gAgent.getID())) + // // LLPermissions perm = itemp->getPermissions(); + // // if ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) + // { + // // User has full perm copy of texture + // return true; + // } + // } + // } + + return false; } diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index 46725a80e4..7fa728ea57 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -37,6 +37,7 @@ class LLCheckBoxCtrl; class LLTextBox; class LLUICtrl; class LLButton; +class LLMenuButton; class LLViewerObject; class LLComboBox; class LLColorSwatchCtrl; @@ -84,6 +85,10 @@ public: BOOL onDropSculpt(LLInventoryItem* item); static void onCommitSculptType( LLUICtrl *ctrl, void* userdata); + bool pasteCheckMenuItem(const LLSD& userdata); + void pasteDoMenuItem(const LLSD& userdata); + bool pasteEnabletMenuItem(const LLSD& userdata); + protected: void getState(); @@ -97,6 +102,8 @@ protected: void sendSculpt(); void getVolumeParams(LLVolumeParams& volume_params); + + bool canCopyTexture(LLUUID image_id); protected: // Per-object options @@ -164,6 +171,7 @@ protected: LLButton *mBtnPasteRot; LLButton *mBtnCopyParams; LLButton *mBtnPasteParams; + LLMenuButton *mBtnPasteMenu; LLCheckBoxCtrl *mCheckLock; LLCheckBoxCtrl *mCheckPhysics; @@ -196,9 +204,10 @@ protected: LLSD mParamsClipboard; LLVolumeParams mClipboardVolumeParams; BOOL mHasParamsClipboard; - BOOL mHasFlexiParam; - BOOL mHasSculptParam; - BOOL mHasLightParam; + + BOOL mPasteParametric; + BOOL mPastePhysics; + BOOL mPasteLight; LLPointer mObject; LLPointer mRootObject; diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 1e2846d943..8a7272d9e4 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1696,25 +1696,38 @@ even though the user gets a free copy. --> + Date: Wed, 17 Apr 2019 02:41:33 -0700 Subject: Added translation support for build tools paste buttons tooltips --- indra/newview/llpanelobject.cpp | 65 +++++++++------------- .../newview/skins/default/xui/en/floater_tools.xml | 12 ++++ 2 files changed, 37 insertions(+), 40 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 1809392ad0..8a51007af7 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -2050,19 +2050,17 @@ void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata) self->sendSculpt(); } -void copy_vector_to_clipboard(const LLVector3& vec) -{ - std::string stringVec = llformat("<%g, %g, %g>", vec.mV[VX], vec.mV[VY], vec.mV[VZ]); - LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec)); -} - void LLPanelObject::onCopyPos(const LLSD& data) { - mClipboardPos = LLVector3(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get()); + mClipboardPos = LLVector3(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get()); - copy_vector_to_clipboard(mClipboardPos); + std::string stringVec = llformat("<%g, %g, %g>", mClipboardPos.mV[VX], mClipboardPos.mV[VY], mClipboardPos.mV[VZ]); + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec)); + + LLStringUtil::format_map_t args; + args["VALUE"] = stringVec; + mBtnPastePos->setToolTip(getString("paste_position", args)); - mBtnPastePos->setToolTip(llformat("Paste Position\n<%g, %g, %g>", mClipboardPos.mV[VX], mClipboardPos.mV[VY], mClipboardPos.mV[VZ])); mBtnPastePos->setEnabled(TRUE); mHasPosClipboard = TRUE; @@ -2070,11 +2068,15 @@ void LLPanelObject::onCopyPos(const LLSD& data) void LLPanelObject::onCopySize(const LLSD& data) { - mClipboardSize = LLVector3(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get()); + mClipboardSize = LLVector3(mCtrlScaleX->get(), mCtrlScaleY->get(), mCtrlScaleZ->get()); + + std::string stringVec = llformat("<%g, %g, %g>", mClipboardSize.mV[VX], mClipboardSize.mV[VY], mClipboardSize.mV[VZ]); + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec)); - copy_vector_to_clipboard(mClipboardSize); + LLStringUtil::format_map_t args; + args["VALUE"] = stringVec; + mBtnPasteSize->setToolTip(getString("paste_size", args)); - mBtnPasteSize->setToolTip(llformat("Paste Size\n<%g, %g, %g>", mClipboardSize.mV[VX], mClipboardSize.mV[VY], mClipboardSize.mV[VZ])); mBtnPasteSize->setEnabled(TRUE); mHasSizeClipboard = TRUE; @@ -2082,11 +2084,15 @@ void LLPanelObject::onCopySize(const LLSD& data) void LLPanelObject::onCopyRot(const LLSD& data) { - mClipboardRot = LLVector3(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get()); + mClipboardRot = LLVector3(mCtrlRotX->get(), mCtrlRotY->get(), mCtrlRotZ->get()); + + std::string stringVec = llformat("<%g, %g, %g>", mClipboardRot.mV[VX], mClipboardRot.mV[VY], mClipboardRot.mV[VZ]); + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec)); - copy_vector_to_clipboard(mClipboardRot); + LLStringUtil::format_map_t args; + args["VALUE"] = stringVec; + mBtnPasteRot->setToolTip(getString("paste_rotation", args)); - mBtnPasteRot->setToolTip(llformat("Paste Rotation\n<%g, %g, %g>", mClipboardRot.mV[VX], mClipboardRot.mV[VY], mClipboardRot.mV[VZ])); mBtnPasteRot->setEnabled(TRUE); mHasRotClipboard = TRUE; @@ -2221,8 +2227,6 @@ void LLPanelObject::onCopyParams(const LLSD& data) } } } - - // Physics { @@ -2373,7 +2377,7 @@ void LLPanelObject::onPasteParams(const LLSD& data) bool LLPanelObject::pasteCheckMenuItem(const LLSD& userdata) { - std::string command = userdata.asString(); + std::string command = userdata.asString(); if ("Parametric" == command) { @@ -2388,12 +2392,12 @@ bool LLPanelObject::pasteCheckMenuItem(const LLSD& userdata) return mPasteLight; } - return false; + return false; } void LLPanelObject::pasteDoMenuItem(const LLSD& userdata) { - std::string command = userdata.asString(); + std::string command = userdata.asString(); if ("Parametric" == command) { @@ -2411,7 +2415,7 @@ void LLPanelObject::pasteDoMenuItem(const LLSD& userdata) bool LLPanelObject::pasteEnabletMenuItem(const LLSD& userdata) { - std::string command = userdata.asString(); + std::string command = userdata.asString(); // Keep at least one option enabled if (mPasteParametric + mPastePhysics + mPasteLight == 1) @@ -2457,7 +2461,6 @@ bool LLPanelObject::canCopyTexture(LLUUID image_id) items, LLInventoryModel::INCLUDE_TRASH, asset_id_matches); - if (items.size()) { // search for copyable version first @@ -2465,30 +2468,12 @@ bool LLPanelObject::canCopyTexture(LLUUID image_id) { LLInventoryItem* itemp = items[i]; LLPermissions item_permissions = itemp->getPermissions(); - // if (item_permissions.allowCopyBy(gAgent.getID(), gAgent.getGroupID())) if (item_permissions.allowCopyBy(gAgent.getID())) { - // inventory_item_id = itemp->getUUID(); - // break; return true; } } } - // if (inventory_item_id.notNull()) - // { - // LLInventoryItem* itemp = gInventory.getItem(inventory_item_id); - // if (itemp) - // { - // if (itemp && !itemp->getPermissions().allowCopyBy(gAgent.getID())) - // // LLPermissions perm = itemp->getPermissions(); - // // if ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) - // { - // // User has full perm copy of texture - // return true; - // } - // } - // } - return false; } diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 8a7272d9e4..150d3d9804 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1387,6 +1387,18 @@ even though the user gets a free copy. name="Object" top="16" width="295"> + +Paste Position +[VALUE] + + +Paste Size +[VALUE] + + +Paste Rotation +[VALUE] + Date: Thu, 18 Apr 2019 19:26:37 +0300 Subject: SL-10791 [Legacy Profiles] Functionality to copy agent id and name from profile --- indra/llui/llmenubutton.cpp | 8 ++++ indra/llui/llmenubutton.h | 3 +- indra/newview/llpanelprofile.cpp | 37 +++++++++++++++- indra/newview/llpanelprofile.h | 2 + .../skins/default/textures/icons/CopyBright.png | Bin 0 -> 519 bytes indra/newview/skins/default/textures/textures.xml | 1 + .../skins/default/xui/en/menu_name_field.xml | 22 ++++++++++ .../default/xui/en/panel_profile_secondlife.xml | 48 ++++++++++++++++----- 8 files changed, 109 insertions(+), 12 deletions(-) create mode 100644 indra/newview/skins/default/textures/icons/CopyBright.png create mode 100644 indra/newview/skins/default/xui/en/menu_name_field.xml (limited to 'indra') diff --git a/indra/llui/llmenubutton.cpp b/indra/llui/llmenubutton.cpp index 303afcda15..583704418b 100644 --- a/indra/llui/llmenubutton.cpp +++ b/indra/llui/llmenubutton.cpp @@ -40,6 +40,7 @@ void LLMenuButton::MenuPositions::declareValues() declare("topleft", MP_TOP_LEFT); declare("topright", MP_TOP_RIGHT); declare("bottomleft", MP_BOTTOM_LEFT); + declare("bottomright", MP_BOTTOM_RIGHT); } LLMenuButton::Params::Params() @@ -212,6 +213,13 @@ void LLMenuButton::updateMenuOrigin() mY = rect.mBottom; break; } + case MP_BOTTOM_RIGHT: + { + const LLRect& menu_rect = menu->getRect(); + mX = rect.mRight - menu_rect.getWidth(); + mY = rect.mBottom; + break; + } } } diff --git a/indra/llui/llmenubutton.h b/indra/llui/llmenubutton.h index 67ec1983b3..e42f8f53bd 100644 --- a/indra/llui/llmenubutton.h +++ b/indra/llui/llmenubutton.h @@ -41,7 +41,8 @@ public: { MP_TOP_LEFT, MP_TOP_RIGHT, - MP_BOTTOM_LEFT + MP_BOTTOM_LEFT, + MP_BOTTOM_RIGHT } EMenuPosition; struct MenuPositions diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index e5fa8de6a0..d40f874f24 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -34,7 +34,7 @@ // UI #include "llavatariconctrl.h" -// #include "llclipboard.h" //gClipboard +#include "llclipboard.h" #include "llcheckboxctrl.h" #include "lllineeditor.h" #include "llloadingindicator.h" @@ -269,8 +269,10 @@ BOOL LLPanelProfileSecondLife::postBuild() mGroupInviteButton = getChild("group_invite"); mPayButton = getChild("pay"); mIMButton = getChild("im"); + mCopyMenuButton = getChild("copy_btn"); mStatusText->setVisible(FALSE); + mCopyMenuButton->setVisible(FALSE); mAddFriendButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onAddFriendButtonClick, this)); mIMButton->setCommitCallback(boost::bind(&LLPanelProfileSecondLife::onIMButtonClick, this)); @@ -283,6 +285,9 @@ BOOL LLPanelProfileSecondLife::postBuild() 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(); }); @@ -291,6 +296,7 @@ BOOL LLPanelProfileSecondLife::postBuild() mGroupList->setReturnCallback(boost::bind(&LLPanelProfileSecondLife::openGroupProfile, this)); LLVoiceClient::getInstance()->addObserver((LLVoiceClientStatusObserver*)this); + mCopyMenuButton->setMenu("menu_name_field.xml", LLMenuButton::MP_BOTTOM_RIGHT); return TRUE; } @@ -407,6 +413,7 @@ void LLPanelProfileSecondLife::resetData() mDescriptionEdit->setValue(LLStringUtil::null); mStatusText->setVisible(FALSE); + mCopyMenuButton->setVisible(FALSE); mGroups.clear(); mGroupList->setGroups(mGroups); } @@ -467,6 +474,7 @@ void LLPanelProfileSecondLife::onAvatarNameCache(const LLUUID& agent_id, const L mAvatarNameCacheConnection.disconnect(); getChild("complete_name")->setValue( av_name.getCompleteName() ); + mCopyMenuButton->setVisible(TRUE); } void LLPanelProfileSecondLife::fillCommonData(const LLAvatarData* avatar_data) @@ -763,6 +771,33 @@ void LLPanelProfileSecondLife::onCommitTexture() } } +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()); + } + 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()) diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index 4ed09761df..ba98a360fa 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -178,6 +178,7 @@ private: /*virtual*/ void updateButtons(); void onClickSetName(); void onCommitTexture(); + void onCommitMenu(const LLSD& userdata); void onAvatarNameCacheSetName(const LLUUID& id, const LLAvatarName& av_name); private: @@ -201,6 +202,7 @@ private: LLButton* mGroupInviteButton; LLButton* mPayButton; LLButton* mIMButton; + LLMenuButton* mCopyMenuButton; bool mVoiceStatus; diff --git a/indra/newview/skins/default/textures/icons/CopyBright.png b/indra/newview/skins/default/textures/icons/CopyBright.png new file mode 100644 index 0000000000..8d21c47295 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/CopyBright.png differ diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 2540ee148d..444ad358c3 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -187,6 +187,7 @@ with the same filename but different name + diff --git a/indra/newview/skins/default/xui/en/menu_name_field.xml b/indra/newview/skins/default/xui/en/menu_name_field.xml new file mode 100644 index 0000000000..3c5e5dd353 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_name_field.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml index 8ebb1522b4..e577e6a4d2 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml @@ -112,23 +112,51 @@ layout="topleft" visible="false" /> - + border_visible="false"> + + + + Date: Thu, 18 Apr 2019 23:39:12 -0700 Subject: Build tools paste options menu --- .../skins/default/xui/en/menu_build_paste.xml | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 indra/newview/skins/default/xui/en/menu_build_paste.xml (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/menu_build_paste.xml b/indra/newview/skins/default/xui/en/menu_build_paste.xml new file mode 100644 index 0000000000..f63362dabf --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_build_paste.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From 6d64ba263079546198bd8c4e1890eb39c4eb3a0c Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Wed, 24 Apr 2019 18:54:50 +0300 Subject: SL-11023 [Legacy Profiles] Selection is too low in some field of profile floater --- indra/newview/skins/default/xui/en/panel_group_list_item_short.xml | 2 +- indra/newview/skins/default/xui/en/panel_profile_secondlife.xml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/panel_group_list_item_short.xml b/indra/newview/skins/default/xui/en/panel_group_list_item_short.xml index e15e050fe1..fb46d1cce3 100644 --- a/indra/newview/skins/default/xui/en/panel_group_list_item_short.xml +++ b/indra/newview/skins/default/xui/en/panel_group_list_item_short.xml @@ -43,7 +43,7 @@ @@ -287,10 +287,10 @@ bg_visible="false" border_visible="true" parse_urls="true" - h_pad="0" + h_pad="1" read_only="true" translate="false" - v_pad="2" + v_pad="4" max_length="254" /> -- cgit v1.2.3 From 04eee0ac24de1bf1744ed7a8707a847961fe7192 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Thu, 25 Apr 2019 16:07:20 +0300 Subject: SL-11031 [Legacy Profiles] "Drop inventory" field visible for own profile --- indra/newview/llpanelprofile.cpp | 2 + indra/newview/llpanelprofile.h | 1 + .../default/xui/en/panel_profile_secondlife.xml | 150 ++++++++++++--------- 3 files changed, 93 insertions(+), 60 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index d40f874f24..6c0b1b9047 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -270,6 +270,7 @@ BOOL LLPanelProfileSecondLife::postBuild() mPayButton = getChild("pay"); mIMButton = getChild("im"); mCopyMenuButton = getChild("copy_btn"); + mGiveInvPanel = getChild("give_stack"); mStatusText->setVisible(FALSE); mCopyMenuButton->setVisible(FALSE); @@ -321,6 +322,7 @@ void LLPanelProfileSecondLife::onOpen(const LLSD& key) mBlockButton->setVisible(!own_profile); mUnblockButton->setVisible(!own_profile); mGroupList->setShowNone(!own_profile); + mGiveInvPanel->setVisible(!own_profile); if (own_profile && !getEmbedded()) { diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index ba98a360fa..7d22b64dbe 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -203,6 +203,7 @@ private: LLButton* mPayButton; LLButton* mIMButton; LLMenuButton* mCopyMenuButton; + LLPanel* mGiveInvPanel; bool mVoiceStatus; diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml index a5f486d4a1..f7d3353786 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml @@ -322,76 +322,106 @@ name="group_list" top_delta="-20" left="66" - right="-6" - height="80" + right="-7" + height="82" follows="left|top|right" layout="topleft" border_visible="true" color="ScrollBgWriteableColor" for_agent="false" /> - - - - - - Drop inventory item here. - + + + + + + + + + Drop inventory item here. + + + Date: Thu, 25 Apr 2019 23:03:18 +0300 Subject: SL-11028 [Legacy Profiles] Selection in account field is malfunctioning --- indra/llui/lltextbase.cpp | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) (limited to 'indra') diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index c570285856..61bb64547c 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -445,8 +445,48 @@ void LLTextBase::drawSelectionBackground() ++rect_it) { LLRect selection_rect = *rect_it; - selection_rect = *rect_it; - selection_rect.translate(mVisibleTextRect.mLeft - content_display_rect.mLeft, mVisibleTextRect.mBottom - content_display_rect.mBottom); + if (mScroller) + { + // If scroller is On content_display_rect has correct rect and safe to use as is + // Note: we might need to account for border + selection_rect.translate(mVisibleTextRect.mLeft - content_display_rect.mLeft, mVisibleTextRect.mBottom - content_display_rect.mBottom); + } + else + { + // If scroller is Off content_display_rect will have rect from document, adjusted to text width, heigh and position + // and we have to acount for offset depending on position + S32 v_delta = 0; + S32 h_delta = 0; + switch (mVAlign) + { + case LLFontGL::TOP: + v_delta = mVisibleTextRect.mTop - content_display_rect.mTop - mVPad; + break; + case LLFontGL::VCENTER: + v_delta = (llmax(mVisibleTextRect.getHeight() - content_display_rect.mTop, -content_display_rect.mBottom) + (mVisibleTextRect.mBottom - content_display_rect.mBottom)) / 2; + break; + case LLFontGL::BOTTOM: + v_delta = mVisibleTextRect.mBottom - content_display_rect.mBottom; + break; + default: + break; + } + switch (mHAlign) + { + case LLFontGL::LEFT: + h_delta = mVisibleTextRect.mLeft - content_display_rect.mLeft + mHPad; + break; + case LLFontGL::HCENTER: + h_delta = (llmax(mVisibleTextRect.getWidth() - content_display_rect.mLeft, -content_display_rect.mRight) + (mVisibleTextRect.mRight - content_display_rect.mRight)) / 2; + break; + case LLFontGL::RIGHT: + h_delta = mVisibleTextRect.mRight - content_display_rect.mRight; + break; + default: + break; + } + selection_rect.translate(h_delta, v_delta); + } gl_rect_2d(selection_rect, selection_color); } } -- cgit v1.2.3 From 023a69720876eaec0135b8536e1945db95336a36 Mon Sep 17 00:00:00 2001 From: maxim_productengine Date: Mon, 3 Jun 2019 17:19:05 +0300 Subject: SL-11344 FIXED Private notes are not saved for another avatar --- indra/newview/llfloaterprofile.cpp | 12 +----------- indra/newview/llpanelprofile.cpp | 22 ++++++++++++++++------ indra/newview/llpanelprofile.h | 3 +++ 3 files changed, 20 insertions(+), 17 deletions(-) (limited to 'indra') diff --git a/indra/newview/llfloaterprofile.cpp b/indra/newview/llfloaterprofile.cpp index 216bcb0580..f2863e1e27 100644 --- a/indra/newview/llfloaterprofile.cpp +++ b/indra/newview/llfloaterprofile.cpp @@ -54,12 +54,6 @@ void LLFloaterProfile::onOpen(const LLSD& key) { mPanelProfile->onOpen(key); - if (mAvatarId == gAgentID) - { - getChild("ok_btn")->setVisible(TRUE); - getChild("cancel_btn")->setVisible(TRUE); - } - // Update the avatar name. mNameCallbackConnection = LLAvatarNameCache::get(mAvatarId, boost::bind(&LLFloaterProfile::onAvatarNameCache, this, _1, _2)); } @@ -91,11 +85,7 @@ void LLFloaterProfile::showClassified(const LLUUID& classified_id, bool edit) void LLFloaterProfile::onOKBtn() { - if (mAvatarId == gAgentID) - { - mPanelProfile->apply(); - } - + mPanelProfile->apply(); closeFloater(); } diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 6c0b1b9047..a60493a360 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -1514,6 +1514,13 @@ void LLPanelProfile::onTabChange() { active_panel->updateData(); } + updateBtnsVisibility(); +} + +void LLPanelProfile::updateBtnsVisibility() +{ + getChild("ok_btn")->setVisible(((getSelfProfile() && !getEmbedded()) || isNotesTabSelected())); + getChild("cancel_btn")->setVisible(((getSelfProfile() && !getEmbedded()) || isNotesTabSelected())); } void LLPanelProfile::onOpen(const LLSD& key) @@ -1557,12 +1564,7 @@ void LLPanelProfile::onOpen(const LLSD& key) resetLoading(); updateData(); - // Only show commit buttons on own profile on floater version - if (getSelfProfile() && !getEmbedded()) - { - getChild("ok_btn")->setVisible(TRUE); - getChild("cancel_btn")->setVisible(TRUE); - } + updateBtnsVisibility(); // KC - Not handling pick and classified opening thru onOpen // because this would make unique profile floaters per slurl @@ -1597,6 +1599,10 @@ void LLPanelProfile::apply() //KC - Classifieds handles this itself } + else + { + mPanelNotes->apply(); + } } void LLPanelProfile::showPick(const LLUUID& pick_id) @@ -1613,6 +1619,10 @@ bool LLPanelProfile::isPickTabSelected() return (mTabContainer->getCurrentPanel() == mPanelPicks); } +bool LLPanelProfile::isNotesTabSelected() +{ + return (mTabContainer->getCurrentPanel() == mPanelNotes); +} void LLPanelProfile::showClassified(const LLUUID& classified_id, bool edit) { diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index 7d22b64dbe..9eeb926549 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -409,6 +409,9 @@ public: void showPick(const LLUUID& pick_id = LLUUID::null); bool isPickTabSelected(); + bool isNotesTabSelected(); + + void updateBtnsVisibility(); void showClassified(const LLUUID& classified_id = LLUUID::null, bool edit = false); -- cgit v1.2.3 From 7ff3fe945378f6b43474e99b53e25fe92d69d211 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Mon, 3 Jun 2019 19:49:44 +0300 Subject: SL-11340 [Legacy profiles] The classifieds list cannot be scrolled down --- indra/llui/lltabcontainer.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'indra') diff --git a/indra/llui/lltabcontainer.cpp b/indra/llui/lltabcontainer.cpp index 6521b883f8..1bb666abba 100644 --- a/indra/llui/lltabcontainer.cpp +++ b/indra/llui/lltabcontainer.cpp @@ -392,9 +392,13 @@ void LLTabContainer::draw() S32 cur_scroll_pos = getScrollPos(); if (cur_scroll_pos > 0) { - S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1); - if (!mIsVertical) + if (mIsVertical) { + target_pixel_scroll = cur_scroll_pos * (BTN_HEIGHT + tabcntrv_pad); + } + else + { + S32 available_width_with_arrows = getRect().getWidth() - mRightTabBtnOffset - 2 * (LLPANEL_BORDER_WIDTH + tabcntr_arrow_btn_size + tabcntr_arrow_btn_size + 1); for(tuple_list_t::iterator iter = mTabList.begin(); iter != mTabList.end(); ++iter) { if (cur_scroll_pos == 0) @@ -1175,13 +1179,15 @@ void LLTabContainer::addTabPanel(const TabPanelParams& panel) sendChildToFront(mNextArrowBtn); sendChildToFront(mJumpPrevArrowBtn); sendChildToFront(mJumpNextArrowBtn); - + + updateMaxScrollPos(); + if( select ) { selectLastTab(); + mScrollPos = mMaxScrollPos; } - updateMaxScrollPos(); } void LLTabContainer::addPlaceholder(LLPanel* child, const std::string& label) @@ -2063,9 +2069,9 @@ void LLTabContainer::updateMaxScrollPos() if( tab_total_height > available_height ) { static LLUICachedControl tabcntrv_arrow_btn_size ("UITabCntrvArrowBtnSize", 0); - S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad); + S32 available_height_with_arrows = getRect().getHeight() - 2*(tabcntrv_arrow_btn_size + 3*tabcntrv_pad) - mNextArrowBtn->getRect().mBottom; S32 additional_needed = tab_total_height - available_height_with_arrows; - setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT) ) ); + setMaxScrollPos((S32) ceil(additional_needed / float(BTN_HEIGHT + tabcntrv_pad) ) ); no_scroll = FALSE; } } -- cgit v1.2.3 From 69a85e3ed0960d90c2a093029768a550fb3f591d Mon Sep 17 00:00:00 2001 From: maxim_productengine Date: Wed, 12 Jun 2019 13:43:29 +0300 Subject: SL-11409 [Legacy Profiles] Copy Display name correctly regardless of View Display Names setting. --- indra/newview/llpanelprofile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index a60493a360..472285e3d9 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -787,7 +787,7 @@ void LLPanelProfileSecondLife::onCommitMenu(const LLSD& userdata) LLWString wstr; if (item_name == "display") { - wstr = utf8str_to_wstring(av_name.getDisplayName()); + wstr = utf8str_to_wstring(av_name.getDisplayName(true)); } else if (item_name == "name") { -- cgit v1.2.3 From dbe5eb8a1dc18811f945f689f026cdcf180496dd Mon Sep 17 00:00:00 2001 From: maxim_productengine Date: Tue, 25 Jun 2019 17:54:21 +0300 Subject: SL-11431 [Legacy Profiles] Clicking someone else's profile picture should open image modal. --- indra/newview/llpanelprofile.cpp | 3 +- indra/newview/llpreviewtexture.cpp | 15 +- indra/newview/llpreviewtexture.h | 2 + indra/newview/lltexturectrl.cpp | 33 +++- indra/newview/lltexturectrl.h | 3 + .../default/xui/en/floater_preview_texture.xml | 208 ++++++++++++--------- .../default/xui/en/panel_profile_secondlife.xml | 1 - 7 files changed, 166 insertions(+), 99 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 472285e3d9..86b6163f45 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -324,6 +324,8 @@ void LLPanelProfileSecondLife::onOpen(const LLSD& key) mGroupList->setShowNone(!own_profile); mGiveInvPanel->setVisible(!own_profile); + mSecondLifePic->setOpenTexPreview(!own_profile); + if (own_profile && !getEmbedded()) { // Group list control cannot toggle ForAgent loading @@ -716,7 +718,6 @@ void LLPanelProfileSecondLife::updateButtons() mShowInSearchCheckbox->setVisible(TRUE); mShowInSearchCheckbox->setEnabled(TRUE); mDescriptionEdit->setEnabled(TRUE); - mSecondLifePic->setEnabled(TRUE); } if (!getSelfProfile()) diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 9d8be4b2fe..90cc18fbe9 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -328,7 +328,10 @@ void LLPreviewTexture::reshape(S32 width, S32 height, BOOL called_from_parent) // add space for dimensions and aspect ratio S32 info_height = dim_rect.mTop + CLIENT_RECT_VPAD; - + if (getChild("buttons_panel")->getVisible()) + { + info_height += getChild("buttons_panel")->getRect().getHeight(); + } LLRect client_rect(horiz_pad, getRect().getHeight(), getRect().getWidth() - horiz_pad, 0); client_rect.mTop -= (PREVIEW_HEADER_SIZE + CLIENT_RECT_VPAD); client_rect.mBottom += PREVIEW_BORDER + CLIENT_RECT_VPAD + info_height ; @@ -373,6 +376,16 @@ void LLPreviewTexture::openToSave() mPreviewToSave = TRUE; } +void LLPreviewTexture::hideCtrlButtons() +{ + getChildView("desc txt")->setVisible(false); + getChildView("desc")->setVisible(false); + getChild("preview_stack")->collapsePanel(getChild("buttons_panel"), true); + getChild("buttons_panel")->setVisible(false); + getChild("combo_aspect_ratio")->setCurrentByIndex(0); //unconstrained + reshape(getRect().getWidth(), getRect().getHeight()); +} + // static void LLPreviewTexture::onFileLoadedForSave(BOOL success, LLViewerFetchedTexture *src_vi, diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h index ad77d9e118..e8bba63cb2 100644 --- a/indra/newview/llpreviewtexture.h +++ b/indra/newview/llpreviewtexture.h @@ -66,6 +66,8 @@ public: static void onSaveAsBtn(void* data); + void hideCtrlButtons(); + /*virtual*/ void setObjectID(const LLUUID& object_id); protected: void init(); diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 1396a8546d..f5b96a3b5a 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -47,6 +47,7 @@ #include "llui.h" #include "llviewerinventory.h" #include "llpermissions.h" +#include "llpreviewtexture.h" #include "llsaleinfo.h" #include "llassetstorage.h" #include "lltextbox.h" @@ -997,6 +998,7 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p) mNeedsRawImageData( FALSE ), mValid( TRUE ), mShowLoadingPlaceholder( TRUE ), + mOpenTexPreview(false), mImageAssetID(p.image_id), mDefaultImageAssetID(p.default_image_id), mDefaultImageName(p.default_image_name), @@ -1249,12 +1251,31 @@ BOOL LLTextureCtrl::handleMouseDown(S32 x, S32 y, MASK mask) if (!handled && mBorder->parentPointInView(x, y)) { - showPicker(FALSE); - //grab textures first... - LLInventoryModelBackgroundFetch::instance().start(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE)); - //...then start full inventory fetch. - LLInventoryModelBackgroundFetch::instance().start(); - handled = TRUE; + if (!mOpenTexPreview) + { + showPicker(FALSE); + //grab textures first... + LLInventoryModelBackgroundFetch::instance().start(gInventory.findCategoryUUIDForType(LLFolderType::FT_TEXTURE)); + //...then start full inventory fetch. + LLInventoryModelBackgroundFetch::instance().start(); + handled = TRUE; + } + else + { + if (getImageAssetID().notNull()) + { + LLPreviewTexture* preview_texture = LLFloaterReg::showTypedInstance("preview_texture", getValue()); + if (preview_texture && !preview_texture->isDependent()) + { + LLFloater* root_floater = gFloaterView->getParentFloater(this); + if (root_floater) + { + root_floater->addDependentFloater(preview_texture); + preview_texture->hideCtrlButtons(); + } + } + } + } } return handled; diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index 6bcf9c3a75..6c11e1ecc3 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -160,6 +160,8 @@ public: void setBlankImageAssetID( const LLUUID& id ) { mBlankImageAssetID = id; } const LLUUID& getBlankImageAssetID() const { return mBlankImageAssetID; } + void setOpenTexPreview(bool open_preview) { mOpenTexPreview = open_preview; } + void setCaption(const std::string& caption); void setCanApplyImmediately(BOOL b); @@ -237,6 +239,7 @@ private: BOOL mShowLoadingPlaceholder; std::string mLoadingPlaceholderString; S32 mLabelWidth; + bool mOpenTexPreview; }; ////////////////////////////////////////////////////////////////////////////////////////// diff --git a/indra/newview/skins/default/xui/en/floater_preview_texture.xml b/indra/newview/skins/default/xui/en/floater_preview_texture.xml index e1e7e1c8c8..048cf7df62 100644 --- a/indra/newview/skins/default/xui/en/floater_preview_texture.xml +++ b/indra/newview/skins/default/xui/en/floater_preview_texture.xml @@ -17,94 +17,122 @@ name="Copy"> Copy To Inventory - - Description: - - - - [WIDTH]px x [HEIGHT]px - - - Preview aspect ratio - - - - + + - + Date: Tue, 15 Oct 2019 19:20:36 +0300 Subject: Buildfix (typo) --- indra/newview/llpanelface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 1e0b1874f7..fb99ffef09 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -307,7 +307,7 @@ BOOL LLPanelFace::postBuild() mBtnCopyFaces = getChild("copy_face_btn"); if(mBtnCopyFaces) { - BtnCopyFaces->setCommitCallback(boost::bind(&LLPanelFace::onCopyFaces, this)); + mBtnCopyFaces->setCommitCallback(boost::bind(&LLPanelFace::onCopyFaces, this)); } mBtnPasteFaces = getChild("paste_face_btn"); if (mBtnPasteFaces) -- cgit v1.2.3 From a09f68a809d8537041ea91c0768ba503f107f26b Mon Sep 17 00:00:00 2001 From: AndreyL ProductEngine Date: Thu, 17 Oct 2019 02:46:09 +0300 Subject: Buildfix (typo) --- indra/newview/llpanelface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index fb99ffef09..8f8f1b4763 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -3161,7 +3161,7 @@ void LLPanelFace::pasteFace(LLViewerObject* objectp, S32 te) LLColor4 spec_color(te_data["material"]["SpecColor"]); LLSelectedTEMaterial::setSpecularLightColor(this, spec_color, te); LLSelectedTEMaterial::setSpecularLightExponent(this, (U8)te_data["material"]["SpecExp"].asInteger(), te, object_id); - LLSelectedTEMaterial::setEnvironmentIntensity(this, (U8)te_data["material"]["EnvIntensity"].asInteger(), te), object_id; + LLSelectedTEMaterial::setEnvironmentIntensity(this, (U8)te_data["material"]["EnvIntensity"].asInteger(), te, object_id); LLSelectedTEMaterial::setDiffuseAlphaMode(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id); if (te_data.has("shiny")) { -- cgit v1.2.3 From d3178573bb57a7c5cc997bde90a62e8d6a1affa4 Mon Sep 17 00:00:00 2001 From: maxim_productengine Date: Fri, 18 Oct 2019 17:23:28 +0300 Subject: SL-12156 FIXED [Project Copy/Paste] The prim's shape can be changed by pasting mesh parameters --- indra/newview/llpanelobject.cpp | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index a382813de6..56aea7db5e 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -2158,7 +2158,10 @@ void LLPanelObject::onCopyParams() mParamsClipboard["is_physical"] = objectp->flagUsePhysics(); // Parametrics - getVolumeParams(mClipboardVolumeParams); + if (!objectp->isMesh()) + { + getVolumeParams(mClipboardVolumeParams); + } LLVOVolume *volobjp = NULL; if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) @@ -2188,19 +2191,22 @@ void LLPanelObject::onCopyParams() if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) { LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); - - LLUUID texture_id = sculpt_params->getSculptTexture(); - if (canCopyTexture(texture_id)) - { - LL_INFOS() << "copu texture " << LL_ENDL; - mParamsClipboard["sculpt"]["id"] = texture_id; - } - else + + if (!objectp->isMesh()) { - mParamsClipboard["sculpt"]["id"] = LLUUID(SCULPT_DEFAULT_TEXTURE); - } + LLUUID texture_id = sculpt_params->getSculptTexture(); + if (canCopyTexture(texture_id)) + { + LL_INFOS() << "copy texture " << LL_ENDL; + mParamsClipboard["sculpt"]["id"] = texture_id; + } + else + { + mParamsClipboard["sculpt"]["id"] = LLUUID(SCULPT_DEFAULT_TEXTURE); + } - mParamsClipboard["sculpt"]["type"] = sculpt_params->getSculptType(); + mParamsClipboard["sculpt"]["type"] = sculpt_params->getSculptType(); + } } // Light Source -- cgit v1.2.3 From 5310f215323aee7caec188ccc9d871e920385113 Mon Sep 17 00:00:00 2001 From: andreykproductengine Date: Mon, 21 Oct 2019 17:46:26 +0300 Subject: SL-12158 Fixed messy 'Align' button positioning --- indra/newview/skins/default/xui/en/panel_tools_texture.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml index ec610758cc..1819106970 100644 --- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml @@ -806,14 +806,14 @@ top_delta="16" width="260" /> - - @@ -1858,7 +1722,7 @@ Paste Rotation increment="5" initial_value="0" layout="topleft" - left="135" + left="125" max_val="95" name="Scale 1" top_pad="4" @@ -1882,7 +1746,7 @@ Paste Rotation follows="left|top" height="15" layout="topleft" - left="135" + left="125" name="Hollow Shape" top_pad="4" width="150"> @@ -1960,7 +1824,7 @@ Paste Rotation follows="left|top" height="10" layout="topleft" - left="135" + left="125" name="scale_taper" top_pad="3" width="150"> @@ -2013,7 +1877,7 @@ Paste Rotation follows="left|top" height="10" layout="topleft" - left="135" + left="125" name="text topshear" top_pad="3" width="141"> @@ -2056,7 +1920,7 @@ Paste Rotation follows="left|top" height="10" layout="topleft" - left="135" + left="125" name="advanced_cut" top_pad="3" width="150"> @@ -2120,7 +1984,7 @@ Paste Rotation follows="left|top" height="10" layout="topleft" - left="135" + left="125" name="text taper2" top_pad="3" width="150"> @@ -2163,7 +2027,7 @@ Paste Rotation follows="left|top" height="10" layout="topleft" - left="135" + left="125" name="text radius delta" top_pad="2" width="78"> @@ -2188,7 +2052,7 @@ Paste Rotation increment="0.05" initial_value="0" layout="topleft" - left="135" + left="125" min_val="-1" name="Radius Offset" top_pad="4" @@ -2213,7 +2077,7 @@ Paste Rotation height="141" label="Sculpt Texture" layout="topleft" - left="135" + left="125" name="sculpt texture control" tool_tip="Click to choose a picture" top="70" @@ -2671,7 +2535,7 @@ Paste Rotation top_pad="8" width="132" /> - - - - - - - - - - - - - - - - - - - - - - - - -- cgit v1.2.3 From f363646eb71d58007fc4936a67ad9c7bde9b93ac Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 2 Jun 2020 21:53:28 +0300 Subject: SL-13359 #2 UI changes for panel object todo: new icons, separator and some repositioning --- indra/newview/llpanelobject.cpp | 82 +++++++++++++++++++--- indra/newview/llpanelobject.h | 7 ++ .../newview/skins/default/xui/en/floater_tools.xml | 64 ++++++++++++++--- .../skins/default/xui/en/menu_copy_paste_pos.xml | 21 ++++++ .../skins/default/xui/en/menu_copy_paste_rot.xml | 21 ++++++ .../skins/default/xui/en/menu_copy_paste_size.xml | 21 ++++++ 6 files changed, 197 insertions(+), 19 deletions(-) create mode 100644 indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml create mode 100644 indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml create mode 100644 indra/newview/skins/default/xui/en/menu_copy_paste_size.xml (limited to 'indra') diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 5fd9655201..e6bbac8247 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -118,8 +118,9 @@ BOOL LLPanelObject::postBuild() // Phantom checkbox mCheckPhantom = getChild("Phantom Checkbox Ctrl"); childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this); - + // Position + mMenuPastePos = getChild("paste_pos_btn"); mLabelPosition = getChild("label position"); mCtrlPosX = getChild("Pos X"); childSetCommitCallback("Pos X",onCommitPosition,this); @@ -129,6 +130,7 @@ BOOL LLPanelObject::postBuild() childSetCommitCallback("Pos Z",onCommitPosition,this); // Scale + mMenuPasteSize = getChild("paste_size_btn"); mLabelSize = getChild("label size"); mCtrlScaleX = getChild("Scale X"); childSetCommitCallback("Scale X",onCommitScale,this); @@ -142,6 +144,7 @@ BOOL LLPanelObject::postBuild() childSetCommitCallback("Scale Z",onCommitScale,this); // Rotation + mMenuPasteRot = getChild("paste_rot_btn"); mLabelRotation = getChild("label rotation"); mCtrlRotX = getChild("Rot X"); childSetCommitCallback("Rot X",onCommitRotation,this); @@ -291,6 +294,8 @@ LLPanelObject::LLPanelObject() mHasRotClipboard(FALSE), mSizeChanged(FALSE) { + mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", boost::bind(&LLPanelObject::menuDoToSelected, this, _2)); + mEnableCallbackRegistrar.add("PanelObject.menuEnable", boost::bind(&LLPanelObject::menuEnableItem, this, _2)); } @@ -377,7 +382,7 @@ void LLPanelObject::getState( ) calcp->clearVar(LLCalc::Z_POS); } - + mMenuPastePos->setEnabled(enable_move); mLabelPosition->setEnabled( enable_move ); mCtrlPosX->setEnabled(enable_move); mCtrlPosY->setEnabled(enable_move); @@ -403,6 +408,7 @@ void LLPanelObject::getState( ) calcp->setVar(LLCalc::Z_SCALE, 0.f); } + mMenuPasteSize->setEnabled(enable_scale); mLabelSize->setEnabled( enable_scale ); mCtrlScaleX->setEnabled( enable_scale ); mCtrlScaleY->setEnabled( enable_scale ); @@ -434,6 +440,7 @@ void LLPanelObject::getState( ) calcp->clearVar(LLCalc::Z_ROT); } + mMenuPasteRot->setEnabled(enable_rotate); mLabelRotation->setEnabled( enable_rotate ); mCtrlRotX->setEnabled( enable_rotate ); mCtrlRotY->setEnabled( enable_rotate ); @@ -1648,6 +1655,8 @@ void LLPanelObject::sendPosition(BOOL btn_down) LLVector3 newpos(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get()); LLViewerRegion* regionp = mObject->getRegion(); + if (!regionp) return; + // Clamp the Z height const F32 height = newpos.mV[VZ]; const F32 min_height = LLWorld::getInstance()->getMinAllowedZ(mObject, mObject->getPositionGlobal()); @@ -2005,6 +2014,57 @@ void LLPanelObject::onCommitSculptType(LLUICtrl *ctrl, void* userdata) self->sendSculpt(); } +void LLPanelObject::menuDoToSelected(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + // paste + if (command == "pos_paste") + { + onPastePos(); + } + else if (command == "size_paste") + { + onPasteSize(); + } + else if (command == "rot_paste") + { + onPasteRot(); + } + // copy + else if (command == "pos_copy") + { + onCopyPos(); + } + else if (command == "size_copy") + { + onCopySize(); + } + else if (command == "rot_copy") + { + onCopyRot(); + } +} + +bool LLPanelObject::menuEnableItem(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + if (command == "pos_paste") + { + return mHasPosClipboard; + } + else if (command == "size_paste") + { + return mHasSizeClipboard; + } + else if (command == "rot_paste") + { + return mHasRotClipboard; + } + return false; +} + void LLPanelObject::onCopyPos() { mClipboardPos = LLVector3(mCtrlPosX->get(), mCtrlPosY->get(), mCtrlPosZ->get()); @@ -2037,14 +2097,20 @@ void LLPanelObject::onCopyRot() void LLPanelObject::onPastePos() { - if(!mHasPosClipboard) return; + if (!mHasPosClipboard) return; + if (mObject.isNull()) return; + + LLViewerRegion* regionp = mObject->getRegion(); + if (!regionp) return; + // Clamp pos on non-attachments, just keep the prims within the region if (!mObject->isAttachment()) { - mClipboardPos.mV[VX] = llclamp( mClipboardPos.mV[VX], 0.f, 256.f); - mClipboardPos.mV[VY] = llclamp( mClipboardPos.mV[VY], 0.f, 256.f); - //height will get properly clammed by sendPosition + F32 max_width = regionp->getWidth(); // meters + mClipboardPos.mV[VX] = llclamp(mClipboardPos.mV[VX], 0.f, max_width); + mClipboardPos.mV[VY] = llclamp(mClipboardPos.mV[VY], 0.f, max_width); + //height will get properly clamped by sendPosition } mCtrlPosX->set( mClipboardPos.mV[VX] ); @@ -2056,7 +2122,7 @@ void LLPanelObject::onPastePos() void LLPanelObject::onPasteSize() { - if(!mHasSizeClipboard) return; + if (!mHasSizeClipboard) return; mClipboardSize.mV[VX] = llclamp(mClipboardSize.mV[VX], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE); mClipboardSize.mV[VY] = llclamp(mClipboardSize.mV[VY], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE); @@ -2071,7 +2137,7 @@ void LLPanelObject::onPasteSize() void LLPanelObject::onPasteRot() { - if(!mHasRotClipboard) return; + if (!mHasRotClipboard) return; mCtrlRotX->set( mClipboardRot.mV[VX] ); mCtrlRotY->set( mClipboardRot.mV[VY] ); diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index e9b9254a78..e8f8d0eb9a 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -37,6 +37,7 @@ class LLCheckBoxCtrl; class LLTextBox; class LLUICtrl; class LLButton; +class LLMenuButton; class LLViewerObject; class LLComboBox; class LLColorSwatchCtrl; @@ -81,6 +82,9 @@ public: BOOL onDropSculpt(LLInventoryItem* item); static void onCommitSculptType( LLUICtrl *ctrl, void* userdata); + void menuDoToSelected(const LLSD& userdata); + bool menuEnableItem(const LLSD& userdata); + protected: void getState(); @@ -137,17 +141,20 @@ protected: LLTextBox* mLabelRevolutions; LLSpinCtrl* mSpinRevolutions; + LLMenuButton* mMenuPastePos; LLTextBox* mLabelPosition; LLSpinCtrl* mCtrlPosX; LLSpinCtrl* mCtrlPosY; LLSpinCtrl* mCtrlPosZ; + LLMenuButton* mMenuPasteSize; LLTextBox* mLabelSize; LLSpinCtrl* mCtrlScaleX; LLSpinCtrl* mCtrlScaleY; LLSpinCtrl* mCtrlScaleZ; BOOL mSizeChanged; + LLMenuButton* mMenuPasteRot; LLTextBox* mLabelRotation; LLSpinCtrl* mCtrlRotX; LLSpinCtrl* mCtrlRotY; diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 0abee2ff80..2397be6b61 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1430,6 +1430,18 @@ even though the user gets a free copy. tool_tip="Causes object to not collide with other objects or avatars" top_pad="0" width="123" /> + - Position (meters) + Position + - Size (meters) + Size + - Rotation (degrees) + Rotation + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml new file mode 100644 index 0000000000..dcfb3faeca --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml new file mode 100644 index 0000000000..58d71b12d5 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + -- cgit v1.2.3 From 30f1038351734b946be9a6f910e4e0eca82be1d4 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 3 Jun 2020 16:12:11 +0300 Subject: SL-13359 #3 UI changes for panel object --- indra/newview/llpanelobject.cpp | 12 +++--- indra/newview/llpanelobject.h | 6 +-- .../textures/icons/ClipboardSmallMenu_Disabled.png | Bin 0 -> 218 bytes .../textures/icons/ClipboardSmallMenu_Off.png | Bin 0 -> 217 bytes .../textures/icons/ClipboardSmallMenu_Press.png | Bin 0 -> 215 bytes indra/newview/skins/default/textures/textures.xml | 4 ++ .../newview/skins/default/xui/en/floater_tools.xml | 48 +++++++++++++-------- 7 files changed, 42 insertions(+), 28 deletions(-) create mode 100644 indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png create mode 100644 indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png create mode 100644 indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png (limited to 'indra') diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index e6bbac8247..6fa2da7bac 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -120,7 +120,7 @@ BOOL LLPanelObject::postBuild() childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this); // Position - mMenuPastePos = getChild("paste_pos_btn"); + mMenuClipboardPos = getChild("clipboard_pos_btn"); mLabelPosition = getChild("label position"); mCtrlPosX = getChild("Pos X"); childSetCommitCallback("Pos X",onCommitPosition,this); @@ -130,7 +130,7 @@ BOOL LLPanelObject::postBuild() childSetCommitCallback("Pos Z",onCommitPosition,this); // Scale - mMenuPasteSize = getChild("paste_size_btn"); + mMenuClipboardSize = getChild("clipboard_size_btn"); mLabelSize = getChild("label size"); mCtrlScaleX = getChild("Scale X"); childSetCommitCallback("Scale X",onCommitScale,this); @@ -144,7 +144,7 @@ BOOL LLPanelObject::postBuild() childSetCommitCallback("Scale Z",onCommitScale,this); // Rotation - mMenuPasteRot = getChild("paste_rot_btn"); + mMenuClipboardRot = getChild("clipboard_rot_btn"); mLabelRotation = getChild("label rotation"); mCtrlRotX = getChild("Rot X"); childSetCommitCallback("Rot X",onCommitRotation,this); @@ -382,7 +382,7 @@ void LLPanelObject::getState( ) calcp->clearVar(LLCalc::Z_POS); } - mMenuPastePos->setEnabled(enable_move); + mMenuClipboardPos->setEnabled(enable_move); mLabelPosition->setEnabled( enable_move ); mCtrlPosX->setEnabled(enable_move); mCtrlPosY->setEnabled(enable_move); @@ -408,7 +408,7 @@ void LLPanelObject::getState( ) calcp->setVar(LLCalc::Z_SCALE, 0.f); } - mMenuPasteSize->setEnabled(enable_scale); + mMenuClipboardSize->setEnabled(enable_scale); mLabelSize->setEnabled( enable_scale ); mCtrlScaleX->setEnabled( enable_scale ); mCtrlScaleY->setEnabled( enable_scale ); @@ -440,7 +440,7 @@ void LLPanelObject::getState( ) calcp->clearVar(LLCalc::Z_ROT); } - mMenuPasteRot->setEnabled(enable_rotate); + mMenuClipboardRot->setEnabled(enable_rotate); mLabelRotation->setEnabled( enable_rotate ); mCtrlRotX->setEnabled( enable_rotate ); mCtrlRotY->setEnabled( enable_rotate ); diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index e8f8d0eb9a..764c0d8af4 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -141,20 +141,20 @@ protected: LLTextBox* mLabelRevolutions; LLSpinCtrl* mSpinRevolutions; - LLMenuButton* mMenuPastePos; + LLMenuButton* mMenuClipboardPos; LLTextBox* mLabelPosition; LLSpinCtrl* mCtrlPosX; LLSpinCtrl* mCtrlPosY; LLSpinCtrl* mCtrlPosZ; - LLMenuButton* mMenuPasteSize; + LLMenuButton* mMenuClipboardSize; LLTextBox* mLabelSize; LLSpinCtrl* mCtrlScaleX; LLSpinCtrl* mCtrlScaleY; LLSpinCtrl* mCtrlScaleZ; BOOL mSizeChanged; - LLMenuButton* mMenuPasteRot; + LLMenuButton* mMenuClipboardRot; LLTextBox* mLabelRotation; LLSpinCtrl* mCtrlRotX; LLSpinCtrl* mCtrlRotY; diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png new file mode 100644 index 0000000000..63b4bd2127 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Disabled.png differ diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png new file mode 100644 index 0000000000..4200182b0c Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Off.png differ diff --git a/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png new file mode 100644 index 0000000000..e12887f489 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardSmallMenu_Press.png differ diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 7325d836d2..b7fa1e72f8 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -438,6 +438,10 @@ with the same filename but different name + + + + diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 2397be6b61..7768f894b8 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1430,19 +1430,29 @@ even though the user gets a free copy. tool_tip="Causes object to not collide with other objects or avatars" top_pad="0" width="123" /> + - Date: Wed, 3 Jun 2020 19:37:53 +0300 Subject: SL-13359 #4 Adjusted some elements --- indra/newview/skins/default/xui/en/floater_tools.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 7768f894b8..afc6155585 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1460,10 +1460,10 @@ even though the user gets a free copy. layout="topleft" name="label position" tool_tip="Position (meters)" - left_pad="3" + left_pad="8" top_delta="0" width="121"> - Position + Position (m) - Size + Size (m) - Rotation + Rotation (°) Date: Wed, 17 Jun 2020 23:38:55 +0300 Subject: SL-13359 #5 Implemented revised changes --- indra/newview/llfloatermodelpreview.cpp | 1 + indra/newview/llpanelface.cpp | 64 +----- indra/newview/llpanelface.h | 7 - indra/newview/llpanelobject.cpp | 219 ++++++++++++++++++--- indra/newview/llpanelobject.h | 11 +- indra/newview/lltexturectrl.cpp | 55 ++++++ indra/newview/lltexturectrl.h | 10 + .../textures/icons/ClipboardMenu_Disabled.png | Bin 0 -> 231 bytes .../default/textures/icons/ClipboardMenu_Off.png | Bin 0 -> 231 bytes .../default/textures/icons/ClipboardMenu_Press.png | Bin 0 -> 224 bytes indra/newview/skins/default/textures/textures.xml | 3 + .../newview/skins/default/xui/en/floater_tools.xml | 31 ++- .../default/xui/en/menu_copy_paste_generic.xml | 21 ++ .../skins/default/xui/en/menu_copy_paste_pos.xml | 26 ++- .../skins/default/xui/en/menu_copy_paste_rot.xml | 26 ++- .../skins/default/xui/en/menu_copy_paste_size.xml | 26 ++- 16 files changed, 382 insertions(+), 118 deletions(-) create mode 100644 indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png create mode 100644 indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png create mode 100644 indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png create mode 100644 indra/newview/skins/default/xui/en/menu_copy_paste_generic.xml (limited to 'indra') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index bc44e37c5a..f44dd92ddb 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -4379,6 +4379,7 @@ void LLModelPreview::textureLoadedCallback( if(final && preview->mModelLoader) { + // for areTexturesReady() if(preview->mModelLoader->mNumOfFetchingTextures > 0) { preview->mModelLoader->mNumOfFetchingTextures-- ; diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 369861fa25..6e99a10b98 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -54,7 +54,6 @@ #include "llmediaentry.h" #include "llmenubutton.h" #include "llnotificationsutil.h" -#include "llpanelobject.h" // LLPanelObject::canCopyTexture #include "llradiogroup.h" #include "llresmgr.h" #include "llselectmgr.h" @@ -2929,7 +2928,7 @@ void LLPanelFace::onCopyFaces() { LLUUID item_id; LLUUID id = te_data["te"]["imageid"].asUUID(); - bool full_perm = LLPanelFace::isLibraryTexture(id) || (objectp->permCopy() && objectp->permTransfer() && objectp->permModify()); + bool full_perm = get_is_library_texture(id) || (objectp->permCopy() && objectp->permTransfer() && objectp->permModify()); if (id.notNull() && !full_perm) { @@ -2944,7 +2943,7 @@ void LLPanelFace::onCopyFaces() // as result it is Hightly unreliable, leaves little control to user, borderline hack // but there are little options to preserve permissions - multiple inventory // items might reference same asset and inventory search is expensive. - item_id = LLPanelFace::getCopyPermInventoryTextureId(id); + item_id = get_copy_free_item_by_asset_id(id); // record value to avoid repeating inventory search when possible asset_item_map[id] = item_id; } @@ -3022,7 +3021,7 @@ void LLPanelFace::onCopyFaces() if (mat_data.has("NormMap")) { LLUUID id = mat_data["NormMap"].asUUID(); - if (id.notNull() && !LLPanelFace::canCopyTexture(id)) + if (id.notNull() && !get_can_copy_texture(id)) { mat_data["NormMap"] = LLUUID(gSavedSettings.getString( "DefaultObjectTexture" )); mat_data["NormMapNoCopy"] = true; @@ -3032,7 +3031,7 @@ void LLPanelFace::onCopyFaces() if (mat_data.has("SpecMap")) { LLUUID id = mat_data["SpecMap"].asUUID(); - if (id.notNull() && !LLPanelFace::canCopyTexture(id)) + if (id.notNull() && !get_can_copy_texture(id)) { mat_data["SpecMap"] = LLUUID(gSavedSettings.getString( "DefaultObjectTexture" )); mat_data["SpecMapNoCopy"] = true; @@ -3504,58 +3503,3 @@ bool LLPanelFace::pasteEnabletMenuItem(const LLSD& userdata) return true; } - -//static -bool LLPanelFace::isLibraryTexture(LLUUID image_id) -{ - if (gInventory.isObjectDescendentOf(image_id, gInventory.getLibraryRootFolderID()) - || image_id == LLUUID(gSavedSettings.getString("DefaultObjectTexture")) - || image_id == LLUUID(gSavedSettings.getString("UIImgWhiteUUID")) - || image_id == LLUUID(gSavedSettings.getString("UIImgInvisibleUUID")) - || image_id == LLUUID(SCULPT_DEFAULT_TEXTURE)) - { - return true; - } - return false; -} - -//static -LLUUID LLPanelFace::getCopyPermInventoryTextureId(LLUUID image_id) -{ - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - LLAssetIDMatches asset_id_matches(image_id); - gInventory.collectDescendentsIf(LLUUID::null, - cats, - items, - LLInventoryModel::INCLUDE_TRASH, - asset_id_matches); - if (items.size()) - { - for (S32 i = 0; i < items.size(); i++) - { - LLViewerInventoryItem* itemp = items[i]; - if (itemp) - { - LLPermissions item_permissions = itemp->getPermissions(); - if (item_permissions.allowOperationBy(PERM_COPY, - gAgent.getID(), - gAgent.getGroupID())) - { - return itemp->getUUID(); - } - } - } - } - return LLUUID::null; -} - -// Static -bool LLPanelFace::canCopyTexture(LLUUID image_id) -{ - // User is allowed to copy a texture if: - // library asset or default texture, - // or copy perm asset exists in user's inventory - - return isLibraryTexture(image_id) || getCopyPermInventoryTextureId(image_id).notNull(); -} diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index dbf3531332..770f10e2ee 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -115,13 +115,6 @@ public: LLRender::eTexIndex getTextureChannelToEdit(); void pasteFace(LLViewerObject* object, S32 te); - static bool isLibraryTexture(LLUUID image_id); - - // Finds copy-enabled texture with specified asset from inventory - // This can be performance unfriendly and doesn't warranty that - // the texture is original source of asset - static LLUUID getCopyPermInventoryTextureId(LLUUID image_id); - static bool canCopyTexture(LLUUID image_id); protected: void getState(); diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 6fa2da7bac..f1426ddf33 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -159,6 +159,8 @@ BOOL LLPanelObject::postBuild() mComboBaseType = getChild("comboBaseType"); childSetCommitCallback("comboBaseType",onCommitParametric,this); + mMenuClipboardParams = getChild("clipboard_params_btn"); + // Cut mLabelCut = getChild("text cut"); mSpinCutBegin = getChild("cut begin"); @@ -289,9 +291,10 @@ LLPanelObject::LLPanelObject() mSelectedType(MI_BOX), mSculptTextureRevert(LLUUID::null), mSculptTypeRevert(0), - mHasPosClipboard(FALSE), - mHasSizeClipboard(FALSE), - mHasRotClipboard(FALSE), + mHasClipboardPos(false), + mHasClipboardSize(false), + mHasClipboardRot(false), + mHasClipboardParams(false), mSizeChanged(FALSE) { mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", boost::bind(&LLPanelObject::menuDoToSelected, this, _2)); @@ -618,7 +621,7 @@ void LLPanelObject::getState( ) } else { - LL_INFOS() << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL; + LL_INFOS("FloaterTools") << "Unknown path " << (S32) path << " profile " << (S32) profile << " in getState" << LL_ENDL; selected_item = MI_BOX; } @@ -944,6 +947,7 @@ void LLPanelObject::getState( ) // Update field enablement mComboBaseType ->setEnabled( enabled ); + mMenuClipboardParams->setEnabled(enabled); mLabelCut ->setEnabled( enabled ); mSpinCutBegin ->setEnabled( enabled ); @@ -1104,7 +1108,8 @@ void LLPanelObject::getState( ) } mComboBaseType->setEnabled(!isMesh); - + mMenuClipboardParams->setEnabled(!isMesh); + if (mCtrlSculptType) { if (sculpt_stitching == LL_SCULPT_TYPE_NONE) @@ -1168,11 +1173,11 @@ void LLPanelObject::sendIsPhysical() LLSelectMgr::getInstance()->selectionUpdatePhysics(value); mIsPhysical = value; - LL_INFOS() << "update physics sent" << LL_ENDL; + LL_INFOS("FloaterTools") << "update physics sent" << LL_ENDL; } else { - LL_INFOS() << "update physics not changed" << LL_ENDL; + LL_INFOS("FloaterTools") << "update physics not changed" << LL_ENDL; } } @@ -1184,11 +1189,11 @@ void LLPanelObject::sendIsTemporary() LLSelectMgr::getInstance()->selectionUpdateTemporary(value); mIsTemporary = value; - LL_INFOS() << "update temporary sent" << LL_ENDL; + LL_INFOS("FloaterTools") << "update temporary sent" << LL_ENDL; } else { - LL_INFOS() << "update temporary not changed" << LL_ENDL; + LL_INFOS("FloaterTools") << "update temporary not changed" << LL_ENDL; } } @@ -1201,11 +1206,11 @@ void LLPanelObject::sendIsPhantom() LLSelectMgr::getInstance()->selectionUpdatePhantom(value); mIsPhantom = value; - LL_INFOS() << "update phantom sent" << LL_ENDL; + LL_INFOS("FloaterTools") << "update phantom sent" << LL_ENDL; } else { - LL_INFOS() << "update phantom not changed" << LL_ENDL; + LL_INFOS("FloaterTools") << "update phantom not changed" << LL_ENDL; } } @@ -1315,7 +1320,7 @@ void LLPanelObject::getVolumeParams(LLVolumeParams& volume_params) break; default: - LL_WARNS() << "Unknown base type " << selected_type + LL_WARNS("FloaterTools") << "Unknown base type " << selected_type << " in getVolumeParams()" << LL_ENDL; // assume a box selected_type = MI_BOX; @@ -2019,7 +2024,13 @@ void LLPanelObject::menuDoToSelected(const LLSD& userdata) std::string command = userdata.asString(); // paste - if (command == "pos_paste") + if (command == "psr_paste") + { + onPastePos(); + onPasteSize(); + onPasteRot(); + } + else if (command == "pos_paste") { onPastePos(); } @@ -2031,7 +2042,17 @@ void LLPanelObject::menuDoToSelected(const LLSD& userdata) { onPasteRot(); } + else if (command == "params_paste") + { + onPasteParams(); + } // copy + else if (command == "psr_copy") + { + onCopyPos(); + onCopySize(); + onCopyRot(); + } else if (command == "pos_copy") { onCopyPos(); @@ -2044,23 +2065,71 @@ void LLPanelObject::menuDoToSelected(const LLSD& userdata) { onCopyRot(); } + else if (command == "params_copy") + { + onCopyParams(); + } } bool LLPanelObject::menuEnableItem(const LLSD& userdata) { std::string command = userdata.asString(); - if (command == "pos_paste") + // paste options + if (command == "psr_paste") + { + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode(LL_PCODE_VOLUME)) + && (selected_count == 1); + + if (!single_volume) + { + return false; + } + + bool enable_move; + bool enable_modify; + + LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(enable_move, enable_modify); + + return enable_move && enable_modify && mHasClipboardPos && mHasClipboardSize && mHasClipboardRot; + } + else if (command == "pos_paste") { - return mHasPosClipboard; + // assumes that menu won't be active if there is no move permission + return mHasClipboardPos; } else if (command == "size_paste") { - return mHasSizeClipboard; + return mHasClipboardSize; } else if (command == "rot_paste") { - return mHasRotClipboard; + return mHasClipboardRot; + } + else if (command == "params_paste") + { + return mHasClipboardParams; + } + // copy options + else if (command == "psr_copy") + { + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + BOOL single_volume = (LLSelectMgr::getInstance()->selectionAllPCode(LL_PCODE_VOLUME)) + && (selected_count == 1); + + if (!single_volume) + { + return false; + } + + bool enable_move; + bool enable_modify; + + LLSelectMgr::getInstance()->selectGetEditMoveLinksetPermissions(enable_move, enable_modify); + + // since we forbid seeing values we also should forbid copying them + return enable_move && enable_modify; } return false; } @@ -2072,7 +2141,7 @@ void LLPanelObject::onCopyPos() std::string stringVec = llformat("<%g, %g, %g>", mClipboardPos.mV[VX], mClipboardPos.mV[VY], mClipboardPos.mV[VZ]); LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec)); - mHasPosClipboard = TRUE; + mHasClipboardPos = true; } void LLPanelObject::onCopySize() @@ -2082,7 +2151,7 @@ void LLPanelObject::onCopySize() std::string stringVec = llformat("<%g, %g, %g>", mClipboardSize.mV[VX], mClipboardSize.mV[VY], mClipboardSize.mV[VZ]); LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec)); - mHasSizeClipboard = TRUE; + mHasClipboardSize = true; } void LLPanelObject::onCopyRot() @@ -2092,12 +2161,12 @@ void LLPanelObject::onCopyRot() std::string stringVec = llformat("<%g, %g, %g>", mClipboardRot.mV[VX], mClipboardRot.mV[VY], mClipboardRot.mV[VZ]); LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(stringVec)); - mHasRotClipboard = TRUE; + mHasClipboardRot = true; } void LLPanelObject::onPastePos() { - if (!mHasPosClipboard) return; + if (!mHasClipboardPos) return; if (mObject.isNull()) return; LLViewerRegion* regionp = mObject->getRegion(); @@ -2122,26 +2191,118 @@ void LLPanelObject::onPastePos() void LLPanelObject::onPasteSize() { - if (!mHasSizeClipboard) return; + if (!mHasClipboardSize) return; mClipboardSize.mV[VX] = llclamp(mClipboardSize.mV[VX], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE); mClipboardSize.mV[VY] = llclamp(mClipboardSize.mV[VY], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE); mClipboardSize.mV[VZ] = llclamp(mClipboardSize.mV[VZ], MIN_PRIM_SCALE, DEFAULT_MAX_PRIM_SCALE); - mCtrlScaleX->set( mClipboardSize.mV[VX] ); - mCtrlScaleY->set( mClipboardSize.mV[VY] ); - mCtrlScaleZ->set( mClipboardSize.mV[VZ] ); + mCtrlScaleX->set(mClipboardSize.mV[VX]); + mCtrlScaleY->set(mClipboardSize.mV[VY]); + mCtrlScaleZ->set(mClipboardSize.mV[VZ]); sendScale(FALSE); } void LLPanelObject::onPasteRot() { - if (!mHasRotClipboard) return; + if (!mHasClipboardRot) return; - mCtrlRotX->set( mClipboardRot.mV[VX] ); - mCtrlRotY->set( mClipboardRot.mV[VY] ); - mCtrlRotZ->set( mClipboardRot.mV[VZ] ); + mCtrlRotX->set(mClipboardRot.mV[VX]); + mCtrlRotY->set(mClipboardRot.mV[VY]); + mCtrlRotZ->set(mClipboardRot.mV[VZ]); sendRotation(FALSE); } + +void LLPanelObject::onCopyParams() +{ + LLViewerObject* objectp = mObject; + if (!objectp) + { + return; + } + + mClipboardParams.clear(); + + // Parametrics + if (!objectp->isMesh()) + { + LLVolumeParams params; + getVolumeParams(params); + mClipboardParams["volume_params"] = params.asLLSD(); + } + + // Sculpted Prim + if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) + { + LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + + if (!objectp->isMesh()) + { + LLUUID texture_id = sculpt_params->getSculptTexture(); + if (get_can_copy_texture(texture_id)) + { + LL_DEBUGS("FloaterTools") << "Recording texture" << LL_ENDL; + mClipboardParams["sculpt"]["id"] = texture_id; + } + else + { + mClipboardParams["sculpt"]["id"] = LLUUID(SCULPT_DEFAULT_TEXTURE); + } + + mClipboardParams["sculpt"]["type"] = sculpt_params->getSculptType(); + } + } + + mHasClipboardParams = TRUE; +} + +void LLPanelObject::onPasteParams() +{ + LLViewerObject* objectp = mObject; + if (!objectp || !mHasClipboardParams) + { + return; + } + + // Sculpted Prim + if (mClipboardParams.has("sculpt")) + { + LLSculptParams sculpt_params; + LLUUID sculpt_id = mClipboardParams["sculpt"]["id"].asUUID(); + U8 sculpt_type = (U8)mClipboardParams["sculpt"]["type"].asInteger(); + sculpt_params.setSculptTexture(sculpt_id, sculpt_type); + objectp->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE); + } + else + { + LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); + if (sculpt_params) + { + objectp->setParameterEntryInUse(LLNetworkData::PARAMS_SCULPT, FALSE, TRUE); + } + } + + // volume params + // make sure updateVolume() won't affect flexible + if (mClipboardParams.has("volume_params")) + { + LLVolumeParams params; + params.fromLLSD(mClipboardParams["volume_params"]); + LLVOVolume *volobjp = (LLVOVolume *)objectp; + if (volobjp->isFlexible()) + { + if (params.getPathParams().getCurveType() == LL_PCODE_PATH_LINE) + { + params.getPathParams().setCurveType(LL_PCODE_PATH_FLEXIBLE); + } + } + else if (params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE) + { + params.getPathParams().setCurveType(LL_PCODE_PATH_LINE); + } + + objectp->updateVolume(params); + } +} diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index 764c0d8af4..5ea3d07699 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -73,6 +73,8 @@ public: void onPasteSize(); void onCopyRot(); void onPasteRot(); + void onCopyParams(); + void onPasteParams(); static void onCommitParametric(LLUICtrl* ctrl, void* userdata); @@ -102,6 +104,7 @@ protected: protected: // Per-object options LLComboBox* mComboBaseType; + LLMenuButton* mMenuClipboardParams; LLTextBox* mLabelCut; LLSpinCtrl* mSpinCutBegin; @@ -183,10 +186,12 @@ protected: LLVector3 mClipboardPos; LLVector3 mClipboardSize; LLVector3 mClipboardRot; + LLSD mClipboardParams; - BOOL mHasPosClipboard; - BOOL mHasSizeClipboard; - BOOL mHasRotClipboard; + bool mHasClipboardPos; + bool mHasClipboardSize; + bool mHasClipboardRot; + bool mHasClipboardParams; LLPointer mObject; LLPointer mRootObject; diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 6a0464c657..2f5be2b32e 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -79,6 +79,61 @@ static const S32 LOCAL_TRACKING_ID_COLUMN = 1; //static const char WHITE_IMAGE_NAME[] = "Blank Texture"; //static const char NO_IMAGE_NAME[] = "None"; + + +//static +bool get_is_library_texture(LLUUID image_id) +{ + if (gInventory.isObjectDescendentOf(image_id, gInventory.getLibraryRootFolderID()) + || image_id == LLUUID(gSavedSettings.getString("DefaultObjectTexture")) + || image_id == LLUUID(gSavedSettings.getString("UIImgWhiteUUID")) + || image_id == LLUUID(gSavedSettings.getString("UIImgInvisibleUUID")) + || image_id == LLUUID(SCULPT_DEFAULT_TEXTURE)) + { + return true; + } + return false; +} + +LLUUID get_copy_free_item_by_asset_id(LLUUID image_id) +{ + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(image_id); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + if (items.size()) + { + for (S32 i = 0; i < items.size(); i++) + { + LLViewerInventoryItem* itemp = items[i]; + if (itemp) + { + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowOperationBy(PERM_COPY, + gAgent.getID(), + gAgent.getGroupID())) + { + return itemp->getUUID(); + } + } + } + } + return LLUUID::null; +} + +bool get_can_copy_texture(LLUUID image_id) +{ + // User is allowed to copy a texture if: + // library asset or default texture, + // or copy perm asset exists in user's inventory + + return get_is_library_texture(image_id) || get_copy_free_item_by_asset_id(image_id).notNull(); +} + LLFloaterTexturePicker::LLFloaterTexturePicker( LLView* owner, LLUUID image_asset_id, diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index b2a34a37c4..2b2c5fa237 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -53,6 +53,16 @@ class LLViewerFetchedTexture; typedef boost::function drag_n_drop_callback; typedef boost::function texture_selected_callback; +// Helper functions for UI that work with picker +bool get_is_library_texture(LLUUID image_id); + +// texture picker works by asset ids since objects normaly do +// not retain inventory ids as result these functions are looking +// for textures in inventory by asset ids +// This search can be performance unfriendly and doesn't warranty +// that the texture is original source of asset +LLUUID get_copy_free_item_by_asset_id(LLUUID image_id); +bool get_can_copy_texture(LLUUID image_id); ////////////////////////////////////////////////////////////////////////////////////////// // LLTextureCtrl diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png new file mode 100644 index 0000000000..9a81c5f94b Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardMenu_Disabled.png differ diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png new file mode 100644 index 0000000000..88012cf8d1 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardMenu_Off.png differ diff --git a/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png b/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png new file mode 100644 index 0000000000..ab02e7d42d Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ClipboardMenu_Press.png differ diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index b7fa1e72f8..473b074213 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -441,6 +441,9 @@ with the same filename but different name + + + diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index afc6155585..0b2b1abeb9 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1436,7 +1436,7 @@ even though the user gets a free copy. height="0" layout="topleft" left_delta="0" - name="lod_tab_border" + name="object_horizontal" top_pad="10" width="95" /> Prim Type --> + + + width="125"> + Path Cut (begin/end) diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_generic.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_generic.xml new file mode 100644 index 0000000000..8e016e4a1c --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_generic.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml index c2763af603..3ea95b281f 100644 --- a/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_pos.xml @@ -3,19 +3,35 @@ layout="topleft" name="Copy Paste Position Menu"> + + + + - + + + + + - - + + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml index dcfb3faeca..06ce80f897 100644 --- a/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_rot.xml @@ -3,19 +3,35 @@ layout="topleft" name="Copy Paste Rotation Menu"> + + + + - + + + + + - - + + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml index 58d71b12d5..7082a0e65b 100644 --- a/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_size.xml @@ -3,19 +3,35 @@ layout="topleft" name="Copy Paste Size Menu"> + + + + - + + + + + - - + + -- cgit v1.2.3 From ef8d42a05ecd611c2bd16492c6727813bdcfd6bb Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 18 Jun 2020 00:13:38 +0300 Subject: SL-13359 #6 Fixed padding --- .../newview/skins/default/xui/en/floater_tools.xml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 0b2b1abeb9..d93ce2af1c 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1737,7 +1737,7 @@ even though the user gets a free copy. layout="topleft" left="125" name="text cut" - top_pad="7" + top_pad="5" width="150"> Path Cut (begin/end) @@ -1775,7 +1775,7 @@ even though the user gets a free copy. layout="topleft" left="125" name="text hollow" - top_pad="6" + top_pad="7" width="68"> Hollow @@ -1823,7 +1823,7 @@ even though the user gets a free copy. layout="topleft" left="125" name="Hollow Shape" - top_pad="4" + top_pad="7" width="150"> Hollow Shape @@ -1859,7 +1859,7 @@ even though the user gets a free copy. layout="topleft" left_delta="0" name="text twist" - top_pad="5" + top_pad="7" width="150"> Twist (begin/end) @@ -1901,12 +1901,12 @@ even though the user gets a free copy. layout="topleft" left="125" name="scale_taper" - top_pad="3" + top_pad="7" width="150"> Taper Top Shear @@ -1997,12 +1997,12 @@ even though the user gets a free copy. layout="topleft" left="125" name="advanced_cut" - top_pad="3" + top_pad="7" width="150"> Profile Cut (begin/end) Taper @@ -2104,7 +2104,7 @@ even though the user gets a free copy. layout="topleft" left="125" name="text radius delta" - top_pad="2" + top_pad="7" width="78"> Radius -- cgit v1.2.3 From d95f86c5931db5b025e0923071c9b3a08bb25301 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 18 Jun 2020 22:38:58 +0300 Subject: SL-13359 #7 Features tab --- indra/newview/llpanelobject.cpp | 43 ++- indra/newview/llpanelobject.h | 1 - indra/newview/llpanelvolume.cpp | 297 ++++++++++++++++++++- indra/newview/llpanelvolume.h | 13 + .../newview/skins/default/xui/en/floater_tools.xml | 43 ++- .../default/xui/en/menu_copy_paste_features.xml | 21 ++ .../default/xui/en/menu_copy_paste_generic.xml | 21 -- .../skins/default/xui/en/menu_copy_paste_light.xml | 21 ++ .../default/xui/en/menu_copy_paste_object.xml | 21 ++ 9 files changed, 428 insertions(+), 53 deletions(-) create mode 100644 indra/newview/skins/default/xui/en/menu_copy_paste_features.xml delete mode 100644 indra/newview/skins/default/xui/en/menu_copy_paste_generic.xml create mode 100644 indra/newview/skins/default/xui/en/menu_copy_paste_light.xml create mode 100644 indra/newview/skins/default/xui/en/menu_copy_paste_object.xml (limited to 'indra') diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index f1426ddf33..9bdc68b86a 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -159,7 +159,7 @@ BOOL LLPanelObject::postBuild() mComboBaseType = getChild("comboBaseType"); childSetCommitCallback("comboBaseType",onCommitParametric,this); - mMenuClipboardParams = getChild("clipboard_params_btn"); + mMenuClipboardParams = getChild("clipboard_obj_params_btn"); // Cut mLabelCut = getChild("text cut"); @@ -294,7 +294,6 @@ LLPanelObject::LLPanelObject() mHasClipboardPos(false), mHasClipboardSize(false), mHasClipboardRot(false), - mHasClipboardParams(false), mSizeChanged(FALSE) { mCommitCallbackRegistrar.add("PanelObject.menuDoToSelected", boost::bind(&LLPanelObject::menuDoToSelected, this, _2)); @@ -2109,7 +2108,7 @@ bool LLPanelObject::menuEnableItem(const LLSD& userdata) } else if (command == "params_paste") { - return mHasClipboardParams; + return mClipboardParams.isMap() && !mClipboardParams.emptyMap(); } // copy options else if (command == "psr_copy") @@ -2218,7 +2217,7 @@ void LLPanelObject::onPasteRot() void LLPanelObject::onCopyParams() { LLViewerObject* objectp = mObject; - if (!objectp) + if (!objectp || objectp->isMesh()) { return; } @@ -2226,42 +2225,34 @@ void LLPanelObject::onCopyParams() mClipboardParams.clear(); // Parametrics - if (!objectp->isMesh()) - { - LLVolumeParams params; - getVolumeParams(params); - mClipboardParams["volume_params"] = params.asLLSD(); - } + LLVolumeParams params; + getVolumeParams(params); + mClipboardParams["volume_params"] = params.asLLSD(); // Sculpted Prim if (objectp->getParameterEntryInUse(LLNetworkData::PARAMS_SCULPT)) { LLSculptParams *sculpt_params = (LLSculptParams *)objectp->getParameterEntry(LLNetworkData::PARAMS_SCULPT); - if (!objectp->isMesh()) + LLUUID texture_id = sculpt_params->getSculptTexture(); + if (get_can_copy_texture(texture_id)) { - LLUUID texture_id = sculpt_params->getSculptTexture(); - if (get_can_copy_texture(texture_id)) - { - LL_DEBUGS("FloaterTools") << "Recording texture" << LL_ENDL; - mClipboardParams["sculpt"]["id"] = texture_id; - } - else - { - mClipboardParams["sculpt"]["id"] = LLUUID(SCULPT_DEFAULT_TEXTURE); - } - - mClipboardParams["sculpt"]["type"] = sculpt_params->getSculptType(); + LL_DEBUGS("FloaterTools") << "Recording texture" << LL_ENDL; + mClipboardParams["sculpt"]["id"] = texture_id; + } + else + { + mClipboardParams["sculpt"]["id"] = LLUUID(SCULPT_DEFAULT_TEXTURE); } - } - mHasClipboardParams = TRUE; + mClipboardParams["sculpt"]["type"] = sculpt_params->getSculptType(); + } } void LLPanelObject::onPasteParams() { LLViewerObject* objectp = mObject; - if (!objectp || !mHasClipboardParams) + if (!objectp) { return; } diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index 5ea3d07699..515dd27c0a 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -191,7 +191,6 @@ protected: bool mHasClipboardPos; bool mHasClipboardSize; bool mHasClipboardRot; - bool mHasClipboardParams; LLPointer mObject; LLPointer mRootObject; diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 05d9346f89..a03e85daff 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -50,6 +50,7 @@ //#include "llfirstuse.h" #include "llfocusmgr.h" #include "llmanipscale.h" +#include "llmenubutton.h" #include "llpreviewscript.h" #include "llresmgr.h" #include "llselectmgr.h" @@ -166,6 +167,9 @@ BOOL LLPanelVolume::postBuild() mSpinPhysicsRestitution->setCommitCallback(boost::bind(&LLPanelVolume::sendPhysicsRestitution, this, _1, mSpinPhysicsRestitution)); } + mMenuClipboardFeatures = getChild("clipboard_features_params_btn"); + mMenuClipboardLight = getChild("clipboard_light_params_btn"); + std::map material_name_map; material_name_map["Stone"]= LLTrans::getString("Stone"); material_name_map["Metal"]= LLTrans::getString("Metal"); @@ -206,6 +210,8 @@ LLPanelVolume::LLPanelVolume() { setMouseOpaque(FALSE); + mCommitCallbackRegistrar.add("PanelVolume.menuDoToSelected", boost::bind(&LLPanelVolume::menuDoToSelected, this, _2)); + mEnableCallbackRegistrar.add("PanelVolume.menuEnable", boost::bind(&LLPanelVolume::menuEnableItem, this, _2)); } @@ -407,7 +413,6 @@ void LLPanelVolume::getState( ) gAgentAvatarp->updateMeshVisibility(); } } - // Flexible properties BOOL is_flexible = volobjp && volobjp->isFlexible(); @@ -562,6 +567,9 @@ void LLPanelVolume::getState( ) mObject = objectp; mRootObject = root_objectp; + + mMenuClipboardFeatures->setEnabled(editable && single_volume && volobjp); // Note: physics doesn't need to be limited by single volume + mMenuClipboardLight->setEnabled(editable && single_volume && volobjp); } // static @@ -662,6 +670,9 @@ void LLPanelVolume::clearCtrls() mSpinPhysicsRestitution->setEnabled(FALSE); mComboMaterial->setEnabled( FALSE ); + + mMenuClipboardFeatures->setEnabled(false); + mMenuClipboardLight->setEnabled(false); } // @@ -829,6 +840,290 @@ void LLPanelVolume::onLightSelectTexture(const LLSD& data) } } +void LLPanelVolume::onCopyFeatures() +{ + LLViewerObject* objectp = mObject; + if (!objectp) + { + return; + } + + LLSD clipboard; + + LLVOVolume *volobjp = NULL; + if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) + { + volobjp = (LLVOVolume *)objectp; + } + + // Flexi Prim + if (volobjp && volobjp->isFlexible()) + { + LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); + if (attributes) + { + clipboard["flex"]["lod"] = attributes->getSimulateLOD(); + clipboard["flex"]["gav"] = attributes->getGravity(); + clipboard["flex"]["ten"] = attributes->getTension(); + clipboard["flex"]["fri"] = attributes->getAirFriction(); + clipboard["flex"]["sen"] = attributes->getWindSensitivity(); + LLVector3 force = attributes->getUserForce(); + clipboard["flex"]["forx"] = force.mV[0]; + clipboard["flex"]["fory"] = force.mV[1]; + clipboard["flex"]["forz"] = force.mV[2]; + } + } + + // Physics + { + clipboard["physics"]["shape"] = objectp->getPhysicsShapeType(); + clipboard["physics"]["gravity"] = objectp->getPhysicsGravity(); + clipboard["physics"]["friction"] = objectp->getPhysicsFriction(); + clipboard["physics"]["density"] = objectp->getPhysicsDensity(); + clipboard["physics"]["restitution"] = objectp->getPhysicsRestitution(); + + U8 material_code = 0; + struct f : public LLSelectedTEGetFunctor + { + U8 get(LLViewerObject* object, S32 te) + { + return object->getMaterial(); + } + } func; + bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&func, material_code); + // This should always be true since material should be per object. + if (material_same) + { + clipboard["physics"]["material"] = material_code; + } + } + + mClipboardParams["features"] = clipboard; +} + +void LLPanelVolume::onPasteFeatures() +{ + LLViewerObject* objectp = mObject; + if (!objectp && mClipboardParams.has("features")) + { + return; + } + + LLSD &clipboard = mClipboardParams["features"]; + + LLVOVolume *volobjp = NULL; + if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) + { + volobjp = (LLVOVolume *)objectp; + } + + // Physics + bool is_root = objectp->isRoot(); + + // Not sure if phantom should go under physics, but doesn't fit elsewhere + BOOL is_phantom = clipboard["is_phantom"].asBoolean() && is_root; + LLSelectMgr::getInstance()->selectionUpdatePhantom(is_phantom); + + BOOL is_physical = clipboard["is_physical"].asBoolean() && is_root; + LLSelectMgr::getInstance()->selectionUpdatePhysics(is_physical); + + if (clipboard.has("physics")) + { + objectp->setPhysicsShapeType((U8)clipboard["physics"]["shape"].asInteger()); + U8 cur_material = objectp->getMaterial(); + U8 material = (U8)clipboard["physics"]["material"].asInteger() | (cur_material & ~LL_MCODE_MASK); + + objectp->setMaterial(material); + objectp->sendMaterialUpdate(); + objectp->setPhysicsGravity(clipboard["physics"]["gravity"].asReal()); + objectp->setPhysicsFriction(clipboard["physics"]["friction"].asReal()); + objectp->setPhysicsDensity(clipboard["physics"]["density"].asReal()); + objectp->setPhysicsRestitution(clipboard["physics"]["restitution"].asReal()); + objectp->updateFlags(TRUE); + } + + // Flexible + bool is_flexible = clipboard.has("flex"); + if (is_flexible && volobjp->canBeFlexible()) + { + LLVOVolume *volobjp = (LLVOVolume *)objectp; + BOOL update_shape = FALSE; + + // do before setParameterEntry or it will think that it is already flexi + update_shape = volobjp->setIsFlexible(is_flexible); + + if (objectp->getClickAction() == CLICK_ACTION_SIT) + { + objectp->setClickAction(CLICK_ACTION_NONE); + } + + LLFlexibleObjectData *attributes = (LLFlexibleObjectData *)objectp->getParameterEntry(LLNetworkData::PARAMS_FLEXIBLE); + if (attributes) + { + LLFlexibleObjectData new_attributes; + new_attributes = *attributes; + new_attributes.setSimulateLOD(clipboard["flex"]["lod"].asInteger()); + new_attributes.setGravity(clipboard["flex"]["gav"].asReal()); + new_attributes.setTension(clipboard["flex"]["ten"].asReal()); + new_attributes.setAirFriction(clipboard["flex"]["fri"].asReal()); + new_attributes.setWindSensitivity(clipboard["flex"]["sen"].asReal()); + F32 fx = (F32)clipboard["flex"]["forx"].asReal(); + F32 fy = (F32)clipboard["flex"]["fory"].asReal(); + F32 fz = (F32)clipboard["flex"]["forz"].asReal(); + LLVector3 force(fx, fy, fz); + new_attributes.setUserForce(force); + objectp->setParameterEntry(LLNetworkData::PARAMS_FLEXIBLE, new_attributes, true); + } + + if (update_shape) + { + mObject->sendShapeUpdate(); + LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom()); + } + } + else + { + LLVOVolume *volobjp = (LLVOVolume *)objectp; + if (volobjp->setIsFlexible(is_flexible)) + { + mObject->sendShapeUpdate(); + LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom()); + } + } +} + +void LLPanelVolume::onCopyLight() +{ + LLViewerObject* objectp = mObject; + if (!objectp) + { + return; + } + + LLSD clipboard; + + LLVOVolume *volobjp = NULL; + if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) + { + volobjp = (LLVOVolume *)objectp; + } + + // Light Source + if (volobjp && volobjp->getIsLight()) + { + clipboard["light"]["intensity"] = volobjp->getLightIntensity(); + clipboard["light"]["radius"] = volobjp->getLightRadius(); + clipboard["light"]["falloff"] = volobjp->getLightFalloff(); + LLColor3 color = volobjp->getLightSRGBColor(); + clipboard["light"]["r"] = color.mV[0]; + clipboard["light"]["g"] = color.mV[1]; + clipboard["light"]["b"] = color.mV[2]; + + // Spotlight + if (volobjp->isLightSpotlight()) + { + LLUUID id = volobjp->getLightTextureID(); + if (id.notNull() && get_can_copy_texture(id)) + { + clipboard["spot"]["id"] = id; + LLVector3 spot_params = volobjp->getSpotLightParams(); + clipboard["spot"]["fov"] = spot_params.mV[0]; + clipboard["spot"]["focus"] = spot_params.mV[1]; + clipboard["spot"]["ambiance"] = spot_params.mV[2]; + } + } + } + + mClipboardParams["light"] = clipboard; +} + +void LLPanelVolume::onPasteLight() +{ + LLViewerObject* objectp = mObject; + if (!objectp && mClipboardParams.has("light")) + { + return; + } + + LLSD &clipboard = mClipboardParams["light"]; + + LLVOVolume *volobjp = NULL; + if (objectp && (objectp->getPCode() == LL_PCODE_VOLUME)) + { + volobjp = (LLVOVolume *)objectp; + } + + // Light Source + if (volobjp) + { + if (clipboard.has("light")) + { + volobjp->setIsLight(TRUE); + volobjp->setLightIntensity((F32)clipboard["light"]["intensity"].asReal()); + volobjp->setLightRadius((F32)clipboard["light"]["radius"].asReal()); + volobjp->setLightFalloff((F32)clipboard["light"]["falloff"].asReal()); + F32 r = (F32)clipboard["light"]["r"].asReal(); + F32 g = (F32)clipboard["light"]["g"].asReal(); + F32 b = (F32)clipboard["light"]["b"].asReal(); + volobjp->setLightSRGBColor(LLColor3(r, g, b)); + } + else + { + volobjp->setIsLight(FALSE); + } + + if (clipboard.has("spot")) + { + volobjp->setLightTextureID(clipboard["spot"]["id"].asUUID()); + LLVector3 spot_params; + spot_params.mV[0] = (F32)clipboard["spot"]["fov"].asReal(); + spot_params.mV[1] = (F32)clipboard["spot"]["focus"].asReal(); + spot_params.mV[2] = (F32)clipboard["spot"]["ambiance"].asReal(); + volobjp->setSpotLightParams(spot_params); + } + } +} + +void LLPanelVolume::menuDoToSelected(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + // paste + if (command == "features_paste") + { + onPasteFeatures(); + } + else if (command == "light_paste") + { + onPasteLight(); + } + // copy + else if (command == "features_copy") + { + onCopyFeatures(); + } + else if (command == "light_copy") + { + onCopyLight(); + } +} + +bool LLPanelVolume::menuEnableItem(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + // paste options + if (command == "features_paste") + { + return mClipboardParams.has("features"); + } + else if (command == "light_paste") + { + return mClipboardParams.has("light"); + } + return false; +} + // static void LLPanelVolume::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) { diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index 66117316cf..1651108093 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -37,6 +37,7 @@ class LLCheckBoxCtrl; class LLTextBox; class LLUICtrl; class LLButton; +class LLMenuButton; class LLViewerObject; class LLComboBox; class LLColorSwatchCtrl; @@ -73,6 +74,13 @@ public: void onLightCancelTexture(const LLSD& data); void onLightSelectTexture(const LLSD& data); + void onCopyFeatures(); + void onPasteFeatures(); + void onCopyLight(); + void onPasteLight(); + + void menuDoToSelected(const LLSD& userdata); + bool menuEnableItem(const LLSD& userdata); protected: void getState(); @@ -120,6 +128,11 @@ protected: LLSpinCtrl* mSpinPhysicsFriction; LLSpinCtrl* mSpinPhysicsDensity; LLSpinCtrl* mSpinPhysicsRestitution; + + LLMenuButton* mMenuClipboardFeatures; + LLMenuButton* mMenuClipboardLight; + + LLSD mClipboardParams; }; #endif diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index d93ce2af1c..6e08be4866 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -1717,7 +1717,7 @@ even though the user gets a free copy. value="Sculpted" /> None Prim Convex Hull + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_generic.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_generic.xml deleted file mode 100644 index 8e016e4a1c..0000000000 --- a/indra/newview/skins/default/xui/en/menu_copy_paste_generic.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml new file mode 100644 index 0000000000..941efe7d01 --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_light.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml new file mode 100644 index 0000000000..8e016e4a1c --- /dev/null +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_object.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + -- cgit v1.2.3 From 15f02e2da231827a7cac18a2444c212efc8c1d1c Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 19 Jun 2020 17:34:57 +0300 Subject: SL-13359 #8 Reverted changes to texture tab This reverts commit 1e1707d532560583744bb877adfed11864f2db31. --- indra/newview/llpanelface.cpp | 659 +-------------------- indra/newview/llpanelface.h | 29 +- .../skins/default/xui/en/menu_texture_paste.xml | 70 --- .../skins/default/xui/en/panel_tools_texture.xml | 55 +- 4 files changed, 16 insertions(+), 797 deletions(-) delete mode 100644 indra/newview/skins/default/xui/en/menu_texture_paste.xml (limited to 'indra') diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 6e99a10b98..778cb77309 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -38,7 +38,6 @@ #include "llfontgl.h" // project includes -#include "llagent.h" // gAgent #include "llagentdata.h" #include "llbutton.h" #include "llcheckboxctrl.h" @@ -46,13 +45,9 @@ #include "llcombobox.h" #include "lldrawpoolbump.h" #include "llface.h" -#include "llinventoryfunctions.h" -#include "llinventorymodel.h" // gInventory -#include "llinventorymodelbackgroundfetch.h" #include "lllineeditor.h" #include "llmaterialmgr.h" #include "llmediaentry.h" -#include "llmenubutton.h" #include "llnotificationsutil.h" #include "llradiogroup.h" #include "llresmgr.h" @@ -305,18 +300,7 @@ BOOL LLPanelFace::postBuild() { mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow, this); } - - mBtnCopyFaces = getChild("copy_face_btn"); - if(mBtnCopyFaces) - { - mBtnCopyFaces->setCommitCallback(boost::bind(&LLPanelFace::onCopyFaces, this)); - } - mBtnPasteFaces = getChild("paste_face_btn"); - if (mBtnPasteFaces) - { - mBtnPasteFaces->setCommitCallback(boost::bind(&LLPanelFace::onPasteFaces, this)); - } - mBtnPasteMenu = getChild("paste_face_gear_btn"); + clearCtrls(); @@ -325,22 +309,9 @@ BOOL LLPanelFace::postBuild() LLPanelFace::LLPanelFace() : LLPanel(), - mIsAlpha(false), - mPasteColor(TRUE), - mPasteAlpha(TRUE), - mPasteGlow(TRUE), - mPasteDiffuse(TRUE), - mPasteNormal(TRUE), - mPasteSpecular(TRUE), - mPasteMapping(TRUE), - mPasteMedia(TRUE), - mPopulateAllTEs(TRUE) + mIsAlpha(false) { USE_TEXTURE = LLTrans::getString("use_texture"); - - mEnableCallbackRegistrar.add("BuildFace.PasteCheckItem", boost::bind(&LLPanelFace::pasteCheckMenuItem, this, _2)); - mCommitCallbackRegistrar.add("BuildFace.PasteDoToSelected", boost::bind(&LLPanelFace::pasteDoMenuItem, this, _2)); - mEnableCallbackRegistrar.add("BuildFace.PasteEnable", boost::bind(&LLPanelFace::pasteEnabletMenuItem, this, _2)); } @@ -1566,12 +1537,6 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) } } - S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); - BOOL single_volume = (selected_count == 1); - mBtnCopyFaces->setEnabled(editable && single_volume); - mBtnPasteFaces->setEnabled(editable && (mClipboard.size() > 0)); - mBtnPasteMenu->setEnabled(editable); - // Set variable values for numeric expressions LLCalc* calcp = LLCalc::getInstance(); calcp->setVar(LLCalc::TEX_U_SCALE, childGetValue("TexScaleU").asReal()); @@ -1772,6 +1737,8 @@ void LLPanelFace::updateVisibility() getChildView("bumpyRot")->setVisible(show_bumpiness); getChildView("bumpyOffsetU")->setVisible(show_bumpiness); getChildView("bumpyOffsetV")->setVisible(show_bumpiness); + + } // static @@ -2885,621 +2852,3 @@ void LLPanelFace::LLSelectedTE::getMaxDiffuseRepeats(F32& repeats, bool& identic } max_diff_repeats_func; identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_diff_repeats_func, repeats ); } - -static LLSD texture_clipboard; - -void LLPanelFace::onCopyFaces() -{ - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); - S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); - if( !objectp || !node - || objectp->getPCode() != LL_PCODE_VOLUME - || !objectp->permModify() - || objectp->isPermanentEnforced() - || selected_count > 1) - { - return; - } - - mClipboard.clear(); - std::map asset_item_map; - - S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); - mPopulateAllTEs = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()); - for (S32 te = 0; te < num_tes; ++te) - { - if (node->isTESelected(te)) - { - LLTextureEntry* tep = objectp->getTE(te); - if (tep) - { - LLSD te_data; - - // asLLSD() includes media - te_data["te"] = tep->asLLSD(); - te_data["te"]["glow"] = tep->getGlow(); - te_data["te"]["shiny"] = tep->getShiny(); - te_data["te"]["bumpmap"] = tep->getBumpmap(); - te_data["te"]["bumpshiny"] = tep->getBumpShiny(); - te_data["te"]["bumpfullbright"] = tep->getBumpShinyFullbright(); - - if (te_data["te"].has("imageid")) - { - LLUUID item_id; - LLUUID id = te_data["te"]["imageid"].asUUID(); - bool full_perm = get_is_library_texture(id) || (objectp->permCopy() && objectp->permTransfer() && objectp->permModify()); - - if (id.notNull() && !full_perm) - { - std::map::iterator iter = asset_item_map.find(id); - if (iter != asset_item_map.end()) - { - item_id = iter->second; - } - else - { - // What this does is simply searches inventory for item with same asset id, - // as result it is Hightly unreliable, leaves little control to user, borderline hack - // but there are little options to preserve permissions - multiple inventory - // items might reference same asset and inventory search is expensive. - item_id = get_copy_free_item_by_asset_id(id); - // record value to avoid repeating inventory search when possible - asset_item_map[id] = item_id; - } - } - - if (id.isNull() - || (!full_perm && item_id.isNull())) - { - if (!LLLocalBitmapMgr::getInstance()->isLocal(id)) - { - te_data["te"].erase("imageid"); - te_data["te"]["imageid"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); - } - te_data["te"]["itemfullperm"] = true; - } - else - { - te_data["te"]["itemfullperm"] = full_perm; - // If full permission object, texture is free to copy, - // but otherwise we need to check inventory and extract permissions - // - // Normally we care only about restrictions for current user and objects - // don't inherit any 'next owner' permissions from texture, so there is - // no need to record item id if full_perm==true - if (!full_perm && item_id.notNull()) - { - LLViewerInventoryItem* itemp = gInventory.getItem(item_id); - if (itemp) - { - LLPermissions item_permissions = itemp->getPermissions(); - if (item_permissions.allowOperationBy(PERM_COPY, - gAgent.getID(), - gAgent.getGroupID())) - { - te_data["te"]["imageitemid"] = item_id; - te_data["te"]["itemfullperm"] = itemp->getIsFullPerm(); - if (!itemp->isFinished()) - { - // needed for dropTextureAllFaces - LLInventoryModelBackgroundFetch::instance().start(item_id, false); - } - } - } - } - } - } - - LLMaterialPtr material_ptr = tep->getMaterialParams(); - if (!material_ptr.isNull()) - { - LLSD mat_data; - - mat_data["NormMap"] = material_ptr->getNormalID(); - mat_data["SpecMap"] = material_ptr->getSpecularID(); - - mat_data["NormRepX"] = material_ptr->getNormalRepeatX(); - mat_data["NormRepY"] = material_ptr->getNormalRepeatY(); - mat_data["NormOffX"] = material_ptr->getNormalOffsetX(); - mat_data["NormOffY"] = material_ptr->getNormalOffsetY(); - mat_data["NormRot"] = material_ptr->getNormalRotation(); - - mat_data["SpecRepX"] = material_ptr->getSpecularRepeatX(); - mat_data["SpecRepY"] = material_ptr->getSpecularRepeatY(); - mat_data["SpecOffX"] = material_ptr->getSpecularOffsetX(); - mat_data["SpecOffY"] = material_ptr->getSpecularOffsetY(); - mat_data["SpecRot"] = material_ptr->getSpecularRotation(); - - mat_data["SpecColor"] = material_ptr->getSpecularLightColor().getValue(); - mat_data["SpecExp"] = material_ptr->getSpecularLightExponent(); - mat_data["EnvIntensity"] = material_ptr->getEnvironmentIntensity(); - mat_data["AlphaMaskCutoff"] = material_ptr->getAlphaMaskCutoff(); - mat_data["DiffuseAlphaMode"] = material_ptr->getDiffuseAlphaMode(); - - // Replace no-copy textures, destination texture will get used instead if available - if (mat_data.has("NormMap")) - { - LLUUID id = mat_data["NormMap"].asUUID(); - if (id.notNull() && !get_can_copy_texture(id)) - { - mat_data["NormMap"] = LLUUID(gSavedSettings.getString( "DefaultObjectTexture" )); - mat_data["NormMapNoCopy"] = true; - } - - } - if (mat_data.has("SpecMap")) - { - LLUUID id = mat_data["SpecMap"].asUUID(); - if (id.notNull() && !get_can_copy_texture(id)) - { - mat_data["SpecMap"] = LLUUID(gSavedSettings.getString( "DefaultObjectTexture" )); - mat_data["SpecMapNoCopy"] = true; - } - - } - - te_data["material"] = mat_data; - } - - mClipboard.append(te_data); - } - } - } -} - -void LLPanelFace::pasteFace(LLViewerObject* objectp, S32 te) -{ - LLSD te_data; - if ((mClipboard.size() == 1) && mPopulateAllTEs) - { - te_data = *(mClipboard.beginArray()); - } - else if (mClipboard[te]) - { - te_data = mClipboard[te]; - } - else - { - return; - } - - LLTextureEntry* tep = objectp->getTE(te); - if (tep) - { - if (te_data.has("te")) - { - // Texture - bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); - if (mPasteDiffuse && te_data["te"].has("imageid")) - { - const LLUUID& imageid = te_data["te"]["imageid"].asUUID(); //texture or asset id - LLViewerInventoryItem* itemp_res = NULL; - - if (te_data["te"].has("imageitemid")) - { - LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); - if (item_id.notNull()) - { - LLViewerInventoryItem* itemp = gInventory.getItem(item_id); - if (itemp && itemp->isFinished()) - { - // dropTextureAllFaces will fail if incomplete - itemp_res = itemp; - } - } - } - - // for case when item got removed from inventory after we pressed 'copy' - if (!itemp_res && !full_perm) - { - // todo: fix this, we are often searching same tuxter multiple times (equal to number of faces) - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - LLAssetIDMatches asset_id_matches(imageid); - gInventory.collectDescendentsIf(LLUUID::null, - cats, - items, - LLInventoryModel::INCLUDE_TRASH, - asset_id_matches); - - // Extremely unreliable and perfomance unfriendly. - // But we need this to check permissions and it is how texture control finds items - for (S32 i = 0; i < items.size(); i++) - { - LLViewerInventoryItem* itemp = items[i]; - if (itemp && itemp->isFinished()) - { - // dropTextureAllFaces will fail if incomplete - LLPermissions item_permissions = itemp->getPermissions(); - if (item_permissions.allowOperationBy(PERM_COPY, - gAgent.getID(), - gAgent.getGroupID())) - { - itemp_res = itemp; - break; // first match - } - } - } - } - - if (itemp_res) - { - if (te == -1) // all faces - { - LLToolDragAndDrop::dropTextureAllFaces(objectp, - itemp_res, - LLToolDragAndDrop::SOURCE_AGENT, - LLUUID::null); - } - else // one face - { - LLToolDragAndDrop::dropTextureOneFace(objectp, - te, - itemp_res, - LLToolDragAndDrop::SOURCE_AGENT, - LLUUID::null); - } - } - // not an inventory item or no complete items - else if (full_perm) - { - // Either library, local or existed as fullperm when user made a copy - LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(imageid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); - objectp->setTEImage(U8(te), image); - } - } - - // Color / Alpha - if ((mPasteColor || mPasteAlpha) && te_data["te"].has("colors")) - { - LLColor4 color = tep->getColor(); - - LLColor4 clip_color; - clip_color.setValue(te_data["te"]["colors"]); - - // Color - if (mPasteColor) - { - color.mV[VRED] = clip_color.mV[VRED]; - color.mV[VGREEN] = clip_color.mV[VGREEN]; - color.mV[VBLUE] = clip_color.mV[VBLUE]; - } - - // Alpha - if (mPasteAlpha) - { - color.mV[VALPHA] = clip_color.mV[VALPHA]; - } - - objectp->setTEColor(te, color); - } - - if (mPasteColor && te_data["te"].has("fullbright")) - { - objectp->setTEFullbright(te, te_data["te"]["fullbright"].asInteger()); - } - - - // Glow - if (mPasteGlow && te_data["te"].has("glow")) - { - objectp->setTEGlow(te, (F32)te_data["te"]["glow"].asReal()); - } - - if (mPasteNormal && te_data["te"].has("bumpmap")) - { - objectp->setTEBumpmap(te, (U8)te_data["te"]["bumpmap"].asInteger()); - } - if (mPasteSpecular && te_data["te"].has("bumpshiny")) - { - objectp->setTEBumpShiny(te, (U8)te_data["te"]["bumpshiny"].asInteger()); - } - if (mPasteSpecular && te_data["te"].has("bumpfullbright")) - { - objectp->setTEBumpShinyFullbright(te, (U8)te_data["te"]["bumpfullbright"].asInteger()); - } - - // Texture map - if (mPasteMapping) - { - if (te_data["te"].has("scales") && te_data["te"].has("scalet")) - { - objectp->setTEScale(te, (F32)te_data["te"]["scales"].asReal(), (F32)te_data["te"]["scalet"].asReal()); - } - if (te_data["te"].has("offsets") && te_data["te"].has("offsett")) - { - objectp->setTEOffset(te, (F32)te_data["te"]["offsets"].asReal(), (F32)te_data["te"]["offsett"].asReal()); - } - if (te_data["te"].has("imagerot")) - { - objectp->setTERotation(te, (F32)te_data["te"]["imagerot"].asReal()); - } - } - - // Media - if (mPasteMedia && te_data["te"].has("media_flags")) - { - U8 media_flags = te_data["te"]["media_flags"].asInteger(); - objectp->setTEMediaFlags(te, media_flags); - LLVOVolume *vo = dynamic_cast(objectp); - if (vo && te_data["te"].has(LLTextureEntry::TEXTURE_MEDIA_DATA_KEY)) - { - vo->syncMediaData(te, te_data["te"][LLTextureEntry::TEXTURE_MEDIA_DATA_KEY], true/*merge*/, true/*ignore_agent*/); - } - } - else - { - // Keep media flags on destination unchanged - } - } - - if (te_data.has("material")) - { - LLUUID object_id = objectp->getID(); - - LLSelectedTEMaterial::setAlphaMaskCutoff(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id); - - if (mPasteNormal) - { - // Replace placeholders with target's - if (te_data["material"].has("NormMapNoCopy")) - { - LLMaterialPtr material = tep->getMaterialParams(); - if (material.notNull()) - { - LLUUID id = material->getNormalID(); - if (id.notNull()) - { - te_data["material"]["NormMap"] = id; - } - } - } - LLSelectedTEMaterial::setNormalID(this, te_data["material"]["NormMap"].asUUID(), te, object_id); - LLSelectedTEMaterial::setNormalRepeatX(this, (F32)te_data["material"]["NormRepX"].asReal(), te, object_id); - LLSelectedTEMaterial::setNormalRepeatY(this, (F32)te_data["material"]["NormRepY"].asReal(), te, object_id); - LLSelectedTEMaterial::setNormalOffsetX(this, (F32)te_data["material"]["NormOffX"].asReal(), te, object_id); - LLSelectedTEMaterial::setNormalOffsetY(this, (F32)te_data["material"]["NormOffY"].asReal(), te, object_id); - LLSelectedTEMaterial::setNormalRotation(this, (F32)te_data["material"]["NormRot"].asReal(), te, object_id); - } - - if (mPasteSpecular) - { - // Replace placeholders with target's - if (te_data["material"].has("SpecMapNoCopy")) - { - LLMaterialPtr material = tep->getMaterialParams(); - if (material.notNull()) - { - LLUUID id = material->getSpecularID(); - if (id.notNull()) - { - te_data["material"]["SpecMap"] = id; - } - } - } - LLSelectedTEMaterial::setSpecularID(this, te_data["material"]["SpecMap"].asUUID(), te, object_id); - LLSelectedTEMaterial::setSpecularRepeatX(this, (F32)te_data["material"]["SpecRepX"].asReal(), te, object_id); - LLSelectedTEMaterial::setSpecularRepeatY(this, (F32)te_data["material"]["SpecRepY"].asReal(), te, object_id); - LLSelectedTEMaterial::setSpecularOffsetX(this, (F32)te_data["material"]["SpecOffX"].asReal(), te, object_id); - LLSelectedTEMaterial::setSpecularOffsetY(this, (F32)te_data["material"]["SpecOffY"].asReal(), te, object_id); - LLSelectedTEMaterial::setSpecularRotation(this, (F32)te_data["material"]["SpecRot"].asReal(), te, object_id); - LLColor4 spec_color(te_data["material"]["SpecColor"]); - LLSelectedTEMaterial::setSpecularLightColor(this, spec_color, te); - LLSelectedTEMaterial::setSpecularLightExponent(this, (U8)te_data["material"]["SpecExp"].asInteger(), te, object_id); - LLSelectedTEMaterial::setEnvironmentIntensity(this, (U8)te_data["material"]["EnvIntensity"].asInteger(), te, object_id); - LLSelectedTEMaterial::setDiffuseAlphaMode(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id); - if (te_data.has("te") && te_data["te"].has("shiny")) - { - objectp->setTEShiny(te, (U8)te_data["te"]["shiny"].asInteger()); - } - } - } - } -} - -struct LLPanelFacePasteTexFunctor : public LLSelectedTEFunctor -{ - LLPanelFacePasteTexFunctor(LLPanelFace* panel) : - mPanelFace(panel){} - - virtual bool apply(LLViewerObject* objectp, S32 te) - { - mPanelFace->pasteFace(objectp, te); - return true; - } -private: - LLPanelFace *mPanelFace; -}; - -struct LLPanelFaceUpdateFunctor : public LLSelectedObjectFunctor -{ - LLPanelFaceUpdateFunctor(bool update_media) : mUpdateMedia(update_media) {} - virtual bool apply(LLViewerObject* object) - { - object->sendTEUpdate(); - if (mUpdateMedia) - { - LLVOVolume *vo = dynamic_cast(object); - if (vo && vo->hasMedia()) - { - vo->sendMediaDataUpdate(); - } - } - return true; - } -private: - bool mUpdateMedia; -}; - -struct LLPanelFaceNavigateHomeFunctor : public LLSelectedTEFunctor -{ - virtual bool apply(LLViewerObject* objectp, S32 te) - { - if (objectp && objectp->getTE(te)) - { - LLTextureEntry* tep = objectp->getTE(te); - const LLMediaEntry *media_data = tep->getMediaData(); - if (media_data) - { - if (media_data->getCurrentURL().empty() && media_data->getAutoPlay()) - { - viewer_media_t media_impl = - LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep->getMediaData()->getMediaID()); - if (media_impl) - { - media_impl->navigateHome(); - } - } - } - } - return true; - } -}; - -void LLPanelFace::onPasteFaces() -{ - LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); - - LLPanelFacePasteTexFunctor paste_func(this); - selected_objects->applyToTEs(&paste_func); - - LLPanelFaceUpdateFunctor sendfunc(mPasteMedia); - selected_objects->applyToObjects(&sendfunc); - - if (mPasteMedia) - { - LLPanelFaceNavigateHomeFunctor navigate_home_func; - selected_objects->applyToTEs(&navigate_home_func); - } -} - -bool LLPanelFace::pasteCheckMenuItem(const LLSD& userdata) -{ - std::string command = userdata.asString(); - - if ("Color" == command) - { - return mPasteColor; - } - if ("Transparency" == command) - { - return mPasteAlpha; - } - if ("Glow" == command) - { - return mPasteGlow; - } - if ("Diffuse" == command) - { - return mPasteDiffuse; - } - if ("Normal" == command) - { - return mPasteNormal; - } - if ("Specular" == command) - { - return mPasteSpecular; - } - if ("Mapping" == command) - { - return mPasteMapping; - } - if ("Media" == command) - { - return mPasteMedia; - } - - return false; -} - -void LLPanelFace::pasteDoMenuItem(const LLSD& userdata) -{ - std::string command = userdata.asString(); - - if ("Color" == command) - { - mPasteColor = !mPasteColor; - } - if ("Transparency" == command) - { - mPasteAlpha = !mPasteAlpha; - } - if ("Glow" == command) - { - mPasteGlow = !mPasteGlow; - } - if ("Diffuse" == command) - { - mPasteDiffuse = !mPasteDiffuse; - } - if ("Normal" == command) - { - mPasteNormal = !mPasteNormal; - } - if ("Specular" == command) - { - mPasteSpecular = !mPasteSpecular; - } - if ("Mapping" == command) - { - mPasteMapping = !mPasteMapping; - } - if ("Media" == command) - { - mPasteMedia = !mPasteMedia; - } -} - -bool LLPanelFace::pasteEnabletMenuItem(const LLSD& userdata) -{ - std::string command = userdata.asString(); - - // Keep at least one option enabled - S32 num_enabled = mPasteColor - + mPasteAlpha - + mPasteGlow - + mPasteDiffuse - + mPasteNormal - + mPasteSpecular - + mPasteMapping - + mPasteMedia; - if ( num_enabled == 1) - { - if ("Color" == command && mPasteColor) - { - return false; - } - if ("Transparency" == command && mPasteAlpha) - { - return false; - } - if ("Glow" == command && mPasteGlow) - { - return false; - } - if ("Diffuse" == command && mPasteDiffuse) - { - return false; - } - if ("Normal" == command && mPasteNormal) - { - return false; - } - if ("Specular" == command && mPasteSpecular) - { - return false; - } - if ("Mapping" == command && mPasteMapping) - { - return false; - } - if ("Media" == command && mPasteMedia) - { - return false; - } - } - - return true; -} diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 770f10e2ee..2d57d89a44 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -47,7 +47,6 @@ class LLUICtrl; class LLViewerObject; class LLFloater; class LLMaterialID; -class LLMenuButton; // Represents an edit for use in replicating the op across one or more materials in the selection set. // @@ -114,8 +113,6 @@ public: LLRender::eTexIndex getTextureChannelToEdit(); - void pasteFace(LLViewerObject* object, S32 te); - protected: void getState(); @@ -208,14 +205,10 @@ protected: static void onClickAutoFix(void*); static void onAlignTexture(void*); - void onCopyFaces(); - void onPasteFaces(); - bool pasteCheckMenuItem(const LLSD& userdata); - void pasteDoMenuItem(const LLSD& userdata); - bool pasteEnabletMenuItem(const LLSD& userdata); - static F32 valueGlow(LLViewerObject* object, S32 face); + + private: bool isAlpha() { return mIsAlpha; } @@ -241,22 +234,6 @@ private: F32 getCurrentShinyOffsetU(); F32 getCurrentShinyOffsetV(); - LLButton *mBtnCopyFaces; - LLButton *mBtnPasteFaces; - LLMenuButton *mBtnPasteMenu; - - LLSD mClipboard; - BOOL mPasteColor; - BOOL mPasteAlpha; - BOOL mPasteGlow; - BOOL mPasteDiffuse; - BOOL mPasteNormal; - BOOL mPasteSpecular; - BOOL mPasteMapping; - BOOL mPasteMedia; - - BOOL mPopulateAllTEs; - // Update visibility of controls to match current UI mode // (e.g. materials vs media editing) // @@ -520,8 +497,6 @@ public: DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID); DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID); DEF_EDIT_MAT_STATE(LLColor4U, const LLColor4U&,setSpecularLightColor); - - DEF_EDIT_MAT_STATE(LLSD, const LLSD&, fromLLSD); }; class LLSelectedTE diff --git a/indra/newview/skins/default/xui/en/menu_texture_paste.xml b/indra/newview/skins/default/xui/en/menu_texture_paste.xml deleted file mode 100644 index be6535b989..0000000000 --- a/indra/newview/skins/default/xui/en/menu_texture_paste.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml index 1819106970..438fb1e8ed 100644 --- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml @@ -43,7 +43,7 @@ follows="left|top" height="10" layout="topleft" - left_pad="10" + left_pad="15" name="color trans" text_readonly_color="LabelDisabledColor" top="6" @@ -68,7 +68,7 @@ follows="left|top" height="10" layout="topleft" - left_pad="13" + left_pad="15" name="glow label" text_readonly_color="LabelDisabledColor" top="6" @@ -84,7 +84,7 @@ left_delta="0" name="glow" top_pad="4" - width="50" /> + width="80" /> - - - - + Date: Fri, 19 Jun 2020 22:18:31 +0300 Subject: SL-13359 #9 Texture tab --- indra/newview/llpanelface.cpp | 633 ++++++++++++++++++++- indra/newview/llpanelface.h | 20 +- indra/newview/llpanelvolume.cpp | 3 - .../newview/skins/default/xui/en/floater_tools.xml | 6 +- .../skins/default/xui/en/menu_copy_paste_color.xml | 21 + .../default/xui/en/menu_copy_paste_features.xml | 2 +- .../skins/default/xui/en/menu_copy_paste_light.xml | 2 +- .../default/xui/en/menu_copy_paste_object.xml | 2 +- .../default/xui/en/menu_copy_paste_texture.xml | 21 + .../skins/default/xui/en/panel_tools_texture.xml | 51 +- 10 files changed, 740 insertions(+), 21 deletions(-) create mode 100644 indra/newview/skins/default/xui/en/menu_copy_paste_color.xml create mode 100644 indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml (limited to 'indra') diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 778cb77309..6b5d14300f 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -45,9 +45,11 @@ #include "llcombobox.h" #include "lldrawpoolbump.h" #include "llface.h" +#include "llinventorymodel.h" // gInventory #include "lllineeditor.h" #include "llmaterialmgr.h" #include "llmediaentry.h" +#include "llmenubutton.h" #include "llnotificationsutil.h" #include "llradiogroup.h" #include "llresmgr.h" @@ -300,7 +302,9 @@ BOOL LLPanelFace::postBuild() { mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow, this); } - + + mMenuClipboardColor = getChild("clipboard_color_params_btn"); + mMenuClipboardTexture = getChild("clipboard_texture_params_btn"); clearCtrls(); @@ -311,7 +315,9 @@ LLPanelFace::LLPanelFace() : LLPanel(), mIsAlpha(false) { - USE_TEXTURE = LLTrans::getString("use_texture"); + USE_TEXTURE = LLTrans::getString("use_texture"); + mCommitCallbackRegistrar.add("PanelFace.menuDoToSelected", boost::bind(&LLPanelFace::menuDoToSelected, this, _2)); + mEnableCallbackRegistrar.add("PanelFace.menuEnable", boost::bind(&LLPanelFace::menuEnableItem, this, _2)); } @@ -1536,6 +1542,10 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/) } } } + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + BOOL single_volume = (selected_count == 1); + mMenuClipboardColor->setEnabled(editable && single_volume); + mMenuClipboardTexture->setEnabled(editable && single_volume); // Set variable values for numeric expressions LLCalc* calcp = LLCalc::getInstance(); @@ -2566,6 +2576,625 @@ void LLPanelFace::onAlignTexture(void* userdata) self->alignTestureLayer(); } +void LLPanelFace::onCopyColor() +{ + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1) + { + return; + } + + if (mClipboardParams.has("color")) + { + mClipboardParams["color"].clear(); + } + else + { + mClipboardParams["color"] = LLSD::emptyArray(); + } + + std::map asset_item_map; + + // a way to resolve situations where source and target have different amount of faces + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + mClipboardParams["color_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()); + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + LLSD te_data; + + // asLLSD() includes media + te_data["te"] = tep->asLLSD(); // Note: includes a lot more than just color/alpha/glow + + mClipboardParams["color"].append(te_data); + } + } + } +} + +void LLPanelFace::onPasteColor(LLViewerObject* objectp, S32 te) +{ + if (!mClipboardParams.has("color")) + { + return; + } + LLSD te_data; + LLSD &clipboard = mClipboardParams["color"]; // array + if ((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean()) + { + te_data = *(clipboard.beginArray()); + } + else if (clipboard[te]) + { + te_data = clipboard[te]; + } + else + { + return; + } + + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + if (te_data.has("te")) + { + // Color / Alpha + if (te_data["te"].has("colors")) + { + LLColor4 color = tep->getColor(); + + LLColor4 clip_color; + clip_color.setValue(te_data["te"]["colors"]); + + // Color + color.mV[VRED] = clip_color.mV[VRED]; + color.mV[VGREEN] = clip_color.mV[VGREEN]; + color.mV[VBLUE] = clip_color.mV[VBLUE]; + + // Alpha + color.mV[VALPHA] = clip_color.mV[VALPHA]; + + objectp->setTEColor(te, color); + } + + // Color/fullbright + if (te_data["te"].has("fullbright")) + { + objectp->setTEFullbright(te, te_data["te"]["fullbright"].asInteger()); + } + + // Glow + if (te_data["te"].has("glow")) + { + objectp->setTEGlow(te, (F32)te_data["te"]["glow"].asReal()); + } + } + } +} + +void LLPanelFace::onCopyTexture() +{ + + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1) + { + return; + } + + if (mClipboardParams.has("texture")) + { + mClipboardParams["texture"].clear(); + } + else + { + mClipboardParams["texture"] = LLSD::emptyArray(); + } + + std::map asset_item_map; + + // a way to resolve situations where source and target have different amount of faces + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + mClipboardParams["texture_all_tes"] = (num_tes != 1) || (LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool()); + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + LLSD te_data; + + // asLLSD() includes media + te_data["te"] = tep->asLLSD(); + te_data["te"]["shiny"] = tep->getShiny(); + te_data["te"]["bumpmap"] = tep->getBumpmap(); + te_data["te"]["bumpshiny"] = tep->getBumpShiny(); + te_data["te"]["bumpfullbright"] = tep->getBumpShinyFullbright(); + + if (te_data["te"].has("imageid")) + { + LLUUID item_id; + LLUUID id = te_data["te"]["imageid"].asUUID(); + bool full_perm = get_is_library_texture(id) || (objectp->permCopy() && objectp->permTransfer() && objectp->permModify()); + + if (id.notNull() && !full_perm) + { + std::map::iterator iter = asset_item_map.find(id); + if (iter != asset_item_map.end()) + { + item_id = iter->second; + } + else + { + // What this does is simply searches inventory for item with same asset id, + // as result it is Hightly unreliable, leaves little control to user, borderline hack + // but there are little options to preserve permissions - multiple inventory + // items might reference same asset and inventory search is expensive. + item_id = get_copy_free_item_by_asset_id(id); + // record value to avoid repeating inventory search when possible + asset_item_map[id] = item_id; + } + } + + if (id.isNull() + || (!full_perm && item_id.isNull())) + { + if (!LLLocalBitmapMgr::getInstance()->isLocal(id)) + { + te_data["te"].erase("imageid"); + te_data["te"]["imageid"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); + } + te_data["te"]["itemfullperm"] = true; + } + else + { + te_data["te"]["itemfullperm"] = full_perm; + // If full permission object, texture is free to copy, + // but otherwise we need to check inventory and extract permissions + // + // Normally we care only about restrictions for current user and objects + // don't inherit any 'next owner' permissions from texture, so there is + // no need to record item id if full_perm==true + if (!full_perm && item_id.notNull()) + { + //Todo: + // also same thing probably needs to be present in object and volume panels for sculpt and projector images + /* + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (itemp) + { + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowOperationBy(PERM_COPY, + gAgent.getID(), + gAgent.getGroupID())) + { + te_data["te"]["imageitemid"] = item_id; + te_data["te"]["itemfullperm"] = itemp->getIsFullPerm(); + if (!itemp->isFinished()) + { + // needed for dropTextureAllFaces + LLInventoryModelBackgroundFetch::instance().start(item_id, false); + } + } + } + */ + } + } + } + + LLMaterialPtr material_ptr = tep->getMaterialParams(); + if (!material_ptr.isNull()) + { + LLSD mat_data; + + mat_data["NormMap"] = material_ptr->getNormalID(); + mat_data["SpecMap"] = material_ptr->getSpecularID(); + + mat_data["NormRepX"] = material_ptr->getNormalRepeatX(); + mat_data["NormRepY"] = material_ptr->getNormalRepeatY(); + mat_data["NormOffX"] = material_ptr->getNormalOffsetX(); + mat_data["NormOffY"] = material_ptr->getNormalOffsetY(); + mat_data["NormRot"] = material_ptr->getNormalRotation(); + + mat_data["SpecRepX"] = material_ptr->getSpecularRepeatX(); + mat_data["SpecRepY"] = material_ptr->getSpecularRepeatY(); + mat_data["SpecOffX"] = material_ptr->getSpecularOffsetX(); + mat_data["SpecOffY"] = material_ptr->getSpecularOffsetY(); + mat_data["SpecRot"] = material_ptr->getSpecularRotation(); + + mat_data["SpecColor"] = material_ptr->getSpecularLightColor().getValue(); + mat_data["SpecExp"] = material_ptr->getSpecularLightExponent(); + mat_data["EnvIntensity"] = material_ptr->getEnvironmentIntensity(); + mat_data["AlphaMaskCutoff"] = material_ptr->getAlphaMaskCutoff(); + mat_data["DiffuseAlphaMode"] = material_ptr->getDiffuseAlphaMode(); + + // Replace no-copy textures, destination texture will get used instead if available + if (mat_data.has("NormMap")) + { + LLUUID id = mat_data["NormMap"].asUUID(); + if (id.notNull() && !get_can_copy_texture(id)) + { + mat_data["NormMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); + mat_data["NormMapNoCopy"] = true; + } + + } + if (mat_data.has("SpecMap")) + { + LLUUID id = mat_data["SpecMap"].asUUID(); + if (id.notNull() && !get_can_copy_texture(id)) + { + mat_data["SpecMap"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); + mat_data["SpecMapNoCopy"] = true; + } + + } + + te_data["material"] = mat_data; + } + + mClipboardParams["texture"].append(te_data); + } + } + } +} + +void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) +{ + if (!mClipboardParams.has("texture")) + { + return; + } + LLSD te_data; + LLSD &clipboard = mClipboardParams["texture"]; // array + if ((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean()) + { + te_data = *(clipboard.beginArray()); + } + else if (clipboard[te]) + { + te_data = clipboard[te]; + } + else + { + return; + } + + LLTextureEntry* tep = objectp->getTE(te); + if (tep) + { + if (te_data.has("te")) + { + // Texture + bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); + if (te_data["te"].has("imageid")) + { + const LLUUID& imageid = te_data["te"]["imageid"].asUUID(); //texture or asset id + LLViewerInventoryItem* itemp_res = NULL; + + if (te_data["te"].has("imageitemid")) + { + LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); + if (item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (itemp && itemp->isFinished()) + { + // dropTextureAllFaces will fail if incomplete + itemp_res = itemp; + } + } + } + //todo: + // for case when item got removed from inventory after we pressed 'copy' + /*if (!itemp_res && !full_perm) + { + // todo: fix this, we are often searching same tuxter multiple times (equal to number of faces) + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(imageid); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + // Extremely unreliable and perfomance unfriendly. + // But we need this to check permissions and it is how texture control finds items + for (S32 i = 0; i < items.size(); i++) + { + LLViewerInventoryItem* itemp = items[i]; + if (itemp && itemp->isFinished()) + { + // dropTextureAllFaces will fail if incomplete + LLPermissions item_permissions = itemp->getPermissions(); + if (item_permissions.allowOperationBy(PERM_COPY, + gAgent.getID(), + gAgent.getGroupID())) + { + itemp_res = itemp; + break; // first match + } + } + } + }*/ + + if (itemp_res) + { + if (te == -1) // all faces + { + LLToolDragAndDrop::dropTextureAllFaces(objectp, + itemp_res, + LLToolDragAndDrop::SOURCE_AGENT, + LLUUID::null); + } + else // one face + { + LLToolDragAndDrop::dropTextureOneFace(objectp, + te, + itemp_res, + LLToolDragAndDrop::SOURCE_AGENT, + LLUUID::null); + } + } + // not an inventory item or no complete items + else if (full_perm) + { + // Either library, local or existed as fullperm when user made a copy + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(imageid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE); + objectp->setTEImage(U8(te), image); + } + } + + if (te_data["te"].has("bumpmap")) + { + objectp->setTEBumpmap(te, (U8)te_data["te"]["bumpmap"].asInteger()); + } + if (te_data["te"].has("bumpshiny")) + { + objectp->setTEBumpShiny(te, (U8)te_data["te"]["bumpshiny"].asInteger()); + } + if (te_data["te"].has("bumpfullbright")) + { + objectp->setTEBumpShinyFullbright(te, (U8)te_data["te"]["bumpfullbright"].asInteger()); + } + + // Texture map + if (te_data["te"].has("scales") && te_data["te"].has("scalet")) + { + objectp->setTEScale(te, (F32)te_data["te"]["scales"].asReal(), (F32)te_data["te"]["scalet"].asReal()); + } + if (te_data["te"].has("offsets") && te_data["te"].has("offsett")) + { + objectp->setTEOffset(te, (F32)te_data["te"]["offsets"].asReal(), (F32)te_data["te"]["offsett"].asReal()); + } + if (te_data["te"].has("imagerot")) + { + objectp->setTERotation(te, (F32)te_data["te"]["imagerot"].asReal()); + } + + // Media + if (te_data["te"].has("media_flags")) + { + U8 media_flags = te_data["te"]["media_flags"].asInteger(); + objectp->setTEMediaFlags(te, media_flags); + LLVOVolume *vo = dynamic_cast(objectp); + if (vo && te_data["te"].has(LLTextureEntry::TEXTURE_MEDIA_DATA_KEY)) + { + vo->syncMediaData(te, te_data["te"][LLTextureEntry::TEXTURE_MEDIA_DATA_KEY], true/*merge*/, true/*ignore_agent*/); + } + } + else + { + // Keep media flags on destination unchanged + } + } + + if (te_data.has("material")) + { + LLUUID object_id = objectp->getID(); + + LLSelectedTEMaterial::setAlphaMaskCutoff(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id); + + // Normal + // Replace placeholders with target's + if (te_data["material"].has("NormMapNoCopy")) + { + LLMaterialPtr material = tep->getMaterialParams(); + if (material.notNull()) + { + LLUUID id = material->getNormalID(); + if (id.notNull()) + { + te_data["material"]["NormMap"] = id; + } + } + } + LLSelectedTEMaterial::setNormalID(this, te_data["material"]["NormMap"].asUUID(), te, object_id); + LLSelectedTEMaterial::setNormalRepeatX(this, (F32)te_data["material"]["NormRepX"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalRepeatY(this, (F32)te_data["material"]["NormRepY"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalOffsetX(this, (F32)te_data["material"]["NormOffX"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalOffsetY(this, (F32)te_data["material"]["NormOffY"].asReal(), te, object_id); + LLSelectedTEMaterial::setNormalRotation(this, (F32)te_data["material"]["NormRot"].asReal(), te, object_id); + + // Specular + // Replace placeholders with target's + if (te_data["material"].has("SpecMapNoCopy")) + { + LLMaterialPtr material = tep->getMaterialParams(); + if (material.notNull()) + { + LLUUID id = material->getSpecularID(); + if (id.notNull()) + { + te_data["material"]["SpecMap"] = id; + } + } + } + LLSelectedTEMaterial::setSpecularID(this, te_data["material"]["SpecMap"].asUUID(), te, object_id); + LLSelectedTEMaterial::setSpecularRepeatX(this, (F32)te_data["material"]["SpecRepX"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularRepeatY(this, (F32)te_data["material"]["SpecRepY"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularOffsetX(this, (F32)te_data["material"]["SpecOffX"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularOffsetY(this, (F32)te_data["material"]["SpecOffY"].asReal(), te, object_id); + LLSelectedTEMaterial::setSpecularRotation(this, (F32)te_data["material"]["SpecRot"].asReal(), te, object_id); + LLColor4 spec_color(te_data["material"]["SpecColor"]); + LLSelectedTEMaterial::setSpecularLightColor(this, spec_color, te); + LLSelectedTEMaterial::setSpecularLightExponent(this, (U8)te_data["material"]["SpecExp"].asInteger(), te, object_id); + LLSelectedTEMaterial::setEnvironmentIntensity(this, (U8)te_data["material"]["EnvIntensity"].asInteger(), te, object_id); + LLSelectedTEMaterial::setDiffuseAlphaMode(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id); + if (te_data.has("te") && te_data["te"].has("shiny")) + { + objectp->setTEShiny(te, (U8)te_data["te"]["shiny"].asInteger()); + } + } + } +} + +enum EPasteMode +{ + PASTE_COLOR, + PASTE_TEXTURE +}; + +struct LLPanelFacePasteTexFunctor : public LLSelectedTEFunctor +{ + LLPanelFacePasteTexFunctor(LLPanelFace* panel, EPasteMode mode) : + mPanelFace(panel), mMode(mode) {} + + virtual bool apply(LLViewerObject* objectp, S32 te) + { + switch (mMode) + { + case PASTE_COLOR: + mPanelFace->onPasteColor(objectp, te); + break; + case PASTE_TEXTURE: + mPanelFace->onPasteTexture(objectp, te); + break; + } + return true; + } +private: + LLPanelFace *mPanelFace; + EPasteMode mMode; +}; + +struct LLPanelFaceUpdateFunctor : public LLSelectedObjectFunctor +{ + LLPanelFaceUpdateFunctor(bool update_media) : mUpdateMedia(update_media) {} + virtual bool apply(LLViewerObject* object) + { + object->sendTEUpdate(); + if (mUpdateMedia) + { + LLVOVolume *vo = dynamic_cast(object); + if (vo && vo->hasMedia()) + { + vo->sendMediaDataUpdate(); + } + } + return true; + } +private: + bool mUpdateMedia; +}; + +struct LLPanelFaceNavigateHomeFunctor : public LLSelectedTEFunctor +{ + virtual bool apply(LLViewerObject* objectp, S32 te) + { + if (objectp && objectp->getTE(te)) + { + LLTextureEntry* tep = objectp->getTE(te); + const LLMediaEntry *media_data = tep->getMediaData(); + if (media_data) + { + if (media_data->getCurrentURL().empty() && media_data->getAutoPlay()) + { + viewer_media_t media_impl = + LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep->getMediaData()->getMediaID()); + if (media_impl) + { + media_impl->navigateHome(); + } + } + } + } + return true; + } +}; + +void LLPanelFace::menuDoToSelected(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + // paste + if (command == "color_paste") + { + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + + LLPanelFacePasteTexFunctor paste_func(this, PASTE_COLOR); + selected_objects->applyToTEs(&paste_func); + + LLPanelFaceUpdateFunctor sendfunc(false); + selected_objects->applyToObjects(&sendfunc); + } + else if (command == "texture_paste") + { + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + + LLPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE); + selected_objects->applyToTEs(&paste_func); + + LLPanelFaceUpdateFunctor sendfunc(true); + selected_objects->applyToObjects(&sendfunc); + + LLPanelFaceNavigateHomeFunctor navigate_home_func; + selected_objects->applyToTEs(&navigate_home_func); + } + // copy + else if (command == "color_copy") + { + onCopyColor(); + } + else if (command == "texture_copy") + { + onCopyTexture(); + } +} + +bool LLPanelFace::menuEnableItem(const LLSD& userdata) +{ + std::string command = userdata.asString(); + + // paste options + if (command == "color_paste") + { + return mClipboardParams.has("color"); + } + else if (command == "texture_paste") + { + return mClipboardParams.has("texture"); + } + return false; +} + // TODO: I don't know who put these in or what these are for??? void LLPanelFace::setMediaURL(const std::string& url) diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 2d57d89a44..5c1fb7f64d 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -47,6 +47,7 @@ class LLUICtrl; class LLViewerObject; class LLFloater; class LLMaterialID; +class LLMenuButton; // Represents an edit for use in replicating the op across one or more materials in the selection set. // @@ -205,6 +206,16 @@ protected: static void onClickAutoFix(void*); static void onAlignTexture(void*); +public: // needs to be accessible to selection manager + void onCopyColor(); // records all selected faces + void onPasteColor(LLViewerObject* objectp, S32 te); // to specific face + void onCopyTexture(); + void onPasteTexture(LLViewerObject* objectp, S32 te); + +protected: + void menuDoToSelected(const LLSD& userdata); + bool menuEnableItem(const LLSD& userdata); + static F32 valueGlow(LLViewerObject* object, S32 face); @@ -400,7 +411,10 @@ private: * If agent selects texture which is not allowed to be applied for the currently selected object, * all controls of the floater texture picker which allow to apply the texture will be disabled. */ - void onTextureSelectionChanged(LLInventoryItem* itemp); + void onTextureSelectionChanged(LLInventoryItem* itemp); + + LLMenuButton* mMenuClipboardColor; + LLMenuButton* mMenuClipboardTexture; bool mIsAlpha; @@ -415,7 +429,9 @@ private: * up-arrow on a spinner, and avoids running afoul of its throttle. */ bool mUpdateInFlight; - bool mUpdatePending; + bool mUpdatePending; + + LLSD mClipboardParams; public: #if defined(DEF_GET_MAT_STATE) diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index a03e85daff..dd7ef708f2 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -670,9 +670,6 @@ void LLPanelVolume::clearCtrls() mSpinPhysicsRestitution->setEnabled(FALSE); mComboMaterial->setEnabled( FALSE ); - - mMenuClipboardFeatures->setEnabled(false); - mMenuClipboardLight->setEnabled(false); } // diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 6e08be4866..1bbc2302c3 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -2,7 +2,7 @@ + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml index dd58658472..4823d74a26 100644 --- a/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_features.xml @@ -1,7 +1,7 @@ + name="Copy Paste Features Menu"> + name="Copy Paste Light Menu"> + name="Copy Paste Object Menu"> + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml index 438fb1e8ed..611433bc1d 100644 --- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml @@ -11,6 +11,19 @@ name="Texture" top="0" width="295"> + + width="54" /> + width="77" /> + + top_pad="17" + width="90"> - + + Date: Fri, 19 Jun 2020 22:45:20 +0300 Subject: SL-13359 #9.5 Texture tab --- indra/newview/llpanelface.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 6b5d14300f..f4122cac5f 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -38,6 +38,7 @@ #include "llfontgl.h" // project includes +#include "llagent.h" #include "llagentdata.h" #include "llbutton.h" #include "llcheckboxctrl.h" @@ -45,7 +46,9 @@ #include "llcombobox.h" #include "lldrawpoolbump.h" #include "llface.h" +#include "llinventoryfunctions.h" #include "llinventorymodel.h" // gInventory +#include "llinventorymodelbackgroundfetch.h" #include "lllineeditor.h" #include "llmaterialmgr.h" #include "llmediaentry.h" @@ -2773,9 +2776,6 @@ void LLPanelFace::onCopyTexture() // no need to record item id if full_perm==true if (!full_perm && item_id.notNull()) { - //Todo: - // also same thing probably needs to be present in object and volume panels for sculpt and projector images - /* LLViewerInventoryItem* itemp = gInventory.getItem(item_id); if (itemp) { @@ -2793,7 +2793,6 @@ void LLPanelFace::onCopyTexture() } } } - */ } } } @@ -2901,11 +2900,12 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) } } } - //todo: // for case when item got removed from inventory after we pressed 'copy' - /*if (!itemp_res && !full_perm) + // or texture got pasted into previous object + if (!itemp_res && !full_perm) { - // todo: fix this, we are often searching same tuxter multiple times (equal to number of faces) + // Todo: fix this, we are often searching same texture multiple times (equal to number of faces) + // Perhaps just mPanelFace->onPasteTexture(objectp, te, &asset_to_item_id_map); ? Not pretty, but will work LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; LLAssetIDMatches asset_id_matches(imageid); @@ -2933,7 +2933,7 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) } } } - }*/ + } if (itemp_res) { @@ -3013,7 +3013,7 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) LLSelectedTEMaterial::setAlphaMaskCutoff(this, (U8)te_data["material"]["SpecRot"].asInteger(), te, object_id); // Normal - // Replace placeholders with target's + // Replace placeholders with target's if (te_data["material"].has("NormMapNoCopy")) { LLMaterialPtr material = tep->getMaterialParams(); -- cgit v1.2.3 From a066c9a859bac941298368676356fe667a9f6501 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 22 Jun 2020 19:35:56 +0300 Subject: SL-13359 #10 Indicate face selection in tools floater --- indra/newview/llfloatertools.cpp | 100 ++++++++++++--------- .../newview/skins/default/xui/en/floater_tools.xml | 10 +-- .../default/xui/en/menu_copy_paste_texture.xml | 6 +- 3 files changed, 64 insertions(+), 52 deletions(-) (limited to 'indra') diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index 0429749e11..c550b81094 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -480,30 +480,61 @@ void LLFloaterTools::refresh() else #endif { - F32 link_cost = LLSelectMgr::getInstance()->getSelection()->getSelectedLinksetCost(); - S32 link_count = LLSelectMgr::getInstance()->getSelection()->getRootObjectCount(); + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + F32 link_cost = selection->getSelectedLinksetCost(); + S32 link_count = selection->getRootObjectCount(); + S32 object_count = selection->getObjectCount(); - LLCrossParcelFunctor func; - if (LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true)) - { - // Selection crosses parcel bounds. - // We don't display remaining land capacity in this case. - const LLStringExplicit empty_str(""); - childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", empty_str); - } - else - { - LLViewerObject* selected_object = mObjectSelection->getFirstObject(); - if (selected_object) - { - // Select a parcel at the currently selected object's position. - LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal()); - } - else - { - LL_WARNS() << "Failed to get selected object" << LL_ENDL; - } - } + LLCrossParcelFunctor func; + if (!LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, true)) + { + // Unless multiple parcels selected, higlight parcel object is at. + LLViewerObject* selected_object = mObjectSelection->getFirstObject(); + if (selected_object) + { + // Select a parcel at the currently selected object's position. + LLViewerParcelMgr::getInstance()->selectParcelAt(selected_object->getPositionGlobal()); + } + else + { + LL_WARNS() << "Failed to get selected object" << LL_ENDL; + } + } + + if (object_count == 1) + { + // "selection_faces" shouldn't be visible if not LLToolFace::getInstance() + // But still need to be populated in case user switches + + std::string faces_str = ""; + + for (LLObjectSelection::iterator iter = selection->begin(); iter != selection->end();) + { + LLObjectSelection::iterator nextiter = iter++; // not strictly needed, we have only one object + LLSelectNode* node = *nextiter; + LLViewerObject* object = (*nextiter)->getObject(); + if (!object) + continue; + S32 num_tes = llmin((S32)object->getNumTEs(), (S32)object->getNumFaces()); + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + if (!faces_str.empty()) + { + faces_str += ", "; + } + faces_str += llformat("%d", te); + } + } + } + + childSetTextArg("selection_faces", "[FACES_STRING]", faces_str); + } + + bool show_faces = (object_count == 1) + && LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool(); + getChildView("selection_faces")->setVisible(show_faces); LLStringUtil::format_map_t selection_args; selection_args["OBJ_COUNT"] = llformat("%.1d", link_count); @@ -824,7 +855,8 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) bool have_selection = !LLSelectMgr::getInstance()->getSelection()->isEmpty(); getChildView("selection_count")->setVisible(!land_visible && have_selection); - getChildView("remaining_capacity")->setVisible(!land_visible && have_selection); + getChildView("selection_faces")->setVisible(LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool() + && LLSelectMgr::getInstance()->getSelection()->getObjectCount() == 1); getChildView("selection_empty")->setVisible(!land_visible && !have_selection); mTab->setVisible(!land_visible); @@ -1181,26 +1213,6 @@ void LLFloaterTools::updateLandImpacts() return; } - S32 rezzed_prims = parcel->getSimWidePrimCount(); - S32 total_capacity = parcel->getSimWideMaxPrimCapacity(); - LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); - if (region) - { - S32 max_tasks_per_region = (S32)region->getMaxTasks(); - total_capacity = llmin(total_capacity, max_tasks_per_region); - } - std::string remaining_capacity_str = ""; - - bool show_mesh_cost = gMeshRepo.meshRezEnabled(); - if (show_mesh_cost) - { - LLStringUtil::format_map_t remaining_capacity_args; - remaining_capacity_args["LAND_CAPACITY"] = llformat("%d", total_capacity - rezzed_prims); - remaining_capacity_str = getString("status_remaining_capacity", remaining_capacity_args); - } - - childSetTextArg("remaining_capacity", "[CAPACITY_STRING]", remaining_capacity_str); - // Update land impacts info in the weights floater LLFloaterObjectWeights* object_weights_floater = LLFloaterReg::findTypedInstance("object_weights"); if(object_weights_floater) diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml index 1bbc2302c3..f5214420b4 100644 --- a/indra/newview/skins/default/xui/en/floater_tools.xml +++ b/indra/newview/skins/default/xui/en/floater_tools.xml @@ -68,7 +68,7 @@ - [OBJ_COUNT] objects selected, land impact [LAND_IMPACT] + [OBJ_COUNT] objects selected, land impact [LAND_IMPACT] [secondlife:///app/openfloater/object_weights More info] @@ -763,11 +763,12 @@ font="SansSerifSmall" layout="topleft" left="10" - name="selection_count" + name="selection_faces" top_delta="0" visible="false" width="280"> - + Faces selected: [FACES_STRING] + - [CAPACITY_STRING] [secondlife:///app/openfloater/object_weights More info] diff --git a/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml b/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml index 8267041502..f358affc23 100644 --- a/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml +++ b/indra/newview/skins/default/xui/en/menu_copy_paste_texture.xml @@ -7,15 +7,15 @@ layout="topleft" name="params_copy" visible="true"> - + - - + + -- cgit v1.2.3 From 23f20c207d1e69c03e2ce2cb9100ad216ac60708 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 23 Jun 2020 22:02:33 +0300 Subject: SL-12688 Warnings part #1 --- indra/newview/llpanelface.cpp | 299 ++++++++++++++------- indra/newview/llpanelface.h | 2 + .../newview/skins/default/xui/en/notifications.xml | 10 + .../skins/default/xui/en/panel_tools_texture.xml | 9 + 4 files changed, 226 insertions(+), 94 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index f4122cac5f..3849e5c8f7 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -2579,6 +2579,80 @@ void LLPanelFace::onAlignTexture(void* userdata) self->alignTestureLayer(); } +enum EPasteMode +{ + PASTE_COLOR, + PASTE_TEXTURE +}; + +struct LLPanelFacePasteTexFunctor : public LLSelectedTEFunctor +{ + LLPanelFacePasteTexFunctor(LLPanelFace* panel, EPasteMode mode) : + mPanelFace(panel), mMode(mode) {} + + virtual bool apply(LLViewerObject* objectp, S32 te) + { + switch (mMode) + { + case PASTE_COLOR: + mPanelFace->onPasteColor(objectp, te); + break; + case PASTE_TEXTURE: + mPanelFace->onPasteTexture(objectp, te); + break; + } + return true; + } +private: + LLPanelFace *mPanelFace; + EPasteMode mMode; +}; + +struct LLPanelFaceUpdateFunctor : public LLSelectedObjectFunctor +{ + LLPanelFaceUpdateFunctor(bool update_media) : mUpdateMedia(update_media) {} + virtual bool apply(LLViewerObject* object) + { + object->sendTEUpdate(); + if (mUpdateMedia) + { + LLVOVolume *vo = dynamic_cast(object); + if (vo && vo->hasMedia()) + { + vo->sendMediaDataUpdate(); + } + } + return true; + } +private: + bool mUpdateMedia; +}; + +struct LLPanelFaceNavigateHomeFunctor : public LLSelectedTEFunctor +{ + virtual bool apply(LLViewerObject* objectp, S32 te) + { + if (objectp && objectp->getTE(te)) + { + LLTextureEntry* tep = objectp->getTE(te); + const LLMediaEntry *media_data = tep->getMediaData(); + if (media_data) + { + if (media_data->getCurrentURL().empty() && media_data->getAutoPlay()) + { + viewer_media_t media_impl = + LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep->getMediaData()->getMediaID()); + if (media_impl) + { + media_impl->navigateHome(); + } + } + } + } + return true; + } +}; + void LLPanelFace::onCopyColor() { LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); @@ -2625,12 +2699,74 @@ void LLPanelFace::onCopyColor() } } -void LLPanelFace::onPasteColor(LLViewerObject* objectp, S32 te) +void LLPanelFace::onPasteColor() { if (!mClipboardParams.has("color")) { return; } + + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1) + { + // not supposed to happen + LL_WARNS() << "Failed to paste color due to missing or wrong selection" << LL_ENDL; + return; + } + + bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool(); + LLSD &clipboard = mClipboardParams["color"]; // array + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + S32 compare_tes = num_tes; + + if (face_selection_mode) + { + compare_tes = 0; + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + compare_tes++; + } + } + } + + // we can copy if single face was copied in edit face mode or if face count matches + if (!((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean()) + && compare_tes != clipboard.size()) + { + LLSD notif_args; + if (face_selection_mode) + { + static std::string reason = getString("paste_error_face_selection_mismatch"); + notif_args["REASON"] = reason; + } + else + { + static std::string reason = getString("paste_error_object_face_count_mismatch"); + notif_args["REASON"] = reason; + } + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + + LLPanelFacePasteTexFunctor paste_func(this, PASTE_COLOR); + selected_objects->applyToTEs(&paste_func); + + LLPanelFaceUpdateFunctor sendfunc(false); + selected_objects->applyToObjects(&sendfunc); +} + +void LLPanelFace::onPasteColor(LLViewerObject* objectp, S32 te) +{ LLSD te_data; LLSD &clipboard = mClipboardParams["color"]; // array if ((clipboard.size() == 1) && mClipboardParams["color_all_tes"].asBoolean()) @@ -2687,7 +2823,6 @@ void LLPanelFace::onPasteColor(LLViewerObject* objectp, S32 te) void LLPanelFace::onCopyTexture() { - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); @@ -2854,12 +2989,77 @@ void LLPanelFace::onCopyTexture() } } -void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) +void LLPanelFace::onPasteTexture() { if (!mClipboardParams.has("texture")) { return; } + + LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject(); + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(); + S32 selected_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount(); + if (!objectp || !node + || objectp->getPCode() != LL_PCODE_VOLUME + || !objectp->permModify() + || objectp->isPermanentEnforced() + || selected_count > 1) + { + // not supposed to happen + LL_WARNS() << "Failed to paste texture due to missing or wrong selection" << LL_ENDL; + return; + } + + bool face_selection_mode = LLToolFace::getInstance() == LLToolMgr::getInstance()->getCurrentTool(); + LLSD &clipboard = mClipboardParams["texture"]; // array + S32 num_tes = llmin((S32)objectp->getNumTEs(), (S32)objectp->getNumFaces()); + S32 compare_tes = num_tes; + + if (face_selection_mode) + { + compare_tes = 0; + for (S32 te = 0; te < num_tes; ++te) + { + if (node->isTESelected(te)) + { + compare_tes++; + } + } + } + + // we can copy if single face was copied in edit face mode or if face count matches + if (!((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean()) + && compare_tes != clipboard.size()) + { + LLSD notif_args; + if (face_selection_mode) + { + static std::string reason = getString("paste_error_face_selection_mismatch"); + notif_args["REASON"] = reason; + } + else + { + static std::string reason = getString("paste_error_object_face_count_mismatch"); + notif_args["REASON"] = reason; + } + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); + + LLPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE); + selected_objects->applyToTEs(&paste_func); + + LLPanelFaceUpdateFunctor sendfunc(true); + selected_objects->applyToObjects(&sendfunc); + + LLPanelFaceNavigateHomeFunctor navigate_home_func; + selected_objects->applyToTEs(&navigate_home_func); +} + +void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) +{ LLSD te_data; LLSD &clipboard = mClipboardParams["texture"]; // array if ((clipboard.size() == 1) && mClipboardParams["texture_all_tes"].asBoolean()) @@ -3066,80 +3266,6 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) } } -enum EPasteMode -{ - PASTE_COLOR, - PASTE_TEXTURE -}; - -struct LLPanelFacePasteTexFunctor : public LLSelectedTEFunctor -{ - LLPanelFacePasteTexFunctor(LLPanelFace* panel, EPasteMode mode) : - mPanelFace(panel), mMode(mode) {} - - virtual bool apply(LLViewerObject* objectp, S32 te) - { - switch (mMode) - { - case PASTE_COLOR: - mPanelFace->onPasteColor(objectp, te); - break; - case PASTE_TEXTURE: - mPanelFace->onPasteTexture(objectp, te); - break; - } - return true; - } -private: - LLPanelFace *mPanelFace; - EPasteMode mMode; -}; - -struct LLPanelFaceUpdateFunctor : public LLSelectedObjectFunctor -{ - LLPanelFaceUpdateFunctor(bool update_media) : mUpdateMedia(update_media) {} - virtual bool apply(LLViewerObject* object) - { - object->sendTEUpdate(); - if (mUpdateMedia) - { - LLVOVolume *vo = dynamic_cast(object); - if (vo && vo->hasMedia()) - { - vo->sendMediaDataUpdate(); - } - } - return true; - } -private: - bool mUpdateMedia; -}; - -struct LLPanelFaceNavigateHomeFunctor : public LLSelectedTEFunctor -{ - virtual bool apply(LLViewerObject* objectp, S32 te) - { - if (objectp && objectp->getTE(te)) - { - LLTextureEntry* tep = objectp->getTE(te); - const LLMediaEntry *media_data = tep->getMediaData(); - if (media_data) - { - if (media_data->getCurrentURL().empty() && media_data->getAutoPlay()) - { - viewer_media_t media_impl = - LLViewerMedia::getInstance()->getMediaImplFromTextureID(tep->getMediaData()->getMediaID()); - if (media_impl) - { - media_impl->navigateHome(); - } - } - } - } - return true; - } -}; - void LLPanelFace::menuDoToSelected(const LLSD& userdata) { std::string command = userdata.asString(); @@ -3147,26 +3273,11 @@ void LLPanelFace::menuDoToSelected(const LLSD& userdata) // paste if (command == "color_paste") { - LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); - - LLPanelFacePasteTexFunctor paste_func(this, PASTE_COLOR); - selected_objects->applyToTEs(&paste_func); - - LLPanelFaceUpdateFunctor sendfunc(false); - selected_objects->applyToObjects(&sendfunc); + onPasteColor(); } else if (command == "texture_paste") { - LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); - - LLPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE); - selected_objects->applyToTEs(&paste_func); - - LLPanelFaceUpdateFunctor sendfunc(true); - selected_objects->applyToObjects(&sendfunc); - - LLPanelFaceNavigateHomeFunctor navigate_home_func; - selected_objects->applyToTEs(&navigate_home_func); + onPasteTexture(); } // copy else if (command == "color_copy") diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index 5c1fb7f64d..948d33c2c1 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -208,8 +208,10 @@ protected: public: // needs to be accessible to selection manager void onCopyColor(); // records all selected faces + void onPasteColor(); // to specific face void onPasteColor(LLViewerObject* objectp, S32 te); // to specific face void onCopyTexture(); + void onPasteTexture(); void onPasteTexture(LLViewerObject* objectp, S32 te); protected: diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 8a91a1f721..f59ac450f2 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -8946,6 +8946,16 @@ We cannot display a preview of this texture because it is no-copy and/or no-tran name="okignore" yestext="OK"/> + + +Paste failed. [REASON] + + + + When multiple faces are copied, the target object must have the same number of faces selected. + + + When all faces of an object are copied, the target object must have the same number of faces. + + Date: Wed, 24 Jun 2020 18:57:49 +0300 Subject: SL-12688 Warnings part #2 --- indra/newview/llpanelface.cpp | 64 +++++++++++++++++++++- indra/newview/lltexturectrl.cpp | 19 +++---- indra/newview/lltexturectrl.h | 2 +- .../newview/skins/default/xui/en/notifications.xml | 15 ++++- .../skins/default/xui/en/panel_tools_texture.xml | 4 ++ 5 files changed, 89 insertions(+), 15 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 3849e5c8f7..641a3602c8 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -2869,7 +2869,8 @@ void LLPanelFace::onCopyTexture() { LLUUID item_id; LLUUID id = te_data["te"]["imageid"].asUUID(); - bool full_perm = get_is_library_texture(id) || (objectp->permCopy() && objectp->permTransfer() && objectp->permModify()); + bool from_library = get_is_predefined_texture(id); + bool full_perm = from_library || (objectp->permCopy() && objectp->permTransfer() && objectp->permModify()); if (id.notNull() && !full_perm) { @@ -2890,6 +2891,12 @@ void LLPanelFace::onCopyTexture() } } + if (item_id.notNull() && gInventory.isObjectDescendentOf(item_id, gInventory.getLibraryRootFolderID())) + { + full_perm = true; + from_library = true; + } + if (id.isNull() || (!full_perm && item_id.isNull())) { @@ -2899,10 +2906,15 @@ void LLPanelFace::onCopyTexture() te_data["te"]["imageid"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); } te_data["te"]["itemfullperm"] = true; + te_data["te"]["fromlibrary"] = true; } else { te_data["te"]["itemfullperm"] = full_perm; + // from_library is unreliable since we don't get texture item if source object + // is fullperm but it merely means additional checks when assigning texture + te_data["te"]["fromlibrary"] = from_library; + // If full permission object, texture is free to copy, // but otherwise we need to check inventory and extract permissions // @@ -3046,6 +3058,40 @@ void LLPanelFace::onPasteTexture() return; } + bool full_perm = true; + LLSD::array_const_iterator iter = clipboard.beginArray(); + LLSD::array_const_iterator end = clipboard.endArray(); + for (; iter != end; ++iter) + { + const LLSD& te_data = *iter; + if (te_data.has("te")) + { + full_perm &= te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); + if (te_data["te"].has("imageitemid")) + { + LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); + if (item_id.notNull()) + { + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (!itemp) + { + // image might be in object's inventory, but it can be not up to date + LLSD notif_args; + static std::string reason = getString("paste_error_inventory_not_found"); + notif_args["REASON"] = reason; + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } + } + } + } + } + + if (!full_perm) + { + LLNotificationsUtil::add("FacePasteTexturePermissions"); + } + LLObjectSelectionHandle selected_objects = LLSelectMgr::getInstance()->getSelection(); LLPanelFacePasteTexFunctor paste_func(this, PASTE_TEXTURE); @@ -3082,6 +3128,7 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) { // Texture bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); + bool from_library = te_data["te"].has("fromlibrary") && te_data["te"]["fromlibrary"].asBoolean(); if (te_data["te"].has("imageid")) { const LLUUID& imageid = te_data["te"]["imageid"].asUUID(); //texture or asset id @@ -3098,12 +3145,21 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) // dropTextureAllFaces will fail if incomplete itemp_res = itemp; } + else + { + // Theoretically shouldn't happend, but if it does happen, we + // might need to add a notification to user that paste will fail + // since inventory isn't fully loaded + LL_WARNS() << "Item " << item_id << " is incomplete, paste might fail silently." << LL_ENDL; + } } } // for case when item got removed from inventory after we pressed 'copy' // or texture got pasted into previous object if (!itemp_res && !full_perm) { + // Due to checks for imageitemid in LLPanelFace::onPasteTexture() this should no longer be reachable. + LL_INFOS() << "Item " << te_data["te"]["imageitemid"].asUUID() << " no longer in inventory." << LL_ENDL; // Todo: fix this, we are often searching same texture multiple times (equal to number of faces) // Perhaps just mPanelFace->onPasteTexture(objectp, te, &asset_to_item_id_map); ? Not pretty, but will work LLViewerInventoryCategory::cat_array_t cats; @@ -3137,11 +3193,13 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) if (itemp_res) { + // from_library is unreliable since we don't get texture item if object is + // fullperm but it merely means additional checks when assigning texture if (te == -1) // all faces { LLToolDragAndDrop::dropTextureAllFaces(objectp, itemp_res, - LLToolDragAndDrop::SOURCE_AGENT, + from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); } else // one face @@ -3149,7 +3207,7 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) LLToolDragAndDrop::dropTextureOneFace(objectp, te, itemp_res, - LLToolDragAndDrop::SOURCE_AGENT, + from_library ? LLToolDragAndDrop::SOURCE_LIBRARY : LLToolDragAndDrop::SOURCE_AGENT, LLUUID::null); } } diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 2f5be2b32e..b5e4b3608a 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -82,24 +82,23 @@ static const S32 LOCAL_TRACKING_ID_COLUMN = 1; //static -bool get_is_library_texture(LLUUID image_id) +bool get_is_predefined_texture(LLUUID asset_id) { - if (gInventory.isObjectDescendentOf(image_id, gInventory.getLibraryRootFolderID()) - || image_id == LLUUID(gSavedSettings.getString("DefaultObjectTexture")) - || image_id == LLUUID(gSavedSettings.getString("UIImgWhiteUUID")) - || image_id == LLUUID(gSavedSettings.getString("UIImgInvisibleUUID")) - || image_id == LLUUID(SCULPT_DEFAULT_TEXTURE)) + if (asset_id == LLUUID(gSavedSettings.getString("DefaultObjectTexture")) + || asset_id == LLUUID(gSavedSettings.getString("UIImgWhiteUUID")) + || asset_id == LLUUID(gSavedSettings.getString("UIImgInvisibleUUID")) + || asset_id == LLUUID(SCULPT_DEFAULT_TEXTURE)) { return true; } return false; } -LLUUID get_copy_free_item_by_asset_id(LLUUID image_id) +LLUUID get_copy_free_item_by_asset_id(LLUUID asset_id) { LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; - LLAssetIDMatches asset_id_matches(image_id); + LLAssetIDMatches asset_id_matches(asset_id); gInventory.collectDescendentsIf(LLUUID::null, cats, items, @@ -125,13 +124,13 @@ LLUUID get_copy_free_item_by_asset_id(LLUUID image_id) return LLUUID::null; } -bool get_can_copy_texture(LLUUID image_id) +bool get_can_copy_texture(LLUUID asset_id) { // User is allowed to copy a texture if: // library asset or default texture, // or copy perm asset exists in user's inventory - return get_is_library_texture(image_id) || get_copy_free_item_by_asset_id(image_id).notNull(); + return get_is_predefined_texture(asset_id) || get_copy_free_item_by_asset_id(asset_id).notNull(); } LLFloaterTexturePicker::LLFloaterTexturePicker( diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index 2b2c5fa237..97e7bb0d20 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -54,7 +54,7 @@ typedef boost::function drag_n_drop_callback typedef boost::function texture_selected_callback; // Helper functions for UI that work with picker -bool get_is_library_texture(LLUUID image_id); +bool get_is_predefined_texture(LLUUID asset_id); // texture picker works by asset ids since objects normaly do // not retain inventory ids as result these functions are looking diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index f59ac450f2..196d507507 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -8946,7 +8946,7 @@ We cannot display a preview of this texture because it is no-copy and/or no-tran name="okignore" yestext="OK"/> - + + + You applied a texture with limited permissions, object will inherit permissions from texture. + + + + When all faces of an object are copied, the target object must have the same number of faces. + + One or more texture not found in inventory. + Date: Thu, 25 Jun 2020 23:34:22 +0300 Subject: SL-12688 Restored stricter permission requirements You need to own texture in inventory to be able to copy it --- indra/newview/llpanelface.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 641a3602c8..4249a13827 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -2870,7 +2870,7 @@ void LLPanelFace::onCopyTexture() LLUUID item_id; LLUUID id = te_data["te"]["imageid"].asUUID(); bool from_library = get_is_predefined_texture(id); - bool full_perm = from_library || (objectp->permCopy() && objectp->permTransfer() && objectp->permModify()); + bool full_perm = from_library; if (id.notNull() && !full_perm) { @@ -2911,8 +2911,6 @@ void LLPanelFace::onCopyTexture() else { te_data["te"]["itemfullperm"] = full_perm; - // from_library is unreliable since we don't get texture item if source object - // is fullperm but it merely means additional checks when assigning texture te_data["te"]["fromlibrary"] = from_library; // If full permission object, texture is free to copy, @@ -2921,7 +2919,7 @@ void LLPanelFace::onCopyTexture() // Normally we care only about restrictions for current user and objects // don't inherit any 'next owner' permissions from texture, so there is // no need to record item id if full_perm==true - if (!full_perm && item_id.notNull()) + if (!full_perm && !from_library && item_id.notNull()) { LLViewerInventoryItem* itemp = gInventory.getItem(item_id); if (itemp) @@ -3193,8 +3191,6 @@ void LLPanelFace::onPasteTexture(LLViewerObject* objectp, S32 te) if (itemp_res) { - // from_library is unreliable since we don't get texture item if object is - // fullperm but it merely means additional checks when assigning texture if (te == -1) // all faces { LLToolDragAndDrop::dropTextureAllFaces(objectp, -- cgit v1.2.3 From ccf51f173ca80215e5ecb02cdb04724374349de9 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 2 Jul 2020 17:21:09 +0300 Subject: SL-12334 Texture UUID is not copied to clipboard from a full-perms object --- indra/newview/llpanelface.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 4249a13827..091ea3764d 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -2872,6 +2872,20 @@ void LLPanelFace::onCopyTexture() bool from_library = get_is_predefined_texture(id); bool full_perm = from_library; + if (!full_perm + && objectp->permCopy() + && objectp->permTransfer() + && objectp->permModify()) + { + // If agent created this object and nothing is limiting permissions, mark as full perm + // If agent was granted permission to edit objects owned and created by somebody else, mark full perm + // This check is not perfect since we can't figure out whom textures belong to so this ended up restrictive + std::string creator_app_link; + LLUUID creator_id; + LLSelectMgr::getInstance()->selectGetCreator(creator_id, creator_app_link); + full_perm = objectp->mOwnerID == creator_id; + } + if (id.notNull() && !full_perm) { std::map::iterator iter = asset_item_map.find(id); @@ -3056,7 +3070,7 @@ void LLPanelFace::onPasteTexture() return; } - bool full_perm = true; + bool full_perm_object = true; LLSD::array_const_iterator iter = clipboard.beginArray(); LLSD::array_const_iterator end = clipboard.endArray(); for (; iter != end; ++iter) @@ -3064,8 +3078,9 @@ void LLPanelFace::onPasteTexture() const LLSD& te_data = *iter; if (te_data.has("te")) { - full_perm &= te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); - if (te_data["te"].has("imageitemid")) + bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); + full_perm_object &= full_perm; + if (!full_perm && te_data["te"].has("imageitemid")) { LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); if (item_id.notNull()) @@ -3085,7 +3100,7 @@ void LLPanelFace::onPasteTexture() } } - if (!full_perm) + if (!full_perm_object) { LLNotificationsUtil::add("FacePasteTexturePermissions"); } -- cgit v1.2.3 From 3fde31b61026f9052243a5a716dbc0a6419880ae Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 2 Jul 2020 18:36:19 +0300 Subject: SL-12688 Fixed Warning --- indra/newview/llpanelface.cpp | 50 ++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 24 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index 091ea3764d..a3f9acb85a 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -2911,18 +2911,6 @@ void LLPanelFace::onCopyTexture() from_library = true; } - if (id.isNull() - || (!full_perm && item_id.isNull())) - { - if (!LLLocalBitmapMgr::getInstance()->isLocal(id)) - { - te_data["te"].erase("imageid"); - te_data["te"]["imageid"] = LLUUID(gSavedSettings.getString("DefaultObjectTexture")); - } - te_data["te"]["itemfullperm"] = true; - te_data["te"]["fromlibrary"] = true; - } - else { te_data["te"]["itemfullperm"] = full_perm; te_data["te"]["fromlibrary"] = from_library; @@ -3076,26 +3064,40 @@ void LLPanelFace::onPasteTexture() for (; iter != end; ++iter) { const LLSD& te_data = *iter; - if (te_data.has("te")) + if (te_data.has("te") && te_data["te"].has("imageid")) { bool full_perm = te_data["te"].has("itemfullperm") && te_data["te"]["itemfullperm"].asBoolean(); full_perm_object &= full_perm; - if (!full_perm && te_data["te"].has("imageitemid")) + if (!full_perm) { - LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); - if (item_id.notNull()) + if (te_data["te"].has("imageitemid")) { - LLViewerInventoryItem* itemp = gInventory.getItem(item_id); - if (!itemp) + LLUUID item_id = te_data["te"]["imageitemid"].asUUID(); + if (item_id.notNull()) { - // image might be in object's inventory, but it can be not up to date - LLSD notif_args; - static std::string reason = getString("paste_error_inventory_not_found"); - notif_args["REASON"] = reason; - LLNotificationsUtil::add("FacePasteFailed", notif_args); - return; + LLViewerInventoryItem* itemp = gInventory.getItem(item_id); + if (!itemp) + { + // image might be in object's inventory, but it can be not up to date + LLSD notif_args; + static std::string reason = getString("paste_error_inventory_not_found"); + notif_args["REASON"] = reason; + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } } } + else + { + // Item was not found on 'copy' stage + // Since this happened at copy, might be better to either show this + // at copy stage or to drop clipboard here + LLSD notif_args; + static std::string reason = getString("paste_error_inventory_not_found"); + notif_args["REASON"] = reason; + LLNotificationsUtil::add("FacePasteFailed", notif_args); + return; + } } } } -- cgit v1.2.3 From 94eea485edf06c48fcbbbf195ee2f8eb9b8616b1 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Tue, 7 Jul 2020 16:04:37 +0300 Subject: SL-13545 FIXED The 'Flexible Path' settings can be pasted to the sculpted object --- indra/newview/llpanelvolume.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index dd7ef708f2..cd6ea97243 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -981,7 +981,7 @@ void LLPanelVolume::onPasteFeatures() else { LLVOVolume *volobjp = (LLVOVolume *)objectp; - if (volobjp->setIsFlexible(is_flexible)) + if (volobjp->setIsFlexible(false)) { mObject->sendShapeUpdate(); LLSelectMgr::getInstance()->selectionUpdatePhantom(volobjp->flagPhantom()); -- cgit v1.2.3 From e1a3ce0d7465fd1c441168b0fcf5b849f47bab4e Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Sat, 11 Jul 2020 04:35:34 +0300 Subject: SL-13556 The browser status label shouldn't be clickable --- indra/newview/skins/default/xui/en/panel_profile_web.xml | 1 + 1 file changed, 1 insertion(+) (limited to 'indra') diff --git a/indra/newview/skins/default/xui/en/panel_profile_web.xml b/indra/newview/skins/default/xui/en/panel_profile_web.xml index af2ac57f58..e0cb4d3d06 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_web.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_web.xml @@ -31,5 +31,6 @@ follows="bottom|left|right" layout="topleft" halign="center" + parse_urls="false" /> -- cgit v1.2.3 From 0c88287d26f029c1f6f2cbc62982e63628448737 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Wed, 14 Oct 2020 22:35:16 +0300 Subject: build fix --- indra/newview/llfloatermodelpreview.cpp | 55 --------------------------------- 1 file changed, 55 deletions(-) (limited to 'indra') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index b70258a060..b9c03f66a3 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1620,61 +1620,6 @@ void LLFloaterModelPreview::refresh() sInstance->mModelPreview->mDirty = true; } -//static -void LLModelPreview::textureLoadedCallback( - BOOL success, - LLViewerFetchedTexture *src_vi, - LLImageRaw* src, - LLImageRaw* src_aux, - S32 discard_level, - BOOL final, - void* userdata ) -{ - LLModelPreview* preview = (LLModelPreview*) userdata; - preview->refresh(); - - if(final && preview->mModelLoader) - { - // for areTexturesReady() - if(preview->mModelLoader->mNumOfFetchingTextures > 0) - { - preview->mModelLoader->mNumOfFetchingTextures-- ; - } - } -} - -// static -bool LLModelPreview::lodQueryCallback() -{ - // not the best solution, but model preview belongs to floater - // so it is an easy way to check that preview still exists. - LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; - if (fmp && fmp->mModelPreview) - { - LLModelPreview* preview = fmp->mModelPreview; - if (preview->mLodsQuery.size() > 0) - { - S32 lod = preview->mLodsQuery.back(); - preview->mLodsQuery.pop_back(); - preview->genLODs(lod); - - // return false to continue cycle - return false; - } - } - // nothing to process - return true; -} - -void LLModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) -{ - if (!mLODFrozen) - { - genLODs(lod, 3, enforce_tri_limit); - refresh(); - } -} - LLFloaterModelPreview::DecompRequest::DecompRequest(const std::string& stage, LLModel* mdl) { mStage = stage; -- cgit v1.2.3 From 6e20fc99e76e5632e6e609d959156b444290286e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 23 Oct 2020 18:42:57 +0300 Subject: SL-14181 Fix missing message when deleting last classified --- indra/newview/llpanelprofileclassifieds.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra') diff --git a/indra/newview/llpanelprofileclassifieds.cpp b/indra/newview/llpanelprofileclassifieds.cpp index d72028a366..1f638bdeb6 100644 --- a/indra/newview/llpanelprofileclassifieds.cpp +++ b/indra/newview/llpanelprofileclassifieds.cpp @@ -248,6 +248,9 @@ void LLPanelProfileClassifieds::callbackDeleteClassified(const LLSD& notificatio } updateButtons(); + + BOOL no_data = !mTabContainer->getTabCount(); + mNoItemsLabel->setVisible(no_data); } } -- cgit v1.2.3 From 11a9332fa7bd830d8e44f15a91e008f3a6f9c19d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 25 May 2020 23:59:33 +0300 Subject: SL-12889 Failed to cache image crashes Scaled down avatar or group image was getting into cache. --- indra/newview/lltexturecache.cpp | 7 +++++-- indra/newview/lltexturefetch.cpp | 5 +++++ indra/newview/lltexturefetch.h | 1 + indra/newview/llviewertexture.cpp | 9 +++++++-- 4 files changed, 18 insertions(+), 4 deletions(-) (limited to 'indra') diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 2e52414d71..6211d0ce3b 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -616,6 +616,9 @@ bool LLTextureCacheRemoteWorker::doWrite() if(idx >= 0) { // write to the fast cache. + // mRawImage is not entirely safe here since it is a pointer to one owned by cache worker, + // it could have been retrieved via getRequestFinished() and then modified. + // If writeToFastCache crashes, something is wrong around fetch worker. if(!mCache->writeToFastCache(mID, idx, mRawImage, mRawDiscardLevel)) { LL_WARNS() << "writeToFastCache failed" << LL_ENDL; @@ -2155,8 +2158,8 @@ bool LLTextureCache::writeToFastCache(LLUUID image_id, S32 id, LLPointer>= i; if(w * h *c > 0) //valid { - //make a duplicate to keep the original raw image untouched. - + // Make a duplicate to keep the original raw image untouched. + // Might be good idea to do a copy during writeToCache() call instead of here try { #if LL_WINDOWS diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index fe058024f6..f64db7beb5 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -1977,6 +1977,11 @@ bool LLTextureFetchWorker::doWork(S32 param) setState(WAIT_ON_WRITE); ++mCacheWriteCount; CacheWriteResponder* responder = new CacheWriteResponder(mFetcher, mID); + // This call might be under work mutex, but mRawImage is not nessesary safe here. + // If something retrieves it via getRequestFinished() and modifies, image won't + // be protected by work mutex and won't be safe to use here nor in cache worker. + // So make sure users of getRequestFinished() does not attempt to modify image while + // fetcher is working mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority, mFormattedImage->getData(), datasize, mFileSize, mRawImage, mDecodedDiscard, responder); diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index cdf8868597..2aa194e141 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -92,6 +92,7 @@ public: void deleteAllRequests(); // Threads: T* + // keep in mind that if fetcher isn't done, it still might need original raw image bool getRequestFinished(const LLUUID& id, S32& discard_level, LLPointer& raw, LLPointer& aux, LLCore::HttpStatus& last_http_get_status); diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index a2cec9a613..bd83a61e5b 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1238,6 +1238,8 @@ void LLViewerFetchedTexture::loadFromFastCache() { if (mBoostLevel == LLGLTexture::BOOST_ICON) { + // Shouldn't do anything usefull since texures in fast cache are 16x16, + // it is here in case fast cache changes. S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : DEFAULT_ICON_DIMENTIONS; S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : DEFAULT_ICON_DIMENTIONS; if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) @@ -1485,7 +1487,8 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) mOrigWidth = mRawImage->getWidth(); mOrigHeight = mRawImage->getHeight(); - + // This is only safe because it's a local image and fetcher doesn't use raw data + // from local images, but this might become unsafe in case of changes to fetcher if (mBoostLevel == BOOST_PREVIEW) { mRawImage->biasedScaleToPowerOfTwo(1024); @@ -1989,6 +1992,7 @@ bool LLViewerFetchedTexture::updateFetch() if (mRawImage.notNull()) sRawCount--; if (mAuxRawImage.notNull()) sAuxCount--; + // keep in mind that fetcher still might need raw image, don't modify original bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage, mLastHttpGetStatus); if (mRawImage.notNull()) sRawCount++; @@ -2048,7 +2052,8 @@ bool LLViewerFetchedTexture::updateFetch() if (mRawImage && (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height)) { // scale oversized icon, no need to give more work to gl - mRawImage->scale(expected_width, expected_height); + // since we got mRawImage from thread worker and image may be in use (ex: writing cache), make a copy + mRawImage = mRawImage->scaled(expected_width, expected_height); } } -- cgit v1.2.3 From 2d113743f2943a1ab614a41d29cef7e13bc4e878 Mon Sep 17 00:00:00 2001 From: Mnikolenko Productengine Date: Thu, 14 Jan 2021 18:02:09 +0200 Subject: SL-14504 FIXED Classified links always launch your Profile Classifieds --- indra/newview/CMakeLists.txt | 2 + indra/newview/llpanelclassified.cpp | 564 +++++++++++++++++++++ indra/newview/llpanelclassified.h | 175 +++++++ indra/newview/llpanelprofile.cpp | 1 + indra/newview/llpanelprofileclassifieds.cpp | 62 ++- .../newview/skins/default/xui/en/floater_picks.xml | 21 + .../skins/default/xui/en/panel_classified_info.xml | 37 +- 7 files changed, 824 insertions(+), 38 deletions(-) create mode 100644 indra/newview/llpanelclassified.cpp create mode 100644 indra/newview/llpanelclassified.h create mode 100644 indra/newview/skins/default/xui/en/floater_picks.xml (limited to 'indra') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index e47a04a1f9..1efa4e6c23 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -433,6 +433,7 @@ set(viewer_SOURCE_FILES llpanelavatar.cpp llpanelavatartag.cpp llpanelblockedlist.cpp + llpanelclassified.cpp llpanelcontents.cpp llpaneleditsky.cpp llpaneleditwater.cpp @@ -1057,6 +1058,7 @@ set(viewer_HEADER_FILES llpanelavatar.h llpanelavatartag.h llpanelblockedlist.h + llpanelclassified.h llpanelcontents.h llpaneleditsky.h llpaneleditwater.h diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp new file mode 100644 index 0000000000..183000ceac --- /dev/null +++ b/indra/newview/llpanelclassified.cpp @@ -0,0 +1,564 @@ +/** + * @file llpanelclassified.cpp + * @brief LLPanelClassifiedInfo class implementation + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, 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$ + */ + +// Display of a classified used both for the global view in the +// Find directory, and also for each individual user's classified in their +// profile. + +#include "llviewerprecompiledheaders.h" + +#include "llpanelclassified.h" + +#include "lldispatcher.h" +#include "llfloaterreg.h" +#include "llparcel.h" + +#include "llagent.h" +#include "llclassifiedflags.h" +#include "lliconctrl.h" +#include "lltexturectrl.h" +#include "llfloaterworldmap.h" +#include "llviewergenericmessage.h" // send_generic_message +#include "llviewerregion.h" +#include "llscrollcontainer.h" +#include "llcorehttputil.h" + +//static +LLPanelClassifiedInfo::panel_list_t LLPanelClassifiedInfo::sAllPanels; +static LLPanelInjector t_panel_panel_classified_info("panel_classified_info"); + +// "classifiedclickthrough" +// strings[0] = classified_id +// strings[1] = teleport_clicks +// strings[2] = map_clicks +// strings[3] = profile_clicks +class LLDispatchClassifiedClickThrough : public LLDispatchHandler +{ +public: + virtual bool operator()( + const LLDispatcher* dispatcher, + const std::string& key, + const LLUUID& invoice, + const sparam_t& strings) + { + if (strings.size() != 4) return false; + LLUUID classified_id(strings[0]); + S32 teleport_clicks = atoi(strings[1].c_str()); + S32 map_clicks = atoi(strings[2].c_str()); + S32 profile_clicks = atoi(strings[3].c_str()); + + LLPanelClassifiedInfo::setClickThrough( + classified_id, teleport_clicks, map_clicks, profile_clicks, false); + + return true; + } +}; +static LLDispatchClassifiedClickThrough sClassifiedClickThrough; + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLPanelClassifiedInfo::LLPanelClassifiedInfo() + : LLPanel() + , mInfoLoaded(false) + , mScrollingPanel(NULL) + , mScrollContainer(NULL) + , mScrollingPanelMinHeight(0) + , mScrollingPanelWidth(0) + , mSnapshotStreched(false) + , mTeleportClicksOld(0) + , mMapClicksOld(0) + , mProfileClicksOld(0) + , mTeleportClicksNew(0) + , mMapClicksNew(0) + , mProfileClicksNew(0) + , mSnapshotCtrl(NULL) +{ + sAllPanels.push_back(this); +} + +LLPanelClassifiedInfo::~LLPanelClassifiedInfo() +{ + sAllPanels.remove(this); +} + +BOOL LLPanelClassifiedInfo::postBuild() +{ + childSetAction("show_on_map_btn", boost::bind(&LLPanelClassifiedInfo::onMapClick, this)); + childSetAction("teleport_btn", boost::bind(&LLPanelClassifiedInfo::onTeleportClick, this)); + + mScrollingPanel = getChild("scroll_content_panel"); + mScrollContainer = getChild("profile_scroll"); + + mScrollingPanelMinHeight = mScrollContainer->getScrolledViewRect().getHeight(); + mScrollingPanelWidth = mScrollingPanel->getRect().getWidth(); + + mSnapshotCtrl = getChild("classified_snapshot"); + mSnapshotRect = getDefaultSnapshotRect(); + + return TRUE; +} + +void LLPanelClassifiedInfo::reshape(S32 width, S32 height, BOOL called_from_parent /* = TRUE */) +{ + LLPanel::reshape(width, height, called_from_parent); + + if (!mScrollContainer || !mScrollingPanel) + return; + + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + + S32 scroll_height = mScrollContainer->getRect().getHeight(); + if (mScrollingPanelMinHeight >= scroll_height) + { + mScrollingPanel->reshape(mScrollingPanelWidth, mScrollingPanelMinHeight); + } + else + { + mScrollingPanel->reshape(mScrollingPanelWidth + scrollbar_size, scroll_height); + } + + mSnapshotRect = getDefaultSnapshotRect(); + stretchSnapshot(); +} + +void LLPanelClassifiedInfo::onOpen(const LLSD& key) +{ + LLUUID avatar_id = key["classified_creator_id"]; + if(avatar_id.isNull()) + { + return; + } + + if(getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); + } + + setAvatarId(avatar_id); + + resetData(); + resetControls(); + scrollToTop(); + + setClassifiedId(key["classified_id"]); + setClassifiedName(key["classified_name"]); + setDescription(key["classified_desc"]); + setSnapshotId(key["classified_snapshot_id"]); + setFromSearch(key["from_search"]); + + LL_INFOS() << "Opening classified [" << getClassifiedName() << "] (" << getClassifiedId() << ")" << LL_ENDL; + + LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(), this); + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(getClassifiedId()); + gGenericDispatcher.addHandler("classifiedclickthrough", &sClassifiedClickThrough); + + if (gAgent.getRegion()) + { + // While we're at it let's get the stats from the new table if that + // capability exists. + std::string url = gAgent.getRegion()->getCapability("SearchStatRequest"); + if (!url.empty()) + { + LL_INFOS() << "Classified stat request via capability" << LL_ENDL; + LLSD body; + LLUUID classifiedId = getClassifiedId(); + body["classified_id"] = classifiedId; + LLCoreHttpUtil::HttpCoroutineAdapter::callbackHttpPost(url, body, + boost::bind(&LLPanelClassifiedInfo::handleSearchStatResponse, classifiedId, _1)); + } + } + // Update classified click stats. + // *TODO: Should we do this when opening not from search? + sendClickMessage("profile"); + + setInfoLoaded(false); +} + +/*static*/ +void LLPanelClassifiedInfo::handleSearchStatResponse(LLUUID classifiedId, LLSD result) +{ + S32 teleport = result["teleport_clicks"].asInteger(); + S32 map = result["map_clicks"].asInteger(); + S32 profile = result["profile_clicks"].asInteger(); + S32 search_teleport = result["search_teleport_clicks"].asInteger(); + S32 search_map = result["search_map_clicks"].asInteger(); + S32 search_profile = result["search_profile_clicks"].asInteger(); + + LLPanelClassifiedInfo::setClickThrough(classifiedId, + teleport + search_teleport, + map + search_map, + profile + search_profile, + true); +} + +void LLPanelClassifiedInfo::processProperties(void* data, EAvatarProcessorType type) +{ + if(APT_CLASSIFIED_INFO == type) + { + LLAvatarClassifiedInfo* c_info = static_cast(data); + if(c_info && getClassifiedId() == c_info->classified_id) + { + setClassifiedName(c_info->name); + setDescription(c_info->description); + setSnapshotId(c_info->snapshot_id); + setParcelId(c_info->parcel_id); + setPosGlobal(c_info->pos_global); + setSimName(c_info->sim_name); + + setClassifiedLocation(createLocationText(c_info->parcel_name, c_info->sim_name, c_info->pos_global)); + getChild("category")->setValue(LLClassifiedInfo::sCategories[c_info->category]); + + static std::string mature_str = getString("type_mature"); + static std::string pg_str = getString("type_pg"); + static LLUIString price_str = getString("l$_price"); + static std::string date_fmt = getString("date_fmt"); + + bool mature = is_cf_mature(c_info->flags); + getChild("content_type")->setValue(mature ? mature_str : pg_str); + getChild("content_type_moderate")->setVisible(mature); + getChild("content_type_general")->setVisible(!mature); + + std::string auto_renew_str = is_cf_auto_renew(c_info->flags) ? + getString("auto_renew_on") : getString("auto_renew_off"); + getChild("auto_renew")->setValue(auto_renew_str); + + price_str.setArg("[PRICE]", llformat("%d", c_info->price_for_listing)); + getChild("price_for_listing")->setValue(LLSD(price_str)); + + std::string date_str = date_fmt; + LLStringUtil::format(date_str, LLSD().with("datetime", (S32) c_info->creation_date)); + getChild("creation_date")->setValue(date_str); + + setInfoLoaded(true); + + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(), this); + } + } +} + +void LLPanelClassifiedInfo::resetData() +{ + setClassifiedName(LLStringUtil::null); + setDescription(LLStringUtil::null); + setClassifiedLocation(LLStringUtil::null); + setClassifiedId(LLUUID::null); + setSnapshotId(LLUUID::null); + setPosGlobal(LLVector3d::zero); + setParcelId(LLUUID::null); + setSimName(LLStringUtil::null); + setFromSearch(false); + + // reset click stats + mTeleportClicksOld = 0; + mMapClicksOld = 0; + mProfileClicksOld = 0; + mTeleportClicksNew = 0; + mMapClicksNew = 0; + mProfileClicksNew = 0; + + getChild("category")->setValue(LLStringUtil::null); + getChild("content_type")->setValue(LLStringUtil::null); + getChild("click_through_text")->setValue(LLStringUtil::null); + getChild("price_for_listing")->setValue(LLStringUtil::null); + getChild("auto_renew")->setValue(LLStringUtil::null); + getChild("creation_date")->setValue(LLStringUtil::null); + getChild("click_through_text")->setValue(LLStringUtil::null); + getChild("content_type_moderate")->setVisible(FALSE); + getChild("content_type_general")->setVisible(FALSE); +} + +void LLPanelClassifiedInfo::resetControls() +{ + bool is_self = getAvatarId() == gAgent.getID(); + + getChildView("edit_btn")->setEnabled(is_self); + getChildView("edit_btn")->setVisible( is_self); + getChildView("price_layout_panel")->setVisible( is_self); + getChildView("clickthrough_layout_panel")->setVisible( is_self); +} + +void LLPanelClassifiedInfo::setClassifiedName(const std::string& name) +{ + getChild("classified_name")->setValue(name); +} + +std::string LLPanelClassifiedInfo::getClassifiedName() +{ + return getChild("classified_name")->getValue().asString(); +} + +void LLPanelClassifiedInfo::setDescription(const std::string& desc) +{ + getChild("classified_desc")->setValue(desc); +} + +std::string LLPanelClassifiedInfo::getDescription() +{ + return getChild("classified_desc")->getValue().asString(); +} + +void LLPanelClassifiedInfo::setClassifiedLocation(const std::string& location) +{ + getChild("classified_location")->setValue(location); +} + +std::string LLPanelClassifiedInfo::getClassifiedLocation() +{ + return getChild("classified_location")->getValue().asString(); +} + +void LLPanelClassifiedInfo::setSnapshotId(const LLUUID& id) +{ + mSnapshotCtrl->setValue(id); + mSnapshotStreched = false; +} + +void LLPanelClassifiedInfo::draw() +{ + LLPanel::draw(); + + // Stretch in draw because it takes some time to load a texture, + // going to try to stretch snapshot until texture is loaded + if(!mSnapshotStreched) + { + stretchSnapshot(); + } +} + +LLUUID LLPanelClassifiedInfo::getSnapshotId() +{ + return getChild("classified_snapshot")->getValue().asUUID(); +} + +// static +void LLPanelClassifiedInfo::setClickThrough( + const LLUUID& classified_id, + S32 teleport, + S32 map, + S32 profile, + bool from_new_table) +{ + LL_INFOS() << "Click-through data for classified " << classified_id << " arrived: [" + << teleport << ", " << map << ", " << profile << "] (" + << (from_new_table ? "new" : "old") << ")" << LL_ENDL; + + for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) + { + LLPanelClassifiedInfo* self = *iter; + if (self->getClassifiedId() != classified_id) + { + continue; + } + + // *HACK: Skip LLPanelClassifiedEdit instances: they don't display clicks data. + // Those instances should not be in the list at all. + if (typeid(*self) != typeid(LLPanelClassifiedInfo)) + { + continue; + } + + LL_INFOS() << "Updating classified info panel" << LL_ENDL; + + // We need to check to see if the data came from the new stat_table + // or the old classified table. We also need to cache the data from + // the two separate sources so as to display the aggregate totals. + + if (from_new_table) + { + self->mTeleportClicksNew = teleport; + self->mMapClicksNew = map; + self->mProfileClicksNew = profile; + } + else + { + self->mTeleportClicksOld = teleport; + self->mMapClicksOld = map; + self->mProfileClicksOld = profile; + } + + static LLUIString ct_str = self->getString("click_through_text_fmt"); + + ct_str.setArg("[TELEPORT]", llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld)); + ct_str.setArg("[MAP]", llformat("%d", self->mMapClicksNew + self->mMapClicksOld)); + ct_str.setArg("[PROFILE]", llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld)); + + self->getChild("click_through_text")->setValue(ct_str.getString()); + // *HACK: remove this when there is enough room for click stats in the info panel + self->getChildView("click_through_text")->setToolTip(ct_str.getString()); + + LL_INFOS() << "teleport: " << llformat("%d", self->mTeleportClicksNew + self->mTeleportClicksOld) + << ", map: " << llformat("%d", self->mMapClicksNew + self->mMapClicksOld) + << ", profile: " << llformat("%d", self->mProfileClicksNew + self->mProfileClicksOld) + << LL_ENDL; + } +} + +// static +std::string LLPanelClassifiedInfo::createLocationText( + const std::string& original_name, + const std::string& sim_name, + const LLVector3d& pos_global) +{ + std::string location_text; + + location_text.append(original_name); + + if (!sim_name.empty()) + { + if (!location_text.empty()) + location_text.append(", "); + location_text.append(sim_name); + } + + if (!location_text.empty()) + location_text.append(" "); + + if (!pos_global.isNull()) + { + S32 region_x = ll_round((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = ll_round((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = ll_round((F32)pos_global.mdV[VZ]); + location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); + } + + return location_text; +} + +void LLPanelClassifiedInfo::stretchSnapshot() +{ + // *NOTE dzaporozhan + // Could be moved to LLTextureCtrl + + LLViewerFetchedTexture* texture = mSnapshotCtrl->getTexture(); + + if(!texture) + { + return; + } + + if(0 == texture->getOriginalWidth() || 0 == texture->getOriginalHeight()) + { + // looks like texture is not loaded yet + return; + } + + LLRect rc = mSnapshotRect; + // *HACK dzaporozhan + // LLTextureCtrl uses BTN_HEIGHT_SMALL as bottom for texture which causes + // drawn texture to be smaller than expected. (see LLTextureCtrl::draw()) + // Lets increase texture height to force texture look as expected. + rc.mBottom -= BTN_HEIGHT_SMALL; + + F32 t_width = texture->getFullWidth(); + F32 t_height = texture->getFullHeight(); + + F32 ratio = llmin( (rc.getWidth() / t_width), (rc.getHeight() / t_height) ); + + t_width *= ratio; + t_height *= ratio; + + rc.setCenterAndSize(rc.getCenterX(), rc.getCenterY(), llfloor(t_width), llfloor(t_height)); + mSnapshotCtrl->setShape(rc); + + mSnapshotStreched = true; +} + +LLRect LLPanelClassifiedInfo::getDefaultSnapshotRect() +{ + // Using scroll container makes getting default rect a hard task + // because rect in postBuild() and in first reshape() is not the same. + // Using snapshot_panel makes it easier to reshape snapshot. + return getChild("snapshot_panel")->getLocalRect(); +} + +void LLPanelClassifiedInfo::scrollToTop() +{ + LLScrollContainer* scrollContainer = findChild("profile_scroll"); + if (scrollContainer) + scrollContainer->goToTop(); +} + +// static +// *TODO: move out of the panel +void LLPanelClassifiedInfo::sendClickMessage( + const std::string& type, + bool from_search, + const LLUUID& classified_id, + const LLUUID& parcel_id, + const LLVector3d& global_pos, + const std::string& sim_name) +{ + if (gAgent.getRegion()) + { + // You're allowed to click on your own ads to reassure yourself + // that the system is working. + LLSD body; + body["type"] = type; + body["from_search"] = from_search; + body["classified_id"] = classified_id; + body["parcel_id"] = parcel_id; + body["dest_pos_global"] = global_pos.getValue(); + body["region_name"] = sim_name; + + std::string url = gAgent.getRegion()->getCapability("SearchStatTracking"); + LL_INFOS() << "Sending click msg via capability (url=" << url << ")" << LL_ENDL; + LL_INFOS() << "body: [" << body << "]" << LL_ENDL; + LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, body, + "SearchStatTracking Click report sent.", "SearchStatTracking Click report NOT sent."); + } +} + +void LLPanelClassifiedInfo::sendClickMessage(const std::string& type) +{ + sendClickMessage( + type, + fromSearch(), + getClassifiedId(), + getParcelId(), + getPosGlobal(), + getSimName()); +} + +void LLPanelClassifiedInfo::onMapClick() +{ + sendClickMessage("map"); + LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); + LLFloaterReg::showInstance("world_map", "center"); +} + +void LLPanelClassifiedInfo::onTeleportClick() +{ + if (!getPosGlobal().isExactlyZero()) + { + sendClickMessage("teleport"); + gAgent.teleportViaLocation(getPosGlobal()); + LLFloaterWorldMap::getInstance()->trackLocation(getPosGlobal()); + } +} + +//EOF diff --git a/indra/newview/llpanelclassified.h b/indra/newview/llpanelclassified.h new file mode 100644 index 0000000000..471becd0f7 --- /dev/null +++ b/indra/newview/llpanelclassified.h @@ -0,0 +1,175 @@ +/** + * @file llpanelclassified.h + * @brief LLPanelClassifiedInfo class definition + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, 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$ + */ + +// Display of a classified used both for the global view in the +// Find directory, and also for each individual user's classified in their +// profile. +#ifndef LL_LLPANELCLASSIFIED_H +#define LL_LLPANELCLASSIFIED_H + +#include "llavatarpropertiesprocessor.h" +#include "llclassifiedinfo.h" +#include "llfloater.h" +#include "llpanel.h" +#include "llrect.h" + +class LLScrollContainer; +class LLTextureCtrl; + +class LLPanelClassifiedInfo : public LLPanel, public LLAvatarPropertiesObserver +{ + LOG_CLASS(LLPanelClassifiedInfo); +public: + + LLPanelClassifiedInfo(); + virtual ~LLPanelClassifiedInfo(); + + /*virtual*/ void onOpen(const LLSD& key); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; } + + LLUUID& getAvatarId() { return mAvatarId; } + + void setSnapshotId(const LLUUID& id); + + LLUUID getSnapshotId(); + + void setClassifiedId(const LLUUID& id) { mClassifiedId = id; } + + LLUUID& getClassifiedId() { return mClassifiedId; } + + void setClassifiedName(const std::string& name); + + std::string getClassifiedName(); + + void setDescription(const std::string& desc); + + std::string getDescription(); + + void setClassifiedLocation(const std::string& location); + + std::string getClassifiedLocation(); + + void setPosGlobal(const LLVector3d& pos) { mPosGlobal = pos; } + + LLVector3d& getPosGlobal() { return mPosGlobal; } + + void setParcelId(const LLUUID& id) { mParcelId = id; } + + LLUUID getParcelId() { return mParcelId; } + + void setSimName(const std::string& sim_name) { mSimName = sim_name; } + + std::string getSimName() { return mSimName; } + + void setFromSearch(bool val) { mFromSearch = val; } + + bool fromSearch() { return mFromSearch; } + + bool getInfoLoaded() { return mInfoLoaded; } + + void setInfoLoaded(bool loaded) { mInfoLoaded = loaded; } + + static void setClickThrough( + const LLUUID& classified_id, + S32 teleport, + S32 map, + S32 profile, + bool from_new_table); + + static void sendClickMessage( + const std::string& type, + bool from_search, + const LLUUID& classified_id, + const LLUUID& parcel_id, + const LLVector3d& global_pos, + const std::string& sim_name); + + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + /*virtual*/ void draw(); + +protected: + + virtual void resetData(); + + virtual void resetControls(); + + static std::string createLocationText( + const std::string& original_name, + const std::string& sim_name, + const LLVector3d& pos_global); + + void stretchSnapshot(); + void sendClickMessage(const std::string& type); + + LLRect getDefaultSnapshotRect(); + + void scrollToTop(); + + void onMapClick(); + void onTeleportClick(); + + bool mSnapshotStreched; + LLRect mSnapshotRect; + LLTextureCtrl* mSnapshotCtrl; + +private: + + LLUUID mAvatarId; + LLUUID mClassifiedId; + LLVector3d mPosGlobal; + LLUUID mParcelId; + std::string mSimName; + bool mFromSearch; + bool mInfoLoaded; + + LLScrollContainer* mScrollContainer; + LLPanel* mScrollingPanel; + + S32 mScrollingPanelMinHeight; + S32 mScrollingPanelWidth; + + // Needed for stat tracking + S32 mTeleportClicksOld; + S32 mMapClicksOld; + S32 mProfileClicksOld; + S32 mTeleportClicksNew; + S32 mMapClicksNew; + S32 mProfileClicksNew; + + static void handleSearchStatResponse(LLUUID classifiedId, LLSD result); + + + typedef std::list panel_list_t; + static panel_list_t sAllPanels; +}; + +#endif // LL_LLPANELCLASSIFIED_H diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 2cd5aecc2e..82515c8d4a 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -63,6 +63,7 @@ #include "llpanelprofilepicks.h" #include "lltrans.h" #include "llviewercontrol.h" +#include "llviewermenu.h" //is_agent_mappable #include "llvoiceclient.h" #include "llweb.h" diff --git a/indra/newview/llpanelprofileclassifieds.cpp b/indra/newview/llpanelprofileclassifieds.cpp index 1f638bdeb6..7cc9406e08 100644 --- a/indra/newview/llpanelprofileclassifieds.cpp +++ b/indra/newview/llpanelprofileclassifieds.cpp @@ -37,6 +37,7 @@ #include "llcorehttputil.h" #include "lldispatcher.h" #include "llfloaterreg.h" +#include "llfloatersidepanelcontainer.h" #include "llfloaterworldmap.h" #include "lliconctrl.h" #include "lllineeditor.h" @@ -70,13 +71,16 @@ LLPanelProfileClassified::panel_list_t LLPanelProfileClassified::sAllPanels; static LLPanelInjector t_panel_profile_classifieds("panel_profile_classifieds"); static LLPanelInjector t_panel_profile_classified("panel_profile_classified"); -class LLClassifiedHandler : public LLCommandHandler +class LLClassifiedHandler : public LLCommandHandler, public LLAvatarPropertiesObserver { public: // throttle calls from untrusted browsers LLClassifiedHandler() : LLCommandHandler("classified", UNTRUSTED_THROTTLE) {} - - bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + + std::set mClassifiedIds; + std::string mRequestVerb; + + bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) { if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableClassifieds")) { @@ -109,7 +113,10 @@ public: const std::string verb = params[1].asString(); if (verb == "about") { - LLAvatarActions::showClassified(gAgent.getID(), classified_id, false); + mRequestVerb = verb; + mClassifiedIds.insert(classified_id); + LLAvatarPropertiesProcessor::getInstance()->addObserver(LLUUID(), this); + LLAvatarPropertiesProcessor::getInstance()->sendClassifiedInfoRequest(classified_id); return true; } else if (verb == "edit") @@ -120,6 +127,53 @@ public: return false; } + + void openClassified(LLAvatarClassifiedInfo* c_info) + { + if (mRequestVerb == "about") + { + if (c_info->creator_id == gAgent.getID()) + { + LLAvatarActions::showClassified(gAgent.getID(), c_info->classified_id, false); + } + else + { + LLSD params; + params["id"] = c_info->creator_id; + params["open_tab_name"] = "panel_picks"; + params["show_tab_panel"] = "classified_details"; + params["classified_id"] = c_info->classified_id; + params["classified_creator_id"] = c_info->creator_id; + params["classified_snapshot_id"] = c_info->snapshot_id; + params["classified_name"] = c_info->name; + params["classified_desc"] = c_info->description; + params["from_search"] = true; + LLFloaterSidePanelContainer::showPanel("picks", params); + } + } + } + + void processProperties(void* data, EAvatarProcessorType type) + { + if (APT_CLASSIFIED_INFO != type) + { + return; + } + + // is this the classified that we asked for? + LLAvatarClassifiedInfo* c_info = static_cast(data); + if (!c_info || mClassifiedIds.find(c_info->classified_id) == mClassifiedIds.end()) + { + return; + } + + // open the detail side tray for this classified + openClassified(c_info); + + // remove our observer now that we're done + mClassifiedIds.erase(c_info->classified_id); + LLAvatarPropertiesProcessor::getInstance()->removeObserver(LLUUID(), this); + } }; LLClassifiedHandler gClassifiedHandler; diff --git a/indra/newview/skins/default/xui/en/floater_picks.xml b/indra/newview/skins/default/xui/en/floater_picks.xml new file mode 100644 index 0000000000..3cd6abafe5 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_picks.xml @@ -0,0 +1,21 @@ + + + + diff --git a/indra/newview/skins/default/xui/en/panel_classified_info.xml b/indra/newview/skins/default/xui/en/panel_classified_info.xml index d4a2745d1d..04a0bc800d 100644 --- a/indra/newview/skins/default/xui/en/panel_classified_info.xml +++ b/indra/newview/skins/default/xui/en/panel_classified_info.xml @@ -38,28 +38,15 @@ name="auto_renew_off"> Disabled - - - - - - - - - - - - - - diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 8d7cfe1116..85c20268d0 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2438,20 +2438,6 @@ function="World.EnvPreset" function="Advanced.ToggleConsole" parameter="scene monitor" /> - - - - - - Date: Tue, 31 May 2022 22:41:21 +0300 Subject: SL-15312 Tweaks and fixes #2 - changed 'is friend' color - fixed off/online status vanishing - changed user name format - fixed rights behavior - cleaned up some unused code - readded click functionality to permission icons (might need to return buttons instead) --- indra/newview/llpanelprofile.cpp | 207 ++++++++------------- indra/newview/llpanelprofile.h | 9 + .../default/xui/en/panel_profile_secondlife.xml | 18 +- 3 files changed, 87 insertions(+), 147 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 41d8a3e51c..85f443635d 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -468,123 +468,8 @@ public: }; LLProfileHandler gProfileHandler; - -////////////////////////////////////////////////////////////////////////// -// LLAgentHandler - -class LLAgentHandler : public LLCommandHandler -{ -public: - // requires trusted browser to trigger - LLAgentHandler() : LLCommandHandler("agent", UNTRUSTED_THROTTLE) { } - - bool handle(const LLSD& params, const LLSD& query_map, - LLMediaCtrl* web) - { - if (params.size() < 2) return false; - LLUUID avatar_id; - if (!avatar_id.set(params[0], FALSE)) - { - return false; - } - - const std::string verb = params[1].asString(); - if (verb == "about") - { - LLAvatarActions::showProfile(avatar_id); - return true; - } - - if (verb == "inspect") - { - LLFloaterReg::showInstance("inspect_avatar", LLSD().with("avatar_id", avatar_id)); - return true; - } - - if (verb == "im") - { - LLAvatarActions::startIM(avatar_id); - return true; - } - - if (verb == "pay") - { - if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableAvatarPay")) - { - LLNotificationsUtil::add("NoAvatarPay", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); - return true; - } - - LLAvatarActions::pay(avatar_id); - return true; - } - - if (verb == "offerteleport") - { - LLAvatarActions::offerTeleport(avatar_id); - return true; - } - - if (verb == "requestfriend") - { - LLAvatarActions::requestFriendshipDialog(avatar_id); - return true; - } - - if (verb == "removefriend") - { - LLAvatarActions::removeFriendDialog(avatar_id); - return true; - } - - if (verb == "mute") - { - if (! LLAvatarActions::isBlocked(avatar_id)) - { - LLAvatarActions::toggleBlock(avatar_id); - } - return true; - } - - if (verb == "unmute") - { - if (LLAvatarActions::isBlocked(avatar_id)) - { - LLAvatarActions::toggleBlock(avatar_id); - } - return true; - } - - if (verb == "block") - { - if (params.size() > 2) - { - const std::string object_name = LLURI::unescape(params[2].asString()); - LLMute mute(avatar_id, object_name, LLMute::OBJECT); - LLMuteList::getInstance()->add(mute); - LLPanelBlockedList::showPanelAndSelect(mute.mID); - } - return true; - } - - if (verb == "unblock") - { - if (params.size() > 2) - { - const std::string object_name = params[2].asString(); - LLMute mute(avatar_id, object_name, LLMute::OBJECT); - LLMuteList::getInstance()->remove(mute); - } - return true; - } - return false; - } -}; -LLAgentHandler gAgentHandler; - - ///---------------------------------------------------------------------------- -/// LLFloaterInventoryFinder +/// LLFloaterProfilePermissions ///---------------------------------------------------------------------------- class LLFloaterProfilePermissions @@ -605,7 +490,8 @@ private: void fillRightsData(); void rightsConfirmationCallback(const LLSD& notification, const LLSD& response); void confirmModifyRights(bool grant); - void onCommitRights(); + void onCommitSeeOnlineRights(); + void onCommitEditRights(); void onApplyRights(); void onCancel(); @@ -651,7 +537,8 @@ BOOL LLFloaterProfilePermissions::postBuild() mOkBtn = getChild("perms_btn_ok"); mCancelBtn = getChild("perms_btn_cancel"); - mEditObjectRights->setCommitCallback([this](LLUICtrl*, void*) { onCommitRights(); }, nullptr); + mOnlineStatus->setCommitCallback([this](LLUICtrl*, void*) { onCommitSeeOnlineRights(); }, nullptr); + mEditObjectRights->setCommitCallback([this](LLUICtrl*, void*) { onCommitEditRights(); }, nullptr); mOkBtn->setCommitCallback([this](LLUICtrl*, void*) { onApplyRights(); }, nullptr); mCancelBtn->setCommitCallback([this](LLUICtrl*, void*) { onCancel(); }, nullptr); @@ -704,7 +591,9 @@ void LLFloaterProfilePermissions::fillRightsData() { S32 rights = relation->getRightsGrantedTo(); - mOnlineStatus->setValue(LLRelationship::GRANT_ONLINE_STATUS & rights ? TRUE : FALSE); + BOOL see_online = LLRelationship::GRANT_ONLINE_STATUS & rights ? TRUE : FALSE; + mOnlineStatus->setValue(see_online); + mMapRights->setEnabled(see_online); mMapRights->setValue(LLRelationship::GRANT_MAP_LOCATION & rights ? TRUE : FALSE); mEditObjectRights->setValue(LLRelationship::GRANT_MODIFY_OBJECTS & rights ? TRUE : FALSE); } @@ -733,13 +622,38 @@ void LLFloaterProfilePermissions::confirmModifyRights(bool grant) boost::bind(&LLFloaterProfilePermissions::rightsConfirmationCallback, this, _1, _2)); } -void LLFloaterProfilePermissions::onCommitRights() +void LLFloaterProfilePermissions::onCommitSeeOnlineRights() +{ + bool see_online = mOnlineStatus->getValue().asBoolean(); + mMapRights->setEnabled(see_online); + if (see_online) + { + const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(mAvatarID); + if (relation) + { + S32 rights = relation->getRightsGrantedTo(); + mMapRights->setValue(LLRelationship::GRANT_MAP_LOCATION & rights ? TRUE : FALSE); + } + else + { + closeFloater(); + LL_INFOS("ProfilePermissions") << "Floater closing since agent is no longer a friend" << LL_ENDL; + } + } + else + { + mMapRights->setValue(FALSE); + } +} + +void LLFloaterProfilePermissions::onCommitEditRights() { const LLRelationship* buddy_relationship = LLAvatarTracker::instance().getBuddyInfo(mAvatarID); if (!buddy_relationship) { - LL_WARNS("ProfilePermissions") << "Trying to modify rights for non-friend avatar. Skipped." << LL_ENDL; + LL_WARNS("ProfilePermissions") << "Trying to modify rights for non-friend avatar. Closing floater." << LL_ENDL; + closeFloater(); return; } @@ -844,6 +758,13 @@ BOOL LLPanelProfileSecondLife::postBuild() getChild("open_notes")->setCommitCallback([this](LLUICtrl*, void*) { onOpenNotes(); }, nullptr); + mCanSeeOnlineIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); }); + mCantSeeOnlineIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); }); + mCanSeeOnMapIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); }); + mCantSeeOnMapIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); }); + mCanEditObjectsIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); }); + mCantEditObjectsIcon->setMouseUpCallback([this](LLUICtrl*, S32 x, S32 y, MASK mask) { onShowAgentPermissionsDialog(); }); + return TRUE; } @@ -995,9 +916,10 @@ void LLPanelProfileSecondLife::openGroupProfile() void LLPanelProfileSecondLife::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) { mAvatarNameCacheConnection.disconnect(); - // Should be possible to get this from AgentProfile capability - getChild("display_name")->setValue( av_name.getDisplayName() ); - getChild("user_name")->setValue(av_name.getAccountName()); + if (getIsLoaded()) + { + fillNameAgeData(av_name, mBornOn); + } } void LLPanelProfileSecondLife::setNotesSnippet(std::string ¬es) @@ -1049,10 +971,21 @@ void LLPanelProfileSecondLife::fillCommonData(const LLAvatarData* avatar_data) // 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; - args["[AGE]"] = LLDateUtil::ageFromDate( avatar_data->born_on, LLDate::now()); - std::string register_date = getString("AgeFormat", args); - getChild("user_age")->setValue(register_date); + mBornOn = avatar_data->born_on; + + // Should be possible to get user and display names from AgentProfile capability + // but at the moment contraining this to limits of LLAvatarData + LLAvatarName av_name; + if (LLAvatarNameCache::get(avatar_data->avatar_id, &av_name)) + { + fillNameAgeData(av_name, mBornOn); + } + else if (!mAvatarNameCacheConnection.connected()) + { + // shouldn't happen, but just in case + mAvatarNameCacheConnection = LLAvatarNameCache::get(getAvatarId(), boost::bind(&LLPanelProfileSecondLife::onAvatarNameCache, this, _1, _2)); + } + setDescriptionText(avatar_data->about_text); if (avatar_data->image_id.notNull()) @@ -1144,10 +1077,16 @@ void LLPanelProfileSecondLife::fillRightsData() } childSetVisible("permissions_panel", NULL != relation); - childSetVisible("spacer_layout", NULL == relation); - childSetVisible("frind_layout", NULL != relation); - childSetVisible("online_layout", false); - childSetVisible("offline_layout", false); +} + +void LLPanelProfileSecondLife::fillNameAgeData(const LLAvatarName &av_name, const LLDate &born_on) +{ + LLStringUtil::format_map_t args; + args["[AGE]"] = LLDateUtil::ageFromDate(born_on, LLDate::now()); + args["[NAME]"] = av_name.getAccountName(); + std::string register_date = getString("NameAgeFormat", args); + getChild("user_name_age")->setValue(register_date); + getChild("display_name")->setValue(av_name.getDisplayName()); } void LLPanelProfileSecondLife::onImageLoaded(BOOL success, LLViewerFetchedTexture *imagep) @@ -1620,13 +1559,15 @@ void LLPanelProfileSecondLife::onShowAgentPermissionsDialog() LLFloaterProfilePermissions * perms = new LLFloaterProfilePermissions(parent_floater, getAvatarId()); mFloaterPermissionsHandle = perms->getHandle(); perms->openFloater(); + perms->setVisibleAndFrontmost(TRUE); parent_floater->addDependentFloater(mFloaterPermissionsHandle); } } else // already open { - floater->closeFloater(); + floater->setMinimized(FALSE); + floater->setVisibleAndFrontmost(TRUE); } } diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index 2f2437ed0a..4985ec0015 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -136,8 +136,16 @@ protected: */ void fillAccountStatus(const LLAvatarData* avatar_data); + /** + * Sets permissions specific icon + */ void fillRightsData(); + /** + * Fills user name, display name, age. + */ + void fillNameAgeData(const LLAvatarName &av_name, const LLDate &born_on); + void onImageLoaded(BOOL success, LLViewerFetchedTexture *imagep); static void onImageLoaded(BOOL success, LLViewerFetchedTexture *src_vi, @@ -204,6 +212,7 @@ private: bool mWaitingForImageUpload; bool mAllowPublish; std::string mDescriptionText; + LLDate mBornOn; boost::signals2::connection mAvatarNameCacheConnection; }; diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml index 853e782de1..7dd16de0ed 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml @@ -10,8 +10,8 @@ layout="topleft" > + name="NameAgeFormat" + value="[NAME] ([AGE])" /> @@ -99,17 +99,7 @@ Account: [ACCTTYPE] layout="topleft"/> - - Date: Tue, 31 May 2022 16:54:05 -0500 Subject: SL-17484 Fix for unit tests. Deprecate non-threaded LLQueuedThread and make lllfsthread threaded. --- indra/llcommon/llqueuedthread.cpp | 23 +++++++++++-------- indra/llcommon/lltimer.cpp | 7 +++++- indra/llfilesystem/lllfsthread.cpp | 4 ++-- indra/llimage/llimageworker.cpp | 8 ------- indra/llimage/llimageworker.h | 3 --- indra/llimage/tests/llimageworker_test.cpp | 25 --------------------- .../llmessage/tests/llcoproceduremanager_test.cpp | 2 +- indra/newview/llappviewer.cpp | 26 +++++++++++++--------- 8 files changed, 38 insertions(+), 60 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index 871c42f7ee..60304fff75 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -37,12 +37,13 @@ // MAIN THREAD LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool should_pause) : LLThread(name), - mThreaded(threaded), mIdleThread(TRUE), mNextHandle(0), mStarted(FALSE), + mThreaded(threaded), mRequestQueue(name, 1024 * 1024) { + llassert(threaded); // not threaded implementation is deprecated mMainQueue = LL::WorkQueue::getInstance("mainloop"); if (mThreaded) @@ -138,14 +139,18 @@ S32 LLQueuedThread::updateQueue(F32 max_time_ms) if (mThreaded) { // schedule a call to threadedUpdate for every call to updateQueue - mRequestQueue.post([=]() - { - LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qt - update"); - mIdleThread = FALSE; - threadedUpdate(); - mIdleThread = TRUE; - } - ); + if (!isQuitting()) + { + mRequestQueue.post([=]() + { + LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qt - update"); + mIdleThread = FALSE; + threadedUpdate(); + mIdleThread = TRUE; + } + ); + } + if(getPending() > 0) { unpause(); diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index 466f98f9b2..39dfee3755 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -68,7 +68,12 @@ LLTimer* LLTimer::sTimer = NULL; void ms_sleep(U32 ms) { LL_PROFILE_ZONE_SCOPED; - std::this_thread::sleep_for(std::chrono::microseconds(ms)); + using TimePoint = std::chrono::steady_clock::time_point; + auto resume_time = TimePoint::clock::now() + std::chrono::milliseconds(ms); + while (TimePoint::clock::now() < resume_time) + { + std::this_thread::yield(); //note: don't use LLThread::yield here to avoid yielding for too long + } } U32 micro_sleep(U64 us, U32 max_yields) diff --git a/indra/llfilesystem/lllfsthread.cpp b/indra/llfilesystem/lllfsthread.cpp index 944e981ecf..dbb69cd605 100644 --- a/indra/llfilesystem/lllfsthread.cpp +++ b/indra/llfilesystem/lllfsthread.cpp @@ -45,8 +45,7 @@ void LLLFSThread::initClass(bool local_is_threaded) //static S32 LLLFSThread::updateClass(U32 ms_elapsed) { - sLocal->update((F32)ms_elapsed); - return sLocal->getPending(); + return sLocal->update((F32)ms_elapsed); } //static @@ -58,6 +57,7 @@ void LLLFSThread::cleanupClass() { sLocal->update(0); } + sLocal->shutdown(); delete sLocal; sLocal = NULL; } diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 1aace5f3e8..d8503396d7 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -68,14 +68,6 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* return handle; } -// Used by unit test only -// Returns the size of the mutex guarded list as an indication of sanity -S32 LLImageDecodeThread::tut_size() -{ - LLMutexLock lock(mCreationMutex); - return 0; -} - LLImageDecodeThread::Responder::~Responder() { } diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h index 4619ddd6a2..e0a94d2841 100644 --- a/indra/llimage/llimageworker.h +++ b/indra/llimage/llimageworker.h @@ -80,9 +80,6 @@ public: Responder* responder); S32 update(F32 max_time_ms); - // Used by unit tests to check the consistency of the thread instance - S32 tut_size(); - private: struct creation_info { diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp index 462dde9fb8..57d922b1a1 100644 --- a/indra/llimage/tests/llimageworker_test.cpp +++ b/indra/llimage/tests/llimageworker_test.cpp @@ -190,35 +190,10 @@ namespace tut template<> template<> void imagedecodethread_object_t::test<1>() - { - // Test a *non threaded* instance of the class - mThread = new LLImageDecodeThread(false); - ensure("LLImageDecodeThread: non threaded constructor failed", mThread != NULL); - // Test that we start with an empty list right at creation - ensure("LLImageDecodeThread: non threaded init state incorrect", mThread->tut_size() == 0); - // Insert something in the queue - bool done = false; - LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, 0, FALSE, new responder_test(&done)); - // Verifies we got a valid handle - ensure("LLImageDecodeThread: non threaded decodeImage(), returned handle is null", decodeHandle != 0); - // Verifies that we do now have something in the queued list - ensure("LLImageDecodeThread: non threaded decodeImage() insertion in threaded list failed", mThread->tut_size() == 1); - // Trigger queue handling "manually" (on a threaded instance, this is done on the thread loop) - S32 res = mThread->update(0); - // Verifies that we successfully handled the list - ensure("LLImageDecodeThread: non threaded update() list handling test failed", res == 0); - // Verifies that the list is now empty - ensure("LLImageDecodeThread: non threaded update() list emptying test failed", mThread->tut_size() == 0); - } - - template<> template<> - void imagedecodethread_object_t::test<2>() { // Test a *threaded* instance of the class mThread = new LLImageDecodeThread(true); ensure("LLImageDecodeThread: threaded constructor failed", mThread != NULL); - // Test that we start with an empty list right at creation - ensure("LLImageDecodeThread: threaded init state incorrect", mThread->tut_size() == 0); // Insert something in the queue bool done = false; LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, 0, FALSE, new responder_test(&done)); diff --git a/indra/llmessage/tests/llcoproceduremanager_test.cpp b/indra/llmessage/tests/llcoproceduremanager_test.cpp index 6424117ef3..78424a28c8 100644 --- a/indra/llmessage/tests/llcoproceduremanager_test.cpp +++ b/indra/llmessage/tests/llcoproceduremanager_test.cpp @@ -48,7 +48,7 @@ #pragma warning(disable: 4702) #endif -LLCoreHttpUtil::HttpCoroutineAdapter::HttpCoroutineAdapter(std::string const&, unsigned int, unsigned int) +LLCoreHttpUtil::HttpCoroutineAdapter::HttpCoroutineAdapter(std::string const&, unsigned int) { } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a172308d2a..d7ed2bb4df 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1680,16 +1680,20 @@ S32 LLAppViewer::updateTextureThreads(F32 max_time) void LLAppViewer::flushLFSIO() { - while (1) - { - S32 pending = LLLFSThread::updateClass(0); - if (!pending) - { - break; - } - LL_INFOS() << "Waiting for pending IO to finish: " << pending << LL_ENDL; - ms_sleep(100); - } + S32 pending = LLLFSThread::updateClass(0); + if (pending > 0) + { + LL_INFOS() << "Waiting for pending IO to finish: " << pending << LL_ENDL; + while (1) + { + pending = LLLFSThread::updateClass(0); + if (!pending) + { + break; + } + ms_sleep(100); + } + } } bool LLAppViewer::cleanup() @@ -2187,7 +2191,7 @@ bool LLAppViewer::initThreads() LLImage::initClass(gSavedSettings.getBOOL("TextureNewByteRange"),gSavedSettings.getS32("TextureReverseByteRange")); - LLLFSThread::initClass(enable_threads && false); + LLLFSThread::initClass(enable_threads && true); // TODO: fix crashes associated with this shutdo // Image decoding LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true); -- cgit v1.2.3 From 609476e607b18d303afa5f5b5eeabeca84f95d16 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 1 Jun 2022 09:25:16 -0500 Subject: SL-17484 More unit test pruning. Fix for crash when deleting textures. --- indra/llcommon/llqueuedthread.cpp | 5 +++++ indra/llimage/tests/llimageworker_test.cpp | 6 ------ indra/newview/llviewertexturelist.cpp | 6 +++++- 3 files changed, 10 insertions(+), 7 deletions(-) (limited to 'indra') diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index 60304fff75..155e32ebae 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -75,6 +75,11 @@ void LLQueuedThread::shutdown() unpause(); // MAIN THREAD if (mThreaded) { + if (mRequestQueue.size() == 0) + { + mRequestQueue.close(); + } + S32 timeout = 100; for ( ; timeout>0; timeout--) { diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp index 57d922b1a1..d36d35aba4 100644 --- a/indra/llimage/tests/llimageworker_test.cpp +++ b/indra/llimage/tests/llimageworker_test.cpp @@ -199,12 +199,6 @@ namespace tut LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, 0, FALSE, new responder_test(&done)); // Verifies we get back a valid handle ensure("LLImageDecodeThread: threaded decodeImage(), returned handle is null", decodeHandle != 0); - // Wait a little so to simulate the main thread doing something on its main loop... - ms_sleep(500); // 500 milliseconds - // Verifies that the responder has *not* been called yet in the meantime - ensure("LLImageDecodeThread: responder creation failed", done == false); - // Ask the thread to update: that means tells the queue to check itself and creates work requests - mThread->update(1); // Wait till the thread has time to handle the work order (though it doesn't do much per work order...) const U32 INCREMENT_TIME = 500; // 500 milliseconds const U32 MAX_TIME = 20 * INCREMENT_TIME; // Do the loop 20 times max, i.e. wait 10 seconds but no more diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 555355059a..ac036bce31 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1048,7 +1048,11 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time) { iter = mUUIDMap.begin(); } - entries.push_back(iter->second); + + if (iter->second->getGLTexture()) + { + entries.push_back(iter->second); + } ++iter; } } -- cgit v1.2.3 From 4261cbba783359e71b691d6e0e9477ce53f60251 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 1 Jun 2022 10:34:33 -0500 Subject: SL-17485 Add texture memory accounting for OS X --- indra/llrender/llimagegl.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++++ indra/llrender/llimagegl.h | 6 ++- 2 files changed, 92 insertions(+), 1 deletion(-) (limited to 'indra') diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 04974d9122..46f0e1d69e 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -53,6 +53,88 @@ const F32 MIN_TEXTURE_LIFETIME = 10.f; //assumes i is a power of 2 > 0 U32 wpo2(U32 i); + +#if LL_DARWIN +// texture memory accounting (for OS X) +static LLMutex sTexMemMutex; +static std::unordered_map sTextureAllocs; +static U64 sTextureBytes = 0; + +// track a texture alloc on the currently bound texture. +// asserts that no currently tracked alloc exists +static void alloc_tex_image(U32 width, U32 height, U32 pixformat) +{ + U32 texUnit = gGL.getCurrentTexUnitIndex(); + U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture(); + S32 size = LLImageGL::dataFormatBytes(pixformat, width, height); + + llassert(size >= 0); + + sTexMemMutex.lock(); + llassert(sTextureAllocs.find(texName) == sTextureAllocs.end()); + + sTextureAllocs[texName] = size; + sTextureBytes += size; + + sTexMemMutex.unlock(); +} + +// track texture free on given texName +static void free_tex_image(U32 texName) +{ + sTexMemMutex.lock(); + auto iter = sTextureAllocs.find(texName); + if (iter != sTextureAllocs.end()) + { + llassert(iter->second <= sTextureBytes); // sTextureBytes MUST NOT go below zero + + sTextureBytes -= iter->second; + + sTextureAllocs.erase(iter); + } + + sTexMemMutex.unlock(); +} + +// track texture free on given texNames +static void free_tex_images(U32 count, const U32* texNames) +{ + for (int i = 0; i < count; ++i) + { + free_tex_image(texNames[i]); + } +} + +// track texture free on currently bound texture +static void free_cur_tex_image() +{ + U32 texUnit = gGL.getCurrentTexUnitIndex(); + U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture(); + free_tex_image(texName); +} + +// static +U64 LLImageGL::getTextureBytesAllocated() +{ + return sTextureBytes; +} + +#else + +#define alloc_tex_image(width, height, pixformat) (void) width; (void) height; (void) pixformat; +#define free_tex_image(texName) (void) texName; +#define free_tex_images(count, texNames) (void) count; (void) texNames; +#define free_cur_tex_image() + +// static +U64 LLImageGL::getTextureBytesAllocated() +{ + // UNIMPLEMENTED OUTSIDE OF OS X, DO NOT CALL + llassert(false); + return 0; +} +#endif + //statics U32 LLImageGL::sUniqueCount = 0; @@ -217,6 +299,7 @@ S32 LLImageGL::dataFormatBits(S32 dataformat) case GL_RGBA: return 32; case GL_SRGB_ALPHA: return 32; case GL_BGRA: return 32; // Used for QuickTime media textures on the Mac + case GL_DEPTH_COMPONENT: return 24; default: LL_ERRS() << "LLImageGL::Unknown format: " << dataformat << LL_ENDL; return 0; @@ -1218,6 +1301,7 @@ void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures) { if (gGLManager.mInited) { + free_tex_images(numTextures, textures); glDeleteTextures(numTextures, textures); } } @@ -1340,7 +1424,10 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt stop_glerror(); { LL_PROFILE_ZONE_NAMED("glTexImage2D"); + + free_cur_tex_image(); glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); + alloc_tex_image(width, height, pixformat); } stop_glerror(); diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 1716338c0b..619421e68a 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -52,6 +52,10 @@ class LLImageGL : public LLRefCount { friend class LLTexUnit; public: + + // For OS X use only -- get an estimate of how many bytes have been allocated in vram for textures + static U64 getTextureBytesAllocated(); + // These 2 functions replace glGenTextures() and glDeleteTextures() static void generateTextures(S32 numTextures, U32 *textures); static void deleteTextures(S32 numTextures, const U32 *textures); @@ -162,7 +166,7 @@ public: void updatePickMask(S32 width, S32 height, const U8* data_in); BOOL getMask(const LLVector2 &tc); - void checkTexSize(bool forced = false) const ; + void checkTexSize(bool forced = false) const ; // Sets the addressing mode used to sample the texture // (such as wrapping, mirrored wrapping, and clamp) -- cgit v1.2.3 From f4473528eb3f37b4bec3c4cda2a83d9ca94ab133 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Wed, 1 Jun 2022 11:31:45 -0500 Subject: SL-17485 Remove unused members to make mac build happy. --- indra/newview/lltexturefetch.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'indra') diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index d811b32f4f..64ccbf5e4a 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -552,8 +552,6 @@ private: S32 mRequestedDiscard; S32 mLoadedDiscard; S32 mDecodedDiscard; - S32 mFullWidth; - S32 mFullHeight; LLFrameTimer mRequestedDeltaTimer; LLFrameTimer mFetchDeltaTimer; LLTimer mCacheReadTimer; -- cgit v1.2.3 From d7459d87e0b7507b3452aa4effa4dc97e06e8551 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 1 Jun 2022 21:26:29 +0300 Subject: SL-15312 Reverted accidentally deleted slurl handling --- indra/newview/llpanelprofile.cpp | 115 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) (limited to 'indra') diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 85f443635d..470f3fa17e 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -468,6 +468,121 @@ public: }; LLProfileHandler gProfileHandler; + +////////////////////////////////////////////////////////////////////////// +// LLAgentHandler + +class LLAgentHandler : public LLCommandHandler +{ +public: + // requires trusted browser to trigger + LLAgentHandler() : LLCommandHandler("agent", UNTRUSTED_THROTTLE) { } + + bool handle(const LLSD& params, const LLSD& query_map, + LLMediaCtrl* web) + { + if (params.size() < 2) return false; + LLUUID avatar_id; + if (!avatar_id.set(params[0], FALSE)) + { + return false; + } + + const std::string verb = params[1].asString(); + if (verb == "about") + { + LLAvatarActions::showProfile(avatar_id); + return true; + } + + if (verb == "inspect") + { + LLFloaterReg::showInstance("inspect_avatar", LLSD().with("avatar_id", avatar_id)); + return true; + } + + if (verb == "im") + { + LLAvatarActions::startIM(avatar_id); + return true; + } + + if (verb == "pay") + { + if (!LLUI::getInstance()->mSettingGroups["config"]->getBOOL("EnableAvatarPay")) + { + LLNotificationsUtil::add("NoAvatarPay", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit")); + return true; + } + + LLAvatarActions::pay(avatar_id); + return true; + } + + if (verb == "offerteleport") + { + LLAvatarActions::offerTeleport(avatar_id); + return true; + } + + if (verb == "requestfriend") + { + LLAvatarActions::requestFriendshipDialog(avatar_id); + return true; + } + + if (verb == "removefriend") + { + LLAvatarActions::removeFriendDialog(avatar_id); + return true; + } + + if (verb == "mute") + { + if (! LLAvatarActions::isBlocked(avatar_id)) + { + LLAvatarActions::toggleBlock(avatar_id); + } + return true; + } + + if (verb == "unmute") + { + if (LLAvatarActions::isBlocked(avatar_id)) + { + LLAvatarActions::toggleBlock(avatar_id); + } + return true; + } + + if (verb == "block") + { + if (params.size() > 2) + { + const std::string object_name = LLURI::unescape(params[2].asString()); + LLMute mute(avatar_id, object_name, LLMute::OBJECT); + LLMuteList::getInstance()->add(mute); + LLPanelBlockedList::showPanelAndSelect(mute.mID); + } + return true; + } + + if (verb == "unblock") + { + if (params.size() > 2) + { + const std::string object_name = params[2].asString(); + LLMute mute(avatar_id, object_name, LLMute::OBJECT); + LLMuteList::getInstance()->remove(mute); + } + return true; + } + return false; + } +}; +LLAgentHandler gAgentHandler; + + ///---------------------------------------------------------------------------- /// LLFloaterProfilePermissions ///---------------------------------------------------------------------------- -- cgit v1.2.3 From 3efe64619b772ce8cab596d7e74de48dcc7f6c20 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 2 Jun 2022 00:17:54 +0300 Subject: SL-15312 Confirm usaved changes dialog when closing floater --- indra/newview/llfloaterprofile.cpp | 59 +++++++++++- indra/newview/llfloaterprofile.h | 7 +- indra/newview/llpanelavatar.h | 3 + indra/newview/llpanelprofile.cpp | 101 ++++++++++++++++++++- indra/newview/llpanelprofile.h | 49 ++++++---- indra/newview/llpanelprofileclassifieds.cpp | 38 +++++++- indra/newview/llpanelprofileclassifieds.h | 67 +++----------- indra/newview/llpanelprofilepicks.cpp | 27 +++++- indra/newview/llpanelprofilepicks.h | 35 +++---- .../newview/skins/default/xui/en/notifications.xml | 40 +++++++- 10 files changed, 329 insertions(+), 97 deletions(-) (limited to 'indra') diff --git a/indra/newview/llfloaterprofile.cpp b/indra/newview/llfloaterprofile.cpp index 78920863e2..a4a9fe8410 100644 --- a/indra/newview/llfloaterprofile.cpp +++ b/indra/newview/llfloaterprofile.cpp @@ -28,9 +28,10 @@ #include "llfloaterprofile.h" +#include "llagent.h" //gAgent +#include "llnotificationsutil.h" #include "llpanelavatar.h" #include "llpanelprofile.h" -#include "llagent.h" //gAgent static const std::string PANEL_PROFILE_VIEW = "panel_profile_view"; @@ -65,6 +66,62 @@ BOOL LLFloaterProfile::postBuild() return TRUE; } +void LLFloaterProfile::onClickCloseBtn(bool app_quitting) +{ + if (!app_quitting) + { + if (mPanelProfile->hasUnpublishedClassifieds()) + { + LLNotificationsUtil::add("ProfileUnpublishedClassified", LLSD(), LLSD(), + boost::bind(&LLFloaterProfile::onUnsavedChangesCallback, this, _1, _2, false)); + } + else if (mPanelProfile->hasUnsavedChanges()) + { + LLNotificationsUtil::add("ProfileUnsavedChanges", LLSD(), LLSD(), + boost::bind(&LLFloaterProfile::onUnsavedChangesCallback, this, _1, _2, true)); + } + else + { + closeFloater(); + } + } + else + { + closeFloater(); + } +} + +void LLFloaterProfile::onUnsavedChangesCallback(const LLSD& notification, const LLSD& response, bool can_save) +{ + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (can_save) + { + // savable content + + if (option == 0) // Save + { + mPanelProfile->commitUnsavedChanges(); + closeFloater(); + } + if (option == 1) // Discard + { + closeFloater(); + } + // else cancel + } + else + { + // classifieds + + if (option == 0) // Ok + { + closeFloater(); + } + // else cancel + } + +} + void LLFloaterProfile::createPick(const LLPickData &data) { mPanelProfile->createPick(data); diff --git a/indra/newview/llfloaterprofile.h b/indra/newview/llfloaterprofile.h index 1d0450be9c..36023077d3 100644 --- a/indra/newview/llfloaterprofile.h +++ b/indra/newview/llfloaterprofile.h @@ -40,8 +40,11 @@ public: LLFloaterProfile(const LLSD& key); virtual ~LLFloaterProfile(); - /*virtual*/ void onOpen(const LLSD& key); - /*virtual*/ BOOL postBuild(); + BOOL postBuild() override; + + void onOpen(const LLSD& key) override; + void onClickCloseBtn(bool app_quitting = false) override; + void onUnsavedChangesCallback(const LLSD& notification, const LLSD& response, bool can_save); void createPick(const LLPickData &data); void showPick(const LLUUID& pick_id = LLUUID::null); diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 98fd97f00a..f182660c8e 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -140,6 +140,9 @@ public: bool getStarted() { return mLoadingState != PROFILE_INIT; } bool getIsLoaded() { return mLoadingState == PROFILE_LOADED; } + virtual bool hasUnsavedChanges() { return false; } + virtual void commitUnsavedChanges() {} + private: LLUUID mAvatarId; diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index 470f3fa17e..f608712133 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -600,6 +600,9 @@ public: void changed(U32 mask) override; // LLFriendObserver void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); + bool hasUnsavedChanges() { return mHasUnsavedPermChanges; } + + void onApplyRights(); private: void fillRightsData(); @@ -607,8 +610,6 @@ private: void confirmModifyRights(bool grant); void onCommitSeeOnlineRights(); void onCommitEditRights(); - - void onApplyRights(); void onCancel(); LLTextBase* mDescription; @@ -620,6 +621,7 @@ private: LLUUID mAvatarID; F32 mContextConeOpacity; + bool mHasUnsavedPermChanges; LLHandle mOwnerHandle; boost::signals2::connection mAvatarNameCacheConnection; @@ -629,6 +631,7 @@ LLFloaterProfilePermissions::LLFloaterProfilePermissions(LLView * owner, const L : LLFloater(LLSD()) , mAvatarID(avatar_id) , mContextConeOpacity(0.0f) + , mHasUnsavedPermChanges(false) , mOwnerHandle(owner->getHandle()) { buildFromFile("floater_profile_permissions.xml"); @@ -653,6 +656,7 @@ BOOL LLFloaterProfilePermissions::postBuild() mCancelBtn = getChild("perms_btn_cancel"); mOnlineStatus->setCommitCallback([this](LLUICtrl*, void*) { onCommitSeeOnlineRights(); }, nullptr); + mMapRights->setCommitCallback([this](LLUICtrl*, void*) { mHasUnsavedPermChanges = true; }, nullptr); mEditObjectRights->setCommitCallback([this](LLUICtrl*, void*) { onCommitEditRights(); }, nullptr); mOkBtn->setCommitCallback([this](LLUICtrl*, void*) { onApplyRights(); }, nullptr); mCancelBtn->setCommitCallback([this](LLUICtrl*, void*) { onCancel(); }, nullptr); @@ -723,10 +727,14 @@ void LLFloaterProfilePermissions::rightsConfirmationCallback(const LLSD& notific const LLSD& response) { S32 option = LLNotificationsUtil::getSelectedOption(notification, response); - if (option != 0) + if (option != 0) // canceled { mEditObjectRights->setValue(mEditObjectRights->getValue().asBoolean() ? FALSE : TRUE); } + else + { + mHasUnsavedPermChanges = true; + } } void LLFloaterProfilePermissions::confirmModifyRights(bool grant) @@ -759,6 +767,7 @@ void LLFloaterProfilePermissions::onCommitSeeOnlineRights() { mMapRights->setValue(FALSE); } + mHasUnsavedPermChanges = true; } void LLFloaterProfilePermissions::onCommitEditRights() @@ -823,6 +832,7 @@ void LLFloaterProfilePermissions::onCancel() LLPanelProfileSecondLife::LLPanelProfileSecondLife() : LLPanelProfileTab() , mAvatarNameCacheConnection() + , mHasUnsavedDescriptionChanges(false) , mWaitingForImageUpload(false) , mAllowPublish(false) { @@ -1080,6 +1090,38 @@ void LLPanelProfileSecondLife::setProfileImageUploaded(const LLUUID &image_asset setProfileImageUploading(false); } +bool LLPanelProfileSecondLife::hasUnsavedChanges() +{ + LLFloater *floater = mFloaterPermissionsHandle.get(); + if (floater) + { + LLFloaterProfilePermissions* perm = dynamic_cast(floater); + if (perm && perm->hasUnsavedChanges()) + { + return true; + } + } + // if floater + return mHasUnsavedDescriptionChanges; +} + +void LLPanelProfileSecondLife::commitUnsavedChanges() +{ + LLFloater *floater = mFloaterPermissionsHandle.get(); + if (floater) + { + LLFloaterProfilePermissions* perm = dynamic_cast(floater); + if (perm && perm->hasUnsavedChanges()) + { + perm->onApplyRights(); + } + } + if (mHasUnsavedDescriptionChanges) + { + onSaveDescriptionChanges(); + } +} + void LLPanelProfileSecondLife::fillCommonData(const LLAvatarData* avatar_data) { // Refresh avatar id in cache with new info to prevent re-requests @@ -1608,6 +1650,8 @@ void LLPanelProfileSecondLife::setDescriptionText(const std::string &text) { mSaveDescriptionChanges->setEnabled(FALSE); mDiscardDescriptionChanges->setEnabled(FALSE); + mHasUnsavedDescriptionChanges = false; + mDescriptionText = text; mDescriptionEdit->setValue(mDescriptionText); } @@ -1616,6 +1660,7 @@ void LLPanelProfileSecondLife::onSetDescriptionDirty() { mSaveDescriptionChanges->setEnabled(TRUE); mDiscardDescriptionChanges->setEnabled(TRUE); + mHasUnsavedDescriptionChanges = true; } void LLPanelProfileSecondLife::onShowInSearchCallback() @@ -1656,6 +1701,7 @@ void LLPanelProfileSecondLife::onSaveDescriptionChanges() mSaveDescriptionChanges->setEnabled(FALSE); mDiscardDescriptionChanges->setEnabled(FALSE); + mHasUnsavedDescriptionChanges = false; } void LLPanelProfileSecondLife::onDiscardDescriptionChanges() @@ -1847,6 +1893,7 @@ void LLPanelProfileWeb::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent e LLPanelProfileFirstLife::LLPanelProfileFirstLife() : LLPanelProfileTab() + , mHasUnsavedChanges(false) { } @@ -1909,6 +1956,14 @@ void LLPanelProfileFirstLife::setProfileImageUploaded(const LLUUID &image_asset_ setProfileImageUploading(false); } +void LLPanelProfileFirstLife::commitUnsavedChanges() +{ + if (mHasUnsavedChanges) + { + onSaveDescriptionChanges(); + } +} + void LLPanelProfileFirstLife::onChangePhoto() { (new LLProfileImagePicker(PROFILE_IMAGE_FL, new LLHandle(getHandle())))->getFile(); @@ -1937,6 +1992,8 @@ void LLPanelProfileFirstLife::setDescriptionText(const std::string &text) { mSaveChanges->setEnabled(FALSE); mDiscardChanges->setEnabled(FALSE); + mHasUnsavedChanges = false; + mCurrentDescription = text; mDescriptionEdit->setValue(mCurrentDescription); } @@ -1945,6 +2002,7 @@ void LLPanelProfileFirstLife::onSetDescriptionDirty() { mSaveChanges->setEnabled(TRUE); mDiscardChanges->setEnabled(TRUE); + mHasUnsavedChanges = true; } void LLPanelProfileFirstLife::onSaveDescriptionChanges() @@ -1963,6 +2021,7 @@ void LLPanelProfileFirstLife::onSaveDescriptionChanges() mSaveChanges->setEnabled(FALSE); mDiscardChanges->setEnabled(FALSE); + mHasUnsavedChanges = false; } void LLPanelProfileFirstLife::onDiscardDescriptionChanges() @@ -2012,6 +2071,7 @@ void LLPanelProfileFirstLife::setLoaded() LLPanelProfileNotes::LLPanelProfileNotes() : LLPanelProfileTab() + , mHasUnsavedChanges(false) { } @@ -2036,6 +2096,14 @@ void LLPanelProfileNotes::updateData() } } +void LLPanelProfileNotes::commitUnsavedChanges() +{ + if (mHasUnsavedChanges) + { + onSaveNotesChanges(); + } +} + BOOL LLPanelProfileNotes::postBuild() { mNotesEditor = getChild("notes_edit"); @@ -2060,6 +2128,8 @@ void LLPanelProfileNotes::setNotesText(const std::string &text) { mSaveChanges->setEnabled(FALSE); mDiscardChanges->setEnabled(FALSE); + mHasUnsavedChanges = false; + mCurrentNotes = text; mNotesEditor->setValue(mCurrentNotes); } @@ -2068,6 +2138,7 @@ void LLPanelProfileNotes::onSetNotesDirty() { mSaveChanges->setEnabled(TRUE); mDiscardChanges->setEnabled(TRUE); + mHasUnsavedChanges = true; } void LLPanelProfileNotes::onSaveNotesChanges() @@ -2100,6 +2171,7 @@ void LLPanelProfileNotes::onSaveNotesChanges() mSaveChanges->setEnabled(FALSE); mDiscardChanges->setEnabled(FALSE); + mHasUnsavedChanges = false; } void LLPanelProfileNotes::onDiscardNotesChanges() @@ -2238,6 +2310,29 @@ bool LLPanelProfile::isNotesTabSelected() return (mTabContainer->getCurrentPanel() == mPanelNotes); } +bool LLPanelProfile::hasUnsavedChanges() +{ + return mPanelSecondlife->hasUnsavedChanges() + || mPanelPicks->hasUnsavedChanges() + || mPanelClassifieds->hasUnsavedChanges() + || mPanelFirstlife->hasUnsavedChanges() + || mPanelNotes->hasUnsavedChanges(); +} + +bool LLPanelProfile::hasUnpublishedClassifieds() +{ + return mPanelClassifieds->hasNewClassifieds(); +} + +void LLPanelProfile::commitUnsavedChanges() +{ + mPanelSecondlife->commitUnsavedChanges(); + mPanelPicks->commitUnsavedChanges(); + mPanelClassifieds->commitUnsavedChanges(); + mPanelFirstlife->commitUnsavedChanges(); + mPanelNotes->commitUnsavedChanges(); +} + void LLPanelProfile::showClassified(const LLUUID& classified_id, bool edit) { if (classified_id.notNull()) diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h index 4985ec0015..5b30a6c536 100644 --- a/indra/newview/llpanelprofile.h +++ b/indra/newview/llpanelprofile.h @@ -75,27 +75,27 @@ public: LLPanelProfileSecondLife(); /*virtual*/ ~LLPanelProfileSecondLife(); - /*virtual*/ void onOpen(const LLSD& key); + void onOpen(const LLSD& key) override; /** * LLFriendObserver trigger */ - virtual void changed(U32 mask); + void changed(U32 mask) override; // Implements LLVoiceClientStatusObserver::onChange() to enable the call // button when voice is available - /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + void onChange(EStatusType status, const std::string &channelURI, bool proximal) override; - /*virtual*/ void setAvatarId(const LLUUID& avatar_id); + void setAvatarId(const LLUUID& avatar_id) override; - /*virtual*/ BOOL postBuild(); + BOOL postBuild() override; void resetData(); /** * Sends update data request to server. */ - /*virtual*/ void updateData(); + void updateData() override; void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); @@ -103,6 +103,9 @@ public: void setProfileImageUploading(bool loading); void setProfileImageUploaded(const LLUUID &image_asset_id); + bool hasUnsavedChanges() override; + void commitUnsavedChanges() override; + friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); protected: @@ -171,7 +174,7 @@ protected: void processOnlineStatus(bool is_friend, bool show_online, bool online); private: - /*virtual*/ void setLoaded(); + void setLoaded() override; void onCommitMenu(const LLSD& userdata); bool onEnableMenu(const LLSD& userdata); bool onCheckMenu(const LLSD& userdata); @@ -208,6 +211,7 @@ private: LLHandle mFloaterPermissionsHandle; + bool mHasUnsavedDescriptionChanges; bool mVoiceStatus; bool mWaitingForImageUpload; bool mAllowPublish; @@ -270,9 +274,9 @@ public: LLPanelProfileFirstLife(); /*virtual*/ ~LLPanelProfileFirstLife(); - /*virtual*/ void onOpen(const LLSD& key); + void onOpen(const LLSD& key) override; - /*virtual*/ BOOL postBuild(); + BOOL postBuild() override; void processProperties(const LLAvatarData* avatar_data); @@ -281,10 +285,13 @@ public: void setProfileImageUploading(bool loading); void setProfileImageUploaded(const LLUUID &image_asset_id); + bool hasUnsavedChanges() override { return mHasUnsavedChanges; } + void commitUnsavedChanges() override; + friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); protected: - /*virtual*/ void setLoaded(); + void setLoaded() override; void onChangePhoto(); void onRemovePhoto(); @@ -301,6 +308,7 @@ protected: LLButton* mDiscardChanges; std::string mCurrentDescription; + bool mHasUnsavedChanges; }; /** @@ -313,17 +321,20 @@ public: LLPanelProfileNotes(); /*virtual*/ ~LLPanelProfileNotes(); - virtual void setAvatarId(const LLUUID& avatar_id); + void setAvatarId(const LLUUID& avatar_id) override; - /*virtual*/ void onOpen(const LLSD& key); + void onOpen(const LLSD& key) override; - /*virtual*/ BOOL postBuild(); + BOOL postBuild() override; void processProperties(LLAvatarNotes* avatar_notes); void resetData(); - /*virtual*/ void updateData(); + void updateData() override; + + bool hasUnsavedChanges() override { return mHasUnsavedChanges; } + void commitUnsavedChanges() override; protected: void setNotesText(const std::string &text); @@ -336,6 +347,7 @@ protected: LLButton* mDiscardChanges; std::string mCurrentNotes; + bool mHasUnsavedChanges; }; @@ -349,16 +361,19 @@ public: LLPanelProfile(); /*virtual*/ ~LLPanelProfile(); - /*virtual*/ BOOL postBuild(); + BOOL postBuild() override; - /*virtual*/ void updateData(); + void updateData() override; - /*virtual*/ void onOpen(const LLSD& key); + void onOpen(const LLSD& key) override; void createPick(const LLPickData &data); void showPick(const LLUUID& pick_id = LLUUID::null); bool isPickTabSelected(); bool isNotesTabSelected(); + bool hasUnsavedChanges() override; + bool hasUnpublishedClassifieds(); + void commitUnsavedChanges() override; void showClassified(const LLUUID& classified_id = LLUUID::null, bool edit = false); diff --git a/indra/newview/llpanelprofileclassifieds.cpp b/indra/newview/llpanelprofileclassifieds.cpp index 91243169a9..a961422dfe 100644 --- a/indra/newview/llpanelprofileclassifieds.cpp +++ b/indra/newview/llpanelprofileclassifieds.cpp @@ -287,11 +287,11 @@ void LLPanelProfileClassifieds::onClickDelete() { LLUUID classified_id = classified_panel->getClassifiedId(); LLSD args; - args["PICK"] = classified_panel->getClassifiedName(); + args["CLASSIFIED"] = classified_panel->getClassifiedName(); LLSD payload; payload["classified_id"] = classified_id; payload["tab_idx"] = mTabContainer->getCurrentPanelIndex(); - LLNotificationsUtil::add("DeleteAvatarPick", args, payload, + LLNotificationsUtil::add("ProfileDeleteClassified", args, payload, boost::bind(&LLPanelProfileClassifieds::callbackDeleteClassified, this, _1, _2)); } } @@ -417,6 +417,32 @@ void LLPanelProfileClassifieds::updateData() } } +bool LLPanelProfileClassifieds::hasNewClassifieds() +{ + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfileClassified* classified_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (classified_panel && classified_panel->isNew()) + { + return true; + } + } + return false; +} + +bool LLPanelProfileClassifieds::hasUnsavedChanges() +{ + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfileClassified* classified_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (classified_panel && classified_panel->isDirty()) // includes 'new' + { + return true; + } + } + return false; +} + bool LLPanelProfileClassifieds::canAddNewClassified() { return (mTabContainer->getTabCount() < MAX_AVATAR_CLASSIFIEDS); @@ -427,7 +453,7 @@ bool LLPanelProfileClassifieds::canDeleteClassified() return (mTabContainer->getTabCount() > 0); } -void LLPanelProfileClassifieds::apply() +void LLPanelProfileClassifieds::commitUnsavedChanges() { if (getIsLoaded()) { @@ -701,6 +727,7 @@ void LLPanelProfileClassified::processProperties(void* data, EAvatarProcessorTyp { // see LLPanelProfileClassified::sendUpdate() for notes mIsNewWithErrors = false; + mIsNew = false; setClassifiedName(c_info->name); setDescription(c_info->description); @@ -773,7 +800,10 @@ void LLPanelProfileClassified::updateButtons() mTeleportBtnCnt->setVisible(!edit_mode); mMapBtnCnt->setVisible(!edit_mode); mEditBtnCnt->setVisible(!edit_mode); - mCancelBtnCnt->setVisible(edit_mode); + + // cancel button should either delete unpublished + // classified or not be there at all + mCancelBtnCnt->setVisible(edit_mode && !mIsNew); mSaveBtnCnt->setVisible(edit_mode); mEditButton->setVisible(!edit_mode && getSelfProfile()); } diff --git a/indra/newview/llpanelprofileclassifieds.h b/indra/newview/llpanelprofileclassifieds.h index 368718e9dc..000c35a5a1 100644 --- a/indra/newview/llpanelprofileclassifieds.h +++ b/indra/newview/llpanelprofileclassifieds.h @@ -54,7 +54,7 @@ public: LLPublishClassifiedFloater(const LLSD& key); virtual ~LLPublishClassifiedFloater(); - /*virtual*/ BOOL postBuild(); + BOOL postBuild() override; void setPrice(S32 price); S32 getPrice(); @@ -74,21 +74,24 @@ public: LLPanelProfileClassifieds(); /*virtual*/ ~LLPanelProfileClassifieds(); - /*virtual*/ BOOL postBuild(); + BOOL postBuild() override; - /*virtual*/ void onOpen(const LLSD& key); + void onOpen(const LLSD& key) override; void selectClassified(const LLUUID& classified_id, bool edit); - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + void processProperties(void* data, EAvatarProcessorType type) override; - /*virtual*/ void resetData(); + void resetData() override; void updateButtons(); - /*virtual*/ void updateData(); + void updateData() override; - /*virtual*/ void apply(); + bool hasNewClassifieds(); + bool hasUnsavedChanges() override; + // commits changes to existing classifieds, but does not publish new classified! + void commitUnsavedChanges() override; private: void onClickNewBtn(); @@ -119,11 +122,11 @@ public: /*virtual*/ ~LLPanelProfileClassified(); - /*virtual*/ BOOL postBuild(); + BOOL postBuild() override; void onOpen(const LLSD& key); - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + void processProperties(void* data, EAvatarProcessorType type) override; void setSnapshotId(const LLUUID& id); @@ -165,9 +168,9 @@ public: void setInfoLoaded(bool loaded) { mInfoLoaded = loaded; } - /*virtual*/ BOOL isDirty() const; + BOOL isDirty() const override; - /*virtual*/ void resetDirty(); + void resetDirty() override; bool isNew() { return mIsNew; } @@ -209,7 +212,7 @@ public: protected: - /*virtual*/ void resetData(); + void resetData() override; void resetControls(); @@ -259,46 +262,6 @@ protected: void onTextureSelected(); - - - - /** - * Callback for "Map" button, opens Map - */ - void onClickMap(); - - /** - * Callback for "Teleport" button, teleports user to Pick location. - */ - void onClickTeleport(); - - /** - * Enables/disables "Save" button - */ - void enableSaveButton(BOOL enable); - - /** - * Called when snapshot image changes. - */ - void onSnapshotChanged(); - - /** - * Callback for Pick snapshot, name and description changed event. - */ - void onPickChanged(LLUICtrl* ctrl); - - /** - * Callback for "Set Location" button click - */ - void onClickSetLocation(); - - /** - * Callback for "Save" button click - */ - void onClickSave(); - - void onDescriptionFocusReceived(); - void updateTabLabel(const std::string& title); private: diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp index f5c0fb46c8..7142051f17 100644 --- a/indra/newview/llpanelprofilepicks.cpp +++ b/indra/newview/llpanelprofilepicks.cpp @@ -229,7 +229,7 @@ void LLPanelProfilePicks::onClickDelete() LLSD payload; payload["pick_id"] = pick_id; payload["tab_idx"] = mTabContainer->getCurrentPanelIndex(); - LLNotificationsUtil::add("DeleteAvatarPick", args, payload, + LLNotificationsUtil::add("ProfileDeletePick", args, payload, boost::bind(&LLPanelProfilePicks::callbackDeletePick, this, _1, _2)); } } @@ -400,6 +400,31 @@ void LLPanelProfilePicks::updateData() } } +bool LLPanelProfilePicks::hasUnsavedChanges() +{ + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfilePick* pick_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (pick_panel && (pick_panel->isDirty() || pick_panel->isDirty())) + { + return true; + } + } + return false; +} + +void LLPanelProfilePicks::commitUnsavedChanges() +{ + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfilePick* pick_panel = dynamic_cast(mTabContainer->getPanelByIndex(tab_idx)); + if (pick_panel) + { + pick_panel->apply(); + } + } +} + bool LLPanelProfilePicks::canAddNewPick() { return (!LLAgentPicksInfo::getInstance()->isPickLimitReached() && diff --git a/indra/newview/llpanelprofilepicks.h b/indra/newview/llpanelprofilepicks.h index e1c424ca24..d5df7b7f12 100644 --- a/indra/newview/llpanelprofilepicks.h +++ b/indra/newview/llpanelprofilepicks.h @@ -50,17 +50,17 @@ public: LLPanelProfilePicks(); /*virtual*/ ~LLPanelProfilePicks(); - /*virtual*/ BOOL postBuild(); + BOOL postBuild() override; - /*virtual*/ void onOpen(const LLSD& key); + void onOpen(const LLSD& key) override; void createPick(const LLPickData &data); void selectPick(const LLUUID& pick_id); - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + void processProperties(void* data, EAvatarProcessorType type) override; void processProperties(const LLAvatarPicks* avatar_picks); - /*virtual*/ void resetData(); + void resetData() override; void updateButtons(); @@ -72,7 +72,10 @@ public: /** * Sends update data request to server. */ - /*virtual*/ void updateData(); + void updateData() override; + + bool hasUnsavedChanges() override; + void commitUnsavedChanges() override; friend void request_avatar_properties_coro(std::string cap_url, LLUUID agent_id); @@ -107,7 +110,7 @@ public: /*virtual*/ ~LLPanelProfilePick(); - /*virtual*/ BOOL postBuild(); + BOOL postBuild() override; void setAvatarId(const LLUUID& avatar_id); @@ -117,9 +120,14 @@ public: virtual void setPickName(const std::string& name); const std::string getPickName(); - /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + void processProperties(void* data, EAvatarProcessorType type) override; void processProperties(const LLPickData* pick_data); + /** + * Returns true if any of Pick properties was changed by user. + */ + BOOL isDirty() const override; + /** * Saves changes. */ @@ -128,9 +136,9 @@ public: void updateTabLabel(const std::string& title); //This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing - /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); - /*virtual*/ void setParcelID(const LLUUID& parcel_id) { mParcelId = parcel_id; } - /*virtual*/ void setErrorStatus(S32 status, const std::string& reason) {}; + void processParcelInfo(const LLParcelData& parcel_data) override; + void setParcelID(const LLUUID& parcel_id) override { mParcelId = parcel_id; } + void setErrorStatus(S32 status, const std::string& reason) override {}; protected: @@ -191,12 +199,7 @@ protected: /** * Resets panel and all cantrols to unedited state */ - /*virtual*/ void resetDirty(); - - /** - * Returns true if any of Pick properties was changed by user. - */ - /*virtual*/ BOOL isDirty() const; + void resetDirty() override; /** * Callback for "Set Location" button click diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index aa93601669..5899e6df4e 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -1496,7 +1496,19 @@ Insufficient funds to create classified. +Delete classified <nolink>[CLASSIFIED]</nolink>? + confirm + + + + Delete pick <nolink>[PICK]</nolink>? confirm @@ -1506,6 +1518,32 @@ Delete pick <nolink>[PICK]</nolink>? yestext="OK"/> + + You have unpublished classifieds. They will be lost if you close the window. + confirm + + + + + You have usaved changes. + confirm + save + + + Date: Fri, 3 Jun 2022 01:41:25 +0300 Subject: SL-15312 Show user's sl birthday --- indra/newview/llpanelprofile.cpp | 18 ++++++++---- indra/newview/llpanelprofilepicks.cpp | 33 ++++++++++++++-------- .../default/xui/en/panel_profile_secondlife.xml | 19 +++++++++++-- 3 files changed, 51 insertions(+), 19 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp index f608712133..cb10dd75fb 100644 --- a/indra/newview/llpanelprofile.cpp +++ b/indra/newview/llpanelprofile.cpp @@ -1238,12 +1238,20 @@ void LLPanelProfileSecondLife::fillRightsData() void LLPanelProfileSecondLife::fillNameAgeData(const LLAvatarName &av_name, const LLDate &born_on) { - LLStringUtil::format_map_t args; - args["[AGE]"] = LLDateUtil::ageFromDate(born_on, LLDate::now()); - args["[NAME]"] = av_name.getAccountName(); - std::string register_date = getString("NameAgeFormat", args); - getChild("user_name_age")->setValue(register_date); getChild("display_name")->setValue(av_name.getDisplayName()); + + std::string name_and_date = getString("name_date_format"); + LLSD args_name; + args_name["datetime"] = (S32)born_on.secondsSinceEpoch(); + args_name["[NAME]"] = av_name.getAccountName(); + LLStringUtil::format(name_and_date, args_name); + getChild("user_name_date")->setValue(name_and_date); + + std::string register_date = getString("age_format"); + LLSD args_age; + args_age["[AGE]"] = LLDateUtil::ageFromDate(born_on, LLDate::now()); + LLStringUtil::format(register_date, args_age); + getChild("user_age")->setValue(register_date); } void LLPanelProfileSecondLife::onImageLoaded(BOOL success, LLViewerFetchedTexture *imagep) diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp index 7142051f17..69f6ac0407 100644 --- a/indra/newview/llpanelprofilepicks.cpp +++ b/indra/newview/llpanelprofilepicks.cpp @@ -152,16 +152,25 @@ void LLPanelProfilePicks::createPick(const LLPickData &data) { if (getIsLoaded()) { - mNoItemsLabel->setVisible(FALSE); - LLPanelProfilePick* pick_panel = LLPanelProfilePick::create(); - pick_panel->setAvatarId(getAvatarId()); - pick_panel->processProperties(&data); - mTabContainer->addTabPanel( - LLTabContainer::TabPanelParams(). - panel(pick_panel). - select_tab(true). - label(pick_panel->getPickName())); - updateButtons(); + if (canAddNewPick()) + { + mNoItemsLabel->setVisible(FALSE); + LLPanelProfilePick* pick_panel = LLPanelProfilePick::create(); + pick_panel->setAvatarId(getAvatarId()); + pick_panel->processProperties(&data); + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(pick_panel). + select_tab(true). + label(pick_panel->getPickName())); + updateButtons(); + } + else + { + // This means that something doesn't properly check limits + // before creating a pick + LL_WARNS() << "failed to add pick" << LL_ENDL; + } } else { @@ -313,7 +322,7 @@ void LLPanelProfilePicks::processProperties(const LLAvatarPicks* avatar_picks) } } - while (!mSheduledPickCreation.empty()) + while (!mSheduledPickCreation.empty() && canAddNewPick()) { const LLPickData data = mSheduledPickCreation.back(); @@ -331,6 +340,8 @@ void LLPanelProfilePicks::processProperties(const LLAvatarPicks* avatar_picks) has_selection = true; } + mSheduledPickCreation.clear(); + BOOL no_data = !mTabContainer->getTabCount(); mNoItemsLabel->setVisible(no_data); if (no_data) diff --git a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml index 7dd16de0ed..63136fd6a4 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_secondlife.xml @@ -10,8 +10,11 @@ layout="topleft" > + name="name_date_format" + value="[NAME], [mth,datetime,slt] [day,datetime,slt], [year,datetime,slt]" /> + @@ -99,7 +102,17 @@ Account: [ACCTTYPE] layout="topleft"/> + + Date: Fri, 3 Jun 2022 20:30:39 +0300 Subject: SL-15312 Updated classified's layout - better emphasis onto publsihing/saving button - better resize logic --- indra/newview/llpanelprofileclassifieds.cpp | 10 +- indra/newview/llpanelprofileclassifieds.h | 5 +- .../default/xui/en/panel_profile_classified.xml | 229 ++++++++++++++------- .../default/xui/en/panel_profile_classifieds.xml | 2 +- 4 files changed, 167 insertions(+), 79 deletions(-) (limited to 'indra') diff --git a/indra/newview/llpanelprofileclassifieds.cpp b/indra/newview/llpanelprofileclassifieds.cpp index a961422dfe..1cfe0b0a2b 100644 --- a/indra/newview/llpanelprofileclassifieds.cpp +++ b/indra/newview/llpanelprofileclassifieds.cpp @@ -579,9 +579,8 @@ BOOL LLPanelProfileClassified::postBuild() mSetLocationButton = getChild("set_to_curr_location_btn"); mCancelButton = getChild("cancel_btn"); - mTeleportBtnCnt = getChild("teleport_btn_lp"); - mMapBtnCnt = getChild("map_btn_lp"); - mEditBtnCnt = getChild("edit_btn_lp"); + mUtilityBtnCnt = getChild("util_buttons_lp"); + mPublishBtnsCnt = getChild("publish_layout_panel"); mCancelBtnCnt = getChild("cancel_btn_lp"); mSaveBtnCnt = getChild("save_btn_lp"); @@ -797,13 +796,12 @@ void LLPanelProfileClassified::setEditMode(BOOL edit_mode) void LLPanelProfileClassified::updateButtons() { bool edit_mode = getEditMode(); - mTeleportBtnCnt->setVisible(!edit_mode); - mMapBtnCnt->setVisible(!edit_mode); - mEditBtnCnt->setVisible(!edit_mode); + mUtilityBtnCnt->setVisible(!edit_mode); // cancel button should either delete unpublished // classified or not be there at all mCancelBtnCnt->setVisible(edit_mode && !mIsNew); + mPublishBtnsCnt->setVisible(edit_mode); mSaveBtnCnt->setVisible(edit_mode); mEditButton->setVisible(!edit_mode && getSelfProfile()); } diff --git a/indra/newview/llpanelprofileclassifieds.h b/indra/newview/llpanelprofileclassifieds.h index 000c35a5a1..e0ca75728f 100644 --- a/indra/newview/llpanelprofileclassifieds.h +++ b/indra/newview/llpanelprofileclassifieds.h @@ -291,9 +291,8 @@ private: LLButton* mSetLocationButton; LLButton* mCancelButton; - LLPanel* mMapBtnCnt; - LLPanel* mTeleportBtnCnt; - LLPanel* mEditBtnCnt; + LLPanel* mUtilityBtnCnt; + LLPanel* mPublishBtnsCnt; LLPanel* mSaveBtnCnt; LLPanel* mCancelBtnCnt; diff --git a/indra/newview/skins/default/xui/en/panel_profile_classified.xml b/indra/newview/skins/default/xui/en/panel_profile_classified.xml index e4627309b3..eb09240617 100644 --- a/indra/newview/skins/default/xui/en/panel_profile_classified.xml +++ b/indra/newview/skins/default/xui/en/panel_profile_classified.xml @@ -4,7 +4,7 @@ top="0" left="0" height="420" - width="325" + width="315" follows="all" layout="topleft" help_topic="panel_profile_classified" @@ -60,24 +60,43 @@ > Save - + + name="scroll_layout_panel" + auto_resize="true"> + - - + + + + name="util_buttons_lp" + auto_resize="true"> + + + + width="85">