From 187844d5fcc5c489a2112df464d2f5b9d1c28a33 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Fri, 15 Jul 2011 19:15:30 +0300
Subject: [PATCH] STORM-1506 FIXED Reset the estate to global sun when changing
 region environment settings.

By the way, moved estate info storage from the REGION/ESTATE floater to a model class.
---
 indra/newview/CMakeLists.txt          |   4 +-
 indra/newview/llestateinfomodel.cpp   | 230 ++++++++++++++++++
 indra/newview/llestateinfomodel.h     | 103 ++++++++
 indra/newview/llfloaterauction.cpp    |  15 +-
 indra/newview/llfloaterregioninfo.cpp | 336 +++++++-------------------
 indra/newview/llfloaterregioninfo.h   |  19 +-
 6 files changed, 423 insertions(+), 284 deletions(-)
 create mode 100644 indra/newview/llestateinfomodel.cpp
 create mode 100644 indra/newview/llestateinfomodel.h

diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index da9a145423..935dd2e887 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -150,8 +150,9 @@ set(viewer_SOURCE_FILES
     lldrawpoolwlsky.cpp
     lldriverparam.cpp
     lldynamictexture.cpp
-    llenvmanager.cpp
     llemote.cpp
+    llenvmanager.cpp
+    llestateinfomodel.cpp
     lleventnotifier.cpp
     lleventpoll.cpp
     llexpandabletextbox.cpp
@@ -711,6 +712,7 @@ set(viewer_HEADER_FILES
     lldynamictexture.h
     llemote.h
     llenvmanager.h
+    llestateinfomodel.h
     lleventnotifier.h
     lleventpoll.h
     llexpandabletextbox.h
diff --git a/indra/newview/llestateinfomodel.cpp b/indra/newview/llestateinfomodel.cpp
new file mode 100644
index 0000000000..7ed22d68f6
--- /dev/null
+++ b/indra/newview/llestateinfomodel.cpp
@@ -0,0 +1,230 @@
+/** 
+ * @file llestateinfomodel.cpp
+ * @brief Estate info model
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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 "llestateinfomodel.h"
+
+// libs
+#include "llhttpclient.h"
+#include "llregionflags.h"
+#include "message.h"
+
+// viewer
+#include "llagent.h"
+#include "llfloaterregioninfo.h" // for invoice id
+#include "llviewerregion.h"
+
+LLEstateInfoModel::LLEstateInfoModel()
+:	mID(0)
+,	mFlags(0)
+,	mSunHour(0)
+{
+}
+
+boost::signals2::connection LLEstateInfoModel::setUpdateCallback(const update_signal_t::slot_type& cb)
+{
+	return mUpdateSignal.connect(cb);
+}
+
+boost::signals2::connection LLEstateInfoModel::setCommitCallback(const update_signal_t::slot_type& cb)
+{
+	return mCommitSignal.connect(cb);
+}
+
+void LLEstateInfoModel::sendEstateInfo()
+{
+	if (!commitEstateInfoCaps())
+	{
+		// the caps method failed, try the old way
+		LLFloaterRegionInfo::nextInvoice();
+		commitEstateInfoDataserver();
+	}
+}
+
+bool LLEstateInfoModel::getUseFixedSun()			const {	return mFlags & REGION_FLAGS_SUN_FIXED;				}
+bool LLEstateInfoModel::getIsExternallyVisible()	const {	return mFlags & REGION_FLAGS_EXTERNALLY_VISIBLE;	}
+bool LLEstateInfoModel::getAllowDirectTeleport()	const {	return mFlags & REGION_FLAGS_ALLOW_DIRECT_TELEPORT;	}
+bool LLEstateInfoModel::getDenyAnonymous()			const {	return mFlags & REGION_FLAGS_DENY_ANONYMOUS; 		}
+bool LLEstateInfoModel::getDenyAgeUnverified()		const {	return mFlags & REGION_FLAGS_DENY_AGEUNVERIFIED;	}
+bool LLEstateInfoModel::getAllowVoiceChat()			const {	return mFlags & REGION_FLAGS_ALLOW_VOICE;			}
+
+void LLEstateInfoModel::setUseFixedSun(bool val)			{ setFlag(REGION_FLAGS_SUN_FIXED, 				val);	}
+void LLEstateInfoModel::setIsExternallyVisible(bool val)	{ setFlag(REGION_FLAGS_EXTERNALLY_VISIBLE,		val);	}
+void LLEstateInfoModel::setAllowDirectTeleport(bool val)	{ setFlag(REGION_FLAGS_ALLOW_DIRECT_TELEPORT,	val);	}
+void LLEstateInfoModel::setDenyAnonymous(bool val)			{ setFlag(REGION_FLAGS_DENY_ANONYMOUS,			val);	}
+void LLEstateInfoModel::setDenyAgeUnverified(bool val)		{ setFlag(REGION_FLAGS_DENY_AGEUNVERIFIED,		val);	}
+void LLEstateInfoModel::setAllowVoiceChat(bool val)			{ setFlag(REGION_FLAGS_ALLOW_VOICE,				val);	}
+
+void LLEstateInfoModel::update(const strings_t& strings)
+{
+	// NOTE: LLDispatcher extracts strings with an extra \0 at the
+	// end.  If we pass the std::string direct to the UI/renderer
+	// it draws with a weird character at the end of the string.
+	mName		= strings[0].c_str();
+	mOwnerID	= LLUUID(strings[1].c_str());
+	mID			= strtoul(strings[2].c_str(), NULL, 10);
+	mFlags		= strtoul(strings[3].c_str(), NULL, 10);
+	mSunHour	= ((F32)(strtod(strings[4].c_str(), NULL)))/1024.0f;
+
+	LL_DEBUGS("Windlight Sync") << "Received estate info: "
+		<< "is_sun_fixed = " << getUseFixedSun()
+		<< ", sun_hour = " << getSunHour() << LL_ENDL;
+	lldebugs << getInfoDump() << llendl;
+
+	// Update region owner.
+	LLViewerRegion* regionp = gAgent.getRegion();
+	regionp->setOwner(mOwnerID);
+
+	// Let interested parties know that estate info has been updated.
+	mUpdateSignal();
+}
+
+void LLEstateInfoModel::notifyCommit()
+{
+	mCommitSignal();
+}
+
+//== PRIVATE STUFF ============================================================
+
+class LLEstateChangeInfoResponder : public LLHTTPClient::Responder
+{
+public:
+
+	// if we get a normal response, handle it here
+	virtual void result(const LLSD& content)
+	{
+		llinfos << "Committed estate info" << llendl;
+		LLEstateInfoModel::instance().notifyCommit();
+	}
+
+	// if we get an error response
+	virtual void error(U32 status, const std::string& reason)
+	{
+		llwarns << "Failed to commit estate info (" << status << "): " << reason << llendl;
+	}
+};
+
+// tries to send estate info using a cap; returns true if it succeeded
+bool LLEstateInfoModel::commitEstateInfoCaps()
+{
+	std::string url = gAgent.getRegion()->getCapability("EstateChangeInfo");
+
+	if (url.empty())
+	{
+		// whoops, couldn't find the cap, so bail out
+		return false;
+	}
+
+	LLSD body;
+	body["estate_name"          ] = getName();
+	body["sun_hour"             ] = getSunHour();
+
+	body["is_sun_fixed"         ] = getUseFixedSun();
+	body["is_externally_visible"] = getIsExternallyVisible();
+	body["allow_direct_teleport"] = getAllowDirectTeleport();
+	body["deny_anonymous"       ] = getDenyAnonymous();
+	body["deny_age_unverified"  ] = getDenyAgeUnverified();
+	body["allow_voice_chat"     ] = getAllowVoiceChat();
+
+	body["invoice"              ] = LLFloaterRegionInfo::getLastInvoice();
+
+	LL_DEBUGS("Windlight Sync") << "Sending estate caps: "
+		<< "is_sun_fixed = " << getUseFixedSun()
+		<< ", sun_hour = " << getSunHour() << LL_ENDL;
+	lldebugs << body << LL_ENDL;
+
+	// we use a responder so that we can re-get the data after committing to the database
+	LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder);
+    return true;
+}
+
+/* This is the old way of doing things, is deprecated, and should be
+   deleted when the dataserver model can be removed */
+// key = "estatechangeinfo"
+// strings[0] = str(estate_id) (added by simulator before relay - not here)
+// strings[1] = estate_name
+// strings[2] = str(estate_flags)
+// strings[3] = str((S32)(sun_hour * 1024.f))
+void LLEstateInfoModel::commitEstateInfoDataserver()
+{
+	LL_DEBUGS("Windlight Sync") << "Sending estate info: "
+		<< "is_sun_fixed = " << getUseFixedSun()
+		<< ", sun_hour = " << getSunHour() << LL_ENDL;
+	lldebugs << getInfoDump() << LL_ENDL;
+
+	LLMessageSystem* msg = gMessageSystem;
+	msg->newMessage("EstateOwnerMessage");
+	msg->nextBlockFast(_PREHASH_AgentData);
+	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+	msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used
+
+	msg->nextBlock("MethodData");
+	msg->addString("Method", "estatechangeinfo");
+	msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice());
+
+	msg->nextBlock("ParamList");
+	msg->addString("Parameter", getName());
+
+	msg->nextBlock("ParamList");
+	msg->addString("Parameter", llformat("%u", getFlags()));
+
+	msg->nextBlock("ParamList");
+	msg->addString("Parameter", llformat("%d", (S32) (getSunHour() * 1024.0f)));
+
+	gAgent.sendMessage();
+}
+
+void LLEstateInfoModel::setFlag(U32 flag, bool val)
+{
+	if (val)
+	{
+		mFlags |= flag;
+	}
+	else
+	{
+		mFlags &= ~flag;
+	}
+}
+
+std::string LLEstateInfoModel::getInfoDump()
+{
+	LLSD dump;
+	dump["estate_name"          ] = getName();
+	dump["sun_hour"             ] = getSunHour();
+
+	dump["is_sun_fixed"         ] = getUseFixedSun();
+	dump["is_externally_visible"] = getIsExternallyVisible();
+	dump["allow_direct_teleport"] = getAllowDirectTeleport();
+	dump["deny_anonymous"       ] = getDenyAnonymous();
+	dump["deny_age_unverified"  ] = getDenyAgeUnverified();
+	dump["allow_voice_chat"     ] = getAllowVoiceChat();
+
+	std::stringstream dump_str;
+	dump_str << dump;
+	return dump_str.str();
+}
diff --git a/indra/newview/llestateinfomodel.h b/indra/newview/llestateinfomodel.h
new file mode 100644
index 0000000000..56391eda91
--- /dev/null
+++ b/indra/newview/llestateinfomodel.h
@@ -0,0 +1,103 @@
+/** 
+ * @file llestateinfomodel.h
+ * @brief Estate info model
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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_LLESTATEINFOMODEL_H
+#define LL_LLESTATEINFOMODEL_H
+
+class LLMessageSystem;
+
+#include "llsingleton.h"
+
+/**
+ * Contains estate info, notifies interested parties of its changes.
+ */
+class LLEstateInfoModel : public LLSingleton<LLEstateInfoModel>
+{
+	LOG_CLASS(LLEstateInfoModel);
+
+public:
+	typedef boost::signals2::signal<void()> update_signal_t;
+	boost::signals2::connection setUpdateCallback(const update_signal_t::slot_type& cb); /// the model has been externally updated
+	boost::signals2::connection setCommitCallback(const update_signal_t::slot_type& cb); /// our changes have been applied
+
+	void sendEstateInfo(); /// send estate info to the simulator
+
+	// getters
+	bool				getUseFixedSun()			const;
+	bool				getIsExternallyVisible()	const;
+	bool				getAllowDirectTeleport()	const;
+	bool				getDenyAnonymous()			const;
+	bool				getDenyAgeUnverified()		const;
+	bool				getAllowVoiceChat()			const;
+
+	const std::string&	getName()					const { return mName; }
+	const LLUUID&		getOwnerID()				const { return mOwnerID; }
+	U32					getID()						const { return mID; }
+	F32					getSunHour()				const { return getUseFixedSun() ? mSunHour : 0.f; }
+
+	// setters
+	void setUseFixedSun(bool val);
+	void setIsExternallyVisible(bool val);
+	void setAllowDirectTeleport(bool val);
+	void setDenyAnonymous(bool val);
+	void setDenyAgeUnverified(bool val);
+	void setAllowVoiceChat(bool val);
+
+	void setSunHour(F32 sun_hour) { mSunHour = sun_hour; }
+
+protected:
+	typedef std::vector<std::string> strings_t;
+
+	friend class LLSingleton<LLEstateInfoModel>;
+	friend class LLDispatchEstateUpdateInfo;
+	friend class LLEstateChangeInfoResponder;
+
+	LLEstateInfoModel();
+
+	/// refresh model with data from the incoming server message
+	void update(const strings_t& strings);
+
+	void notifyCommit();
+
+private:
+	bool commitEstateInfoCaps();
+	void commitEstateInfoDataserver();
+	U32  getFlags() const { return mFlags; }
+	void setFlag(U32 flag, bool val);
+	std::string getInfoDump();
+
+	// estate info
+	std::string	mName;			/// estate name
+	LLUUID		mOwnerID;		/// estate owner id
+	U32			mID;			/// estate id
+	U32			mFlags;			/// estate flags
+	F32			mSunHour;		/// estate sun hour
+
+	update_signal_t mUpdateSignal; /// emitted when we receive update from sim
+	update_signal_t mCommitSignal; /// emitted when our update gets applied to sim
+};
+
+#endif // LL_LLESTATEINFOMODEL_H
diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp
index c6743ca13b..2939d31087 100644
--- a/indra/newview/llfloaterauction.cpp
+++ b/indra/newview/llfloaterauction.cpp
@@ -27,7 +27,6 @@
 
 #include "llviewerprecompiledheaders.h"
 #include "llfloaterauction.h"
-#include "llfloaterregioninfo.h"
 
 #include "llgl.h"
 #include "llimagej2c.h"
@@ -40,6 +39,7 @@
 
 #include "llagent.h"
 #include "llcombobox.h"
+#include "llestateinfomodel.h"
 #include "llmimetypes.h"
 #include "llnotifications.h"
 #include "llnotificationsutil.h"
@@ -114,16 +114,9 @@ void LLFloaterAuction::initialize()
 		getChildView("reset_parcel_btn")->setEnabled(TRUE);
 		getChildView("start_auction_btn")->setEnabled(TRUE);
 
-		LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate();
-		if (panel)
-		{	// Only enable "Sell to Anyone" on Teen grid or if we don't know the ID yet
-			U32 estate_id = panel->getEstateID();
-			getChildView("sell_to_anyone_btn")->setEnabled((estate_id == ESTATE_TEEN || estate_id == 0));
-		}
-		else
-		{	// Don't have the panel up, so don't know if we're on the teen grid or not.  Default to enabling it
-			getChildView("sell_to_anyone_btn")->setEnabled(TRUE);
-		}
+		U32 estate_id = LLEstateInfoModel::instance().getID();
+		// Only enable "Sell to Anyone" on Teen grid or if we don't know the ID yet
+		getChildView("sell_to_anyone_btn")->setEnabled(estate_id == ESTATE_TEEN || estate_id == 0);
 	}
 	else
 	{
diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp
index bedc7ef704..538c5e3b88 100644
--- a/indra/newview/llfloaterregioninfo.cpp
+++ b/indra/newview/llfloaterregioninfo.cpp
@@ -54,6 +54,7 @@
 #include "llcombobox.h"
 #include "lldaycyclemanager.h"
 #include "llenvmanager.h"
+#include "llestateinfomodel.h"
 #include "llfilepicker.h"
 #include "llfloatergodtools.h"	// for send_sim_wide_deletes()
 #include "llfloatertopobjects.h" // added to fix SL-32336
@@ -1363,6 +1364,9 @@ LLPanelEstateInfo::LLPanelEstateInfo()
 :	LLPanelRegionInfo(),
 	mEstateID(0)	// invalid
 {
+	LLEstateInfoModel& estate_info = LLEstateInfoModel::instance();
+	estate_info.setCommitCallback(boost::bind(&LLPanelEstateInfo::refreshFromEstate, this));
+	estate_info.setUpdateCallback(boost::bind(&LLPanelEstateInfo::refreshFromEstate, this));
 }
 
 // static
@@ -1385,29 +1389,6 @@ void LLPanelEstateInfo::initDispatch(LLDispatcher& dispatch)
 	estate_dispatch_initialized = true;
 }
 
-#ifndef TMP_DISABLE_WLES
-// Disables the sun-hour slider and the use fixed time check if the use global time is check
-void LLPanelEstateInfo::onChangeUseGlobalTime()
-{
-	bool enabled = !getChild<LLUICtrl>("use_global_time_check")->getValue().asBoolean();
-	getChildView("sun_hour_slider")->setEnabled(enabled);
-	getChildView("fixed_sun_check")->setEnabled(enabled);
-	getChild<LLUICtrl>("fixed_sun_check")->setValue(LLSD(FALSE));
-	enableButton("apply_btn");
-}
-
-// Enables the sun-hour slider if the fixed-sun checkbox is set
-void LLPanelEstateInfo::onChangeFixedSun()
-{
-	bool enabled = !getChild<LLUICtrl>("fixed_sun_check")->getValue().asBoolean();
-	getChildView("use_global_time_check")->setEnabled(enabled);
-	getChild<LLUICtrl>("use_global_time_check")->setValue(LLSD(FALSE));
-	enableButton("apply_btn");
-}
-#endif // TMP_DISABLE_WLES
-
-
-
 //---------------------------------------------------------------------------
 // Add/Remove estate access button callbacks
 //---------------------------------------------------------------------------
@@ -1610,10 +1591,7 @@ std::string all_estates_text()
 // static
 bool LLPanelEstateInfo::isLindenEstate()
 {
-	LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate();
-	if (!panel) return false;
-
-	U32 estate_id = panel->getEstateID();
+	U32 estate_id = LLEstateInfoModel::instance().getID();
 	return (estate_id <= ESTATE_LAST_LINDEN);
 }
 
@@ -1975,7 +1953,7 @@ void LLPanelEstateInfo::updateControls(LLViewerRegion* region)
 	// Can't ban people from mainland, orientation islands, etc. because this
 	// creates much network traffic and server load.
 	// Disable their accounts in CSR tool instead.
-	bool linden_estate = (getEstateID() <= ESTATE_LAST_LINDEN);
+	bool linden_estate = isLindenEstate();
 	bool enable_ban = (god || owner || manager) && !linden_estate;
 	getChildView("add_banned_avatar_btn")->setEnabled(enable_ban);
 	getChildView("remove_banned_avatar_btn")->setEnabled(enable_ban);
@@ -1987,6 +1965,8 @@ void LLPanelEstateInfo::updateControls(LLViewerRegion* region)
 	getChildView("add_estate_manager_btn")->setEnabled(god || owner);
 	getChildView("remove_estate_manager_btn")->setEnabled(god || owner);
 	getChildView("estate_manager_name_list")->setEnabled(god || owner);
+
+	refresh();
 }
 
 bool LLPanelEstateInfo::refreshFromRegion(LLViewerRegion* region)
@@ -2093,10 +2073,13 @@ BOOL LLPanelEstateInfo::postBuild()
 
 void LLPanelEstateInfo::refresh()
 {
+	// Disable access restriction controls if they make no sense.
 	bool public_access = getChild<LLUICtrl>("externally_visible_check")->getValue().asBoolean();
+
 	getChildView("Only Allow")->setEnabled(public_access);
 	getChildView("limit_payment")->setEnabled(public_access);
 	getChildView("limit_age_verified")->setEnabled(public_access);
+
 	// if this is set to false, then the limit fields are meaningless and should be turned off
 	if (public_access == false)
 	{
@@ -2105,6 +2088,39 @@ void LLPanelEstateInfo::refresh()
 	}
 }
 
+void LLPanelEstateInfo::refreshFromEstate()
+{
+	const LLEstateInfoModel& estate_info = LLEstateInfoModel::instance();
+
+	getChild<LLUICtrl>("estate_name")->setValue(estate_info.getName());
+	setOwnerName(LLSLURL("agent", estate_info.getOwnerID(), "inspect").getSLURLString());
+
+	getChild<LLUICtrl>("externally_visible_check")->setValue(estate_info.getIsExternallyVisible());
+	getChild<LLUICtrl>("voice_chat_check")->setValue(estate_info.getAllowVoiceChat());
+	getChild<LLUICtrl>("allow_direct_teleport")->setValue(estate_info.getAllowDirectTeleport());
+	getChild<LLUICtrl>("limit_payment")->setValue(estate_info.getDenyAnonymous());
+	getChild<LLUICtrl>("limit_age_verified")->setValue(estate_info.getDenyAgeUnverified());
+
+	// If visible from mainland, disable the access allowed
+	// UI, as anyone can teleport there.
+	// However, gods need to be able to edit the access list for
+	// linden estates, regardless of visibility, to allow object
+	// and L$ transfers.
+	{
+		bool visible_from_mainland = estate_info.getIsExternallyVisible();
+		bool god = gAgent.isGodlike();
+		bool linden_estate = isLindenEstate();
+
+		bool enable_agent = (!visible_from_mainland || (god && linden_estate));
+		bool enable_group = enable_agent;
+		bool enable_ban = !linden_estate;
+
+		setAccessAllowedEnabled(enable_agent, enable_group, enable_ban);
+	}
+
+	refresh();
+}
+
 BOOL LLPanelEstateInfo::sendUpdate()
 {
 	llinfos << "LLPanelEsateInfo::sendUpdate()" << llendl;
@@ -2112,7 +2128,7 @@ BOOL LLPanelEstateInfo::sendUpdate()
 	LLNotification::Params params("ChangeLindenEstate");
 	params.functor.function(boost::bind(&LLPanelEstateInfo::callbackChangeLindenEstate, this, _1, _2));
 
-	if (getEstateID() <= ESTATE_LAST_LINDEN)
+	if (isLindenEstate())
 	{
 		// trying to change reserved estate, warn
 		LLNotifications::instance().add(params);
@@ -2131,13 +2147,21 @@ bool LLPanelEstateInfo::callbackChangeLindenEstate(const LLSD& notification, con
 	switch(option)
 	{
 	case 0:
-		// send the update
-		if (!commitEstateInfoCaps())
 		{
-			// the caps method failed, try the old way
-			LLFloaterRegionInfo::nextInvoice();
-			commitEstateInfoDataserver();
+			LLEstateInfoModel& estate_info = LLEstateInfoModel::instance();
+
+			// update model
+			estate_info.setUseFixedSun(false); // we don't support fixed sun estates anymore
+			estate_info.setIsExternallyVisible(getChild<LLUICtrl>("externally_visible_check")->getValue().asBoolean());
+			estate_info.setAllowDirectTeleport(getChild<LLUICtrl>("allow_direct_teleport")->getValue().asBoolean());
+			estate_info.setDenyAnonymous(getChild<LLUICtrl>("limit_payment")->getValue().asBoolean());
+			estate_info.setDenyAgeUnverified(getChild<LLUICtrl>("limit_age_verified")->getValue().asBoolean());
+			estate_info.setAllowVoiceChat(getChild<LLUICtrl>("voice_chat_check")->getValue().asBoolean());
+
+			// send the update to sim
+			estate_info.sendEstateInfo();
 		}
+
 		// we don't want to do this because we'll get it automatically from the sim
 		// after the spaceserver processes it
 //		else
@@ -2194,6 +2218,8 @@ public:
 	// if we get a normal response, handle it here
 	virtual void result(const LLSD& content)
 	{
+		LL_INFOS("Windlight") << "Successfully committed estate info" << llendl;
+
 	    // refresh the panel from the database
 		LLPanelEstateInfo* panel = dynamic_cast<LLPanelEstateInfo*>(mpPanel.get());
 		if (panel)
@@ -2210,178 +2236,6 @@ private:
 	LLHandle<LLPanel> mpPanel;
 };
 
-// tries to send estate info using a cap; returns true if it succeeded
-bool LLPanelEstateInfo::commitEstateInfoCaps()
-{
-	std::string url = gAgent.getRegion()->getCapability("EstateChangeInfo");
-	
-	if (url.empty())
-	{
-		// whoops, couldn't find the cap, so bail out
-		return false;
-	}
-	
-	LLSD body;
-	body["estate_name"] = getEstateName();
-
-	body["is_externally_visible"] = getChild<LLUICtrl>("externally_visible_check")->getValue().asBoolean();
-	body["allow_direct_teleport"] = getChild<LLUICtrl>("allow_direct_teleport")->getValue().asBoolean();
-	body["deny_anonymous"       ] = getChild<LLUICtrl>("limit_payment")->getValue().asBoolean();
-	body["deny_age_unverified"  ] = getChild<LLUICtrl>("limit_age_verified")->getValue().asBoolean();
-	body["allow_voice_chat"     ] = getChild<LLUICtrl>("voice_chat_check")->getValue().asBoolean();
-	body["invoice"              ] = LLFloaterRegionInfo::getLastInvoice();
-
-	// block fly is in estate database but not in estate UI, so we're not supporting it
-	//body["block_fly"            ] = getChild<LLUICtrl>("")->getValue().asBoolean();
-
-	F32 sun_hour = getSunHour();
-	if (getChild<LLUICtrl>("use_global_time_check")->getValue().asBoolean())
-	{
-		sun_hour = 0.f;			// 0 = global time
-	}
-	body["sun_hour"] = sun_hour;
-
-	// we use a responder so that we can re-get the data after committing to the database
-	LLHTTPClient::post(url, body, new LLEstateChangeInfoResponder(this));
-    return true;
-}
-
-/* This is the old way of doing things, is deprecated, and should be 
-   deleted when the dataserver model can be removed */
-// key = "estatechangeinfo"
-// strings[0] = str(estate_id) (added by simulator before relay - not here)
-// strings[1] = estate_name
-// strings[2] = str(estate_flags)
-// strings[3] = str((S32)(sun_hour * 1024.f))
-void LLPanelEstateInfo::commitEstateInfoDataserver()
-{
-	LLMessageSystem* msg = gMessageSystem;
-	msg->newMessage("EstateOwnerMessage");
-	msg->nextBlockFast(_PREHASH_AgentData);
-	msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-	msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-	msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used
-
-	msg->nextBlock("MethodData");
-	msg->addString("Method", "estatechangeinfo");
-	msg->addUUID("Invoice", LLFloaterRegionInfo::getLastInvoice());
-
-	msg->nextBlock("ParamList");
-	msg->addString("Parameter", getEstateName());
-
-	std::string buffer;
-	buffer = llformat("%u", computeEstateFlags());
-	msg->nextBlock("ParamList");
-	msg->addString("Parameter", buffer);
-
-	F32 sun_hour = getSunHour();
-	if (getChild<LLUICtrl>("use_global_time_check")->getValue().asBoolean())
-	{
-		sun_hour = 0.f;	// 0 = global time
-	}
-
-	buffer = llformat("%d", (S32)(sun_hour*1024.0f));
-	msg->nextBlock("ParamList");
-	msg->addString("Parameter", buffer);
-
-	gAgent.sendMessage();
-}
-
-void LLPanelEstateInfo::setEstateFlags(U32 flags)
-{
-	getChild<LLUICtrl>("externally_visible_check")->setValue(LLSD(flags & REGION_FLAGS_EXTERNALLY_VISIBLE ? TRUE : FALSE) );
-	getChild<LLUICtrl>("voice_chat_check")->setValue(
-		LLSD(flags & REGION_FLAGS_ALLOW_VOICE ? TRUE : FALSE));
-	getChild<LLUICtrl>("allow_direct_teleport")->setValue(LLSD(flags & REGION_FLAGS_ALLOW_DIRECT_TELEPORT ? TRUE : FALSE) );
-	getChild<LLUICtrl>("limit_payment")->setValue(LLSD(flags & REGION_FLAGS_DENY_ANONYMOUS ? TRUE : FALSE) );
-	getChild<LLUICtrl>("limit_age_verified")->setValue(LLSD(flags & REGION_FLAGS_DENY_AGEUNVERIFIED ? TRUE : FALSE) );
-
-	refresh();
-}
-
-U32 LLPanelEstateInfo::computeEstateFlags()
-{
-	U32 flags = 0;
-
-	if (getChild<LLUICtrl>("externally_visible_check")->getValue().asBoolean())
-	{
-		flags |= REGION_FLAGS_EXTERNALLY_VISIBLE;
-	}
-
-	if ( getChild<LLUICtrl>("voice_chat_check")->getValue().asBoolean() )
-	{
-		flags |= REGION_FLAGS_ALLOW_VOICE;
-	}
-	
-	if (getChild<LLUICtrl>("allow_direct_teleport")->getValue().asBoolean())
-	{
-		flags |= REGION_FLAGS_ALLOW_DIRECT_TELEPORT;
-	}
-
-	if (getChild<LLUICtrl>("limit_payment")->getValue().asBoolean())
-	{
-		flags |= REGION_FLAGS_DENY_ANONYMOUS;
-	}
-	
-	if (getChild<LLUICtrl>("limit_age_verified")->getValue().asBoolean())
-	{
-		flags |= REGION_FLAGS_DENY_AGEUNVERIFIED;
-	}
-
-	
-	return flags;
-}
-
-BOOL LLPanelEstateInfo::getGlobalTime()
-{
-	return getChild<LLUICtrl>("use_global_time_check")->getValue().asBoolean();
-}
-
-void LLPanelEstateInfo::setGlobalTime(bool b)
-{
-	getChild<LLUICtrl>("use_global_time_check")->setValue(LLSD(b));
-	getChildView("fixed_sun_check")->setEnabled(LLSD(!b));
-	getChildView("sun_hour_slider")->setEnabled(LLSD(!b));
-	if (b)
-	{
-		getChild<LLUICtrl>("sun_hour_slider")->setValue(LLSD(0.f));
-	}
-}
-
-
-BOOL LLPanelEstateInfo::getFixedSun()
-{
-	return getChild<LLUICtrl>("fixed_sun_check")->getValue().asBoolean();
-}
-
-void LLPanelEstateInfo::setSunHour(F32 sun_hour)
-{
-	if(sun_hour < 6.0f)
-	{
-		sun_hour = 24.0f + sun_hour;
-	}
-	getChild<LLUICtrl>("sun_hour_slider")->setValue(LLSD(sun_hour));
-}
-
-F32 LLPanelEstateInfo::getSunHour()
-{
-	if (getChildView("sun_hour_slider")->getEnabled())
-	{
-		return (F32)getChild<LLUICtrl>("sun_hour_slider")->getValue().asReal();
-	}
-	return 0.f;
-}
-
-const std::string LLPanelEstateInfo::getEstateName() const
-{
-	return getChild<LLUICtrl>("estate_name")->getValue().asString();
-}
-
-void LLPanelEstateInfo::setEstateName(const std::string& name)
-{
-	getChild<LLUICtrl>("estate_name")->setValue(LLSD(name));
-}
-
 const std::string LLPanelEstateInfo::getOwnerName() const
 {
 	return getChild<LLUICtrl>("estate_owner")->getValue().asString();
@@ -2884,55 +2738,10 @@ bool LLDispatchEstateUpdateInfo::operator()(
 {
 	lldebugs << "Received estate update" << llendl;
 
-	LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate();
-	if (!panel) return true;
-
-	// NOTE: LLDispatcher extracts strings with an extra \0 at the
-	// end.  If we pass the std::string direct to the UI/renderer
-	// it draws with a weird character at the end of the string.
-	std::string estate_name = strings[0].c_str(); // preserve c_str() call!
-	panel->setEstateName(estate_name);
-	
-	LLViewerRegion* regionp = gAgent.getRegion();
-
-	LLUUID owner_id(strings[1]);
-	regionp->setOwner(owner_id);
-	// Update estate owner name in UI
-	std::string owner_name = LLSLURL("agent", owner_id, "inspect").getSLURLString();
-	panel->setOwnerName(owner_name);
-
-	U32 estate_id = strtoul(strings[2].c_str(), NULL, 10);
-	panel->setEstateID(estate_id);
-
-	U32 flags = strtoul(strings[3].c_str(), NULL, 10);
-	panel->setEstateFlags(flags);
-
-	F32 sun_hour = ((F32)(strtod(strings[4].c_str(), NULL)))/1024.0f;
-	if(sun_hour == 0 && (flags & REGION_FLAGS_SUN_FIXED ? FALSE : TRUE))
-	{
-		lldebugs << "Estate uses global time" << llendl;
-		panel->setGlobalTime(TRUE);
-	} 
-	else
-	{
-		lldebugs << "Estate sun hour: " << sun_hour << llendl;
-		panel->setGlobalTime(FALSE);
-		panel->setSunHour(sun_hour);
-	}
-
-	bool visible_from_mainland = (bool)(flags & REGION_FLAGS_EXTERNALLY_VISIBLE);
-	bool god = gAgent.isGodlike();
-	bool linden_estate = (estate_id <= ESTATE_LAST_LINDEN);
-
-	// If visible from mainland, disable the access allowed
-	// UI, as anyone can teleport there.
-	// However, gods need to be able to edit the access list for
-	// linden estates, regardless of visibility, to allow object
-	// and L$ transfers.
-	bool enable_agent = (!visible_from_mainland || (god && linden_estate));
-	bool enable_group = enable_agent;
-	bool enable_ban = !linden_estate;
-	panel->setAccessAllowedEnabled(enable_agent, enable_group, enable_ban);
+	// Update estate info model.
+	// This will call LLPanelEstateInfo::refreshFromEstate().
+	// *TODO: Move estate message handling stuff to llestateinfomodel.cpp.
+	LLEstateInfoModel::instance().update(strings);
 
 	return true;
 }
@@ -3275,6 +3084,20 @@ void LLPanelEnvironmentInfo::sendRegionSunUpdate()
 	region_info.sendRegionTerrain(LLFloaterRegionInfo::getLastInvoice());
 }
 
+void LLPanelEnvironmentInfo::fixEstateSun()
+{
+	// We don't support fixed sun estates anymore and need to fix
+	// such estates for region day cycle to take effect.
+	// *NOTE: Assuming that current estate settings have arrived already.
+	LLEstateInfoModel& estate_info = LLEstateInfoModel::instance();
+	if (estate_info.getUseFixedSun())
+	{
+		llinfos << "Switching estate to global sun" << llendl;
+		estate_info.setUseFixedSun(false);
+		estate_info.sendEstateInfo();
+	}
+}
+
 void LLPanelEnvironmentInfo::populateWaterPresetsList()
 {
 	mWaterPresetCombo->removeall();
@@ -3668,6 +3491,9 @@ void LLPanelEnvironmentInfo::onRegionSettingsApplied(bool ok)
 		// That is caused by the simulator re-sending the region info, which in turn makes us
 		// re-request and display old region environment settings while the new ones haven't been applied yet.
 		sendRegionSunUpdate();
+
+		// Switch estate to not using fixed sun for the region day cycle to work properly (STORM-1506).
+		fixEstateSun();
 	}
 	else
 	{
diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h
index e7917c382c..c1fef57ac9 100644
--- a/indra/newview/llfloaterregioninfo.h
+++ b/indra/newview/llfloaterregioninfo.h
@@ -304,23 +304,9 @@ public:
 	virtual BOOL postBuild();
 	virtual void updateChild(LLUICtrl* child_ctrl);
 	virtual void refresh();
-	
-	U32 computeEstateFlags();
-	void setEstateFlags(U32 flags);
-	
-	BOOL getGlobalTime();
-	void setGlobalTime(bool b);
-
-	BOOL getFixedSun();				// *TODO: deprecated
 
-	F32 getSunHour();				// *TODO: deprecated
-	void setSunHour(F32 sun_hour);	// *TODO: deprecated
+	void refreshFromEstate();
 	
-	const std::string getEstateName() const;
-	void setEstateName(const std::string& name);
-
-	U32 getEstateID() const { return mEstateID; }
-	void setEstateID(U32 estate_id) { mEstateID = estate_id; }
 	static bool isLindenEstate();
 	
 	const std::string getOwnerName() const;
@@ -334,8 +320,6 @@ protected:
 	// confirmation dialog callback
 	bool callbackChangeLindenEstate(const LLSD& notification, const LLSD& response);
 
-	void commitEstateInfoDataserver();
-	bool commitEstateInfoCaps();
 	void commitEstateAccess();
 	void commitEstateManagers();
 	
@@ -434,6 +418,7 @@ private:
 	void setDirty(bool dirty);
 
 	void sendRegionSunUpdate();
+	void fixEstateSun();
 
 	void populateWaterPresetsList();
 	void populateSkyPresetsList();
-- 
GitLab