diff options
author | Ansariel <ansariel.hiller@phoenixviewer.com> | 2024-05-22 21:25:21 +0200 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2024-05-22 22:40:26 +0300 |
commit | e2e37cced861b98de8c1a7c9c0d3a50d2d90e433 (patch) | |
tree | 1bb897489ce524986f6196201c10ac0d8861aa5f /indra/newview/llfloaterbuyland.cpp | |
parent | 069ea06848f766466f1a281144c82a0f2bd79f3a (diff) |
Fix line endlings
Diffstat (limited to 'indra/newview/llfloaterbuyland.cpp')
-rw-r--r-- | indra/newview/llfloaterbuyland.cpp | 2758 |
1 files changed, 1379 insertions, 1379 deletions
diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index 2287900e5f..570a223908 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -1,1379 +1,1379 @@ -/**
- * @file llfloaterbuyland.cpp
- * @brief LLFloaterBuyLand 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$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llfloaterbuyland.h"
-
-// viewer includes
-#include "llagent.h"
-#include "llbutton.h"
-#include "llcachename.h"
-#include "llcheckboxctrl.h"
-#include "llcombobox.h"
-#include "llconfirmationmanager.h"
-#include "llcurrencyuimanager.h"
-#include "llfloater.h"
-#include "llfloaterreg.h"
-#include "llfloatertools.h"
-#include "llframetimer.h"
-#include "lliconctrl.h"
-#include "lllineeditor.h"
-#include "llnotificationsutil.h"
-#include "llparcel.h"
-#include "llslurl.h"
-#include "llstatusbar.h"
-#include "lltextbox.h"
-#include "lltexturectrl.h"
-#include "lltrans.h"
-#include "llviewchildren.h"
-#include "llviewercontrol.h"
-#include "lluictrlfactory.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerregion.h"
-#include "llviewertexteditor.h"
-#include "llviewerwindow.h"
-#include "llweb.h"
-#include "llwindow.h"
-#include "llworld.h"
-#include "llxmlrpctransaction.h"
-#include "llviewernetwork.h"
-#include "roles_constants.h"
-
-// NOTE: This is duplicated in lldatamoney.cpp ...
-const F32 GROUP_LAND_BONUS_FACTOR = 1.1f;
-
-class LLFloaterBuyLandUI
-: public LLFloater
-{
-public:
- LLFloaterBuyLandUI(const LLSD& key);
- virtual ~LLFloaterBuyLandUI();
-
- /*virtual*/ void onClose(bool app_quitting);
-
- // Left padding for maturity rating icon.
- static const S32 ICON_PAD = 2;
-
-private:
- class SelectionObserver : public LLParcelObserver
- {
- public:
- SelectionObserver(LLFloaterBuyLandUI* floater) : mFloater(floater) {}
- virtual void changed();
- private:
- LLFloaterBuyLandUI* mFloater;
- };
-
-private:
- SelectionObserver mParcelSelectionObserver;
- LLViewerRegion* mRegion;
- LLParcelSelectionHandle mParcel;
- bool mIsClaim;
- bool mIsForGroup;
-
- bool mCanBuy;
- bool mCannotBuyIsError;
- std::string mCannotBuyReason;
- std::string mCannotBuyURI;
-
- bool mBought;
-
- // information about the agent
- S32 mAgentCommittedTier;
- S32 mAgentCashBalance;
- bool mAgentHasNeverOwnedLand;
-
- // information about the parcel
- bool mParcelValid;
- bool mParcelIsForSale;
- bool mParcelIsGroupLand;
- S32 mParcelGroupContribution;
- S32 mParcelPrice;
- S32 mParcelActualArea;
- S32 mParcelBillableArea;
- S32 mParcelSupportedObjects;
- bool mParcelSoldWithObjects;
- std::string mParcelLocation;
- LLUUID mParcelSnapshot;
- std::string mParcelSellerName;
-
- // user's choices
- S32 mUserPlanChoice;
-
- // from website
- bool mSiteValid;
- bool mSiteMembershipUpgrade;
- std::string mSiteMembershipAction;
- std::vector<std::string>
- mSiteMembershipPlanIDs;
- std::vector<std::string>
- mSiteMembershipPlanNames;
- bool mSiteLandUseUpgrade;
- std::string mSiteLandUseAction;
- std::string mSiteConfirm;
-
- // values in current Preflight transaction... used to avoid extra
- // preflights when the parcel manager goes update crazy
- S32 mPreflightAskBillableArea;
- S32 mPreflightAskCurrencyBuy;
-
- LLViewChildren mChildren;
- LLCurrencyUIManager mCurrency;
-
- enum TransactionType
- {
- TransactionPreflight,
- TransactionCurrency,
- TransactionBuy
- };
- LLXMLRPCTransaction* mTransaction;
- TransactionType mTransactionType;
-
- LLViewerParcelMgr::ParcelBuyInfo* mParcelBuyInfo;
-
-public:
- void setForGroup(bool is_for_group);
- void setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel);
-
- void updateAgentInfo();
- void updateParcelInfo();
- void updateCovenantInfo();
- static void onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data);
- void updateFloaterCovenantText(const std::string& string, const LLUUID &asset_id);
- void updateFloaterEstateName(const std::string& name);
- void updateFloaterLastModified(const std::string& text);
- void updateFloaterEstateOwnerName(const std::string& name);
- void updateWebSiteInfo();
- void finishWebSiteInfo();
-
- void runWebSitePrep(const std::string& password);
- void finishWebSitePrep();
- void sendBuyLand();
-
- void updateNames();
- // Name cache callback
- void updateGroupName(const LLUUID& id,
- const std::string& name,
- bool is_group);
-
- void refreshUI();
-
- void startTransaction(TransactionType type, const LLXMLRPCValue& params);
- bool checkTransaction();
-
- void tellUserError(const std::string& message, const std::string& uri);
-
- virtual bool postBuild();
-
- void startBuyPreConfirm();
- void startBuyPostConfirm(const std::string& password);
-
- void onClickBuy();
- void onClickCancel();
- void onClickErrorWeb();
-
- virtual void draw();
- virtual bool canClose();
-
- void onVisibilityChanged ( const LLSD& new_visibility );
-
-};
-
-// static
-void LLFloaterBuyLand::buyLand(
- LLViewerRegion* region, LLParcelSelectionHandle parcel, bool is_for_group)
-{
- if(is_for_group && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED))
- {
- LLNotificationsUtil::add("OnlyOfficerCanBuyLand");
- return;
- }
-
- LLFloaterBuyLandUI* ui = LLFloaterReg::showTypedInstance<LLFloaterBuyLandUI>("buy_land");
- if (ui)
- {
- ui->setForGroup(is_for_group);
- ui->setParcel(region, parcel);
- }
-}
-
-// static
-void LLFloaterBuyLand::updateCovenantText(const std::string& string, const LLUUID &asset_id)
-{
- LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land");
- if (floater)
- {
- floater->updateFloaterCovenantText(string, asset_id);
- }
-}
-
-// static
-void LLFloaterBuyLand::updateEstateName(const std::string& name)
-{
- LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land");
- if (floater)
- {
- floater->updateFloaterEstateName(name);
- }
-}
-
-// static
-void LLFloaterBuyLand::updateLastModified(const std::string& text)
-{
- LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land");
- if (floater)
- {
- floater->updateFloaterLastModified(text);
- }
-}
-
-// static
-void LLFloaterBuyLand::updateEstateOwnerName(const std::string& name)
-{
- LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land");
- if (floater)
- {
- floater->updateFloaterEstateOwnerName(name);
- }
-}
-
-// static
-LLFloater* LLFloaterBuyLand::buildFloater(const LLSD& key)
-{
- LLFloaterBuyLandUI* floater = new LLFloaterBuyLandUI(key);
- return floater;
-}
-
-//----------------------------------------------------------------------------
-// LLFloaterBuyLandUI
-//----------------------------------------------------------------------------
-
-#if LL_WINDOWS
-// passing 'this' during construction generates a warning. The callee
-// only uses the pointer to hold a reference to 'this' which is
-// already valid, so this call does the correct thing. Disable the
-// warning so that we can compile without generating a warning.
-#pragma warning(disable : 4355)
-#endif
-LLFloaterBuyLandUI::LLFloaterBuyLandUI(const LLSD& key)
-: LLFloater(LLSD()),
- mParcelSelectionObserver(this),
- mParcel(0),
- mBought(false),
- mParcelValid(false), mSiteValid(false),
- mChildren(*this), mCurrency(*this), mTransaction(0),
- mParcelBuyInfo(0)
-{
- LLViewerParcelMgr::getInstance()->addObserver(&mParcelSelectionObserver);
-
-}
-
-LLFloaterBuyLandUI::~LLFloaterBuyLandUI()
-{
- LLViewerParcelMgr::getInstance()->removeObserver(&mParcelSelectionObserver);
- LLViewerParcelMgr::getInstance()->deleteParcelBuy(&mParcelBuyInfo);
-
- delete mTransaction;
-}
-
-// virtual
-void LLFloaterBuyLandUI::onClose(bool app_quitting)
-{
- // This object holds onto observer, transactions, and parcel state.
- // Despite being single_instance, destroy it to call destructors and clean
- // everything up.
- setVisible(false);
- destroy();
-}
-
-void LLFloaterBuyLandUI::SelectionObserver::changed()
-{
- if (LLViewerParcelMgr::getInstance()->selectionEmpty())
- {
- mFloater->closeFloater();
- }
- else
- {
- mFloater->setParcel(LLViewerParcelMgr::getInstance()->getSelectionRegion(),
- LLViewerParcelMgr::getInstance()->getParcelSelection());
- }
-}
-
-
-void LLFloaterBuyLandUI::updateAgentInfo()
-{
- mAgentCommittedTier = gStatusBar->getSquareMetersCommitted();
- mAgentCashBalance = gStatusBar->getBalance();
-
- // *TODO: This is an approximation, we should send this value down
- // to the viewer. See SL-10728 for details.
- mAgentHasNeverOwnedLand = mAgentCommittedTier == 0;
-}
-
-void LLFloaterBuyLandUI::updateParcelInfo()
-{
- LLParcel* parcel = mParcel->getParcel();
- mParcelValid = parcel && mRegion;
- mParcelIsForSale = false;
- mParcelIsGroupLand = false;
- mParcelGroupContribution = 0;
- mParcelPrice = 0;
- mParcelActualArea = 0;
- mParcelBillableArea = 0;
- mParcelSupportedObjects = 0;
- mParcelSoldWithObjects = false;
- mParcelLocation = "";
- mParcelSnapshot.setNull();
- mParcelSellerName = "";
-
- mCanBuy = false;
- mCannotBuyIsError = false;
-
- if (!mParcelValid)
- {
- mCannotBuyReason = getString("no_land_selected");
- return;
- }
-
- if (mParcel->getMultipleOwners())
- {
- mCannotBuyReason = getString("multiple_parcels_selected");
- return;
- }
-
- const LLUUID& parcelOwner = parcel->getOwnerID();
-
- mIsClaim = parcel->isPublic();
- if (!mIsClaim)
- {
- mParcelActualArea = parcel->getArea();
- mParcelIsForSale = parcel->getForSale();
- mParcelIsGroupLand = parcel->getIsGroupOwned();
- mParcelPrice = mParcelIsForSale ? parcel->getSalePrice() : 0;
-
- if (mParcelIsGroupLand)
- {
- LLUUID group_id = parcel->getGroupID();
- mParcelGroupContribution = gAgent.getGroupContribution(group_id);
- }
- }
- else
- {
- mParcelActualArea = mParcel->getClaimableArea();
- mParcelIsForSale = true;
- mParcelPrice = mParcelActualArea * parcel->getClaimPricePerMeter();
- }
-
- mParcelBillableArea =
- ll_round(mRegion->getBillableFactor() * mParcelActualArea);
-
- mParcelSupportedObjects = ll_round(
- parcel->getMaxPrimCapacity() * parcel->getParcelPrimBonus());
- // Can't have more than region max tasks, regardless of parcel
- // object bonus factor.
- LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
- if(region)
- {
- S32 max_tasks_per_region = (S32)region->getMaxTasks();
- mParcelSupportedObjects = llmin(
- mParcelSupportedObjects, max_tasks_per_region);
- }
-
- mParcelSoldWithObjects = parcel->getSellWithObjects();
-
-
- LLVector3 center = parcel->getCenterpoint();
- mParcelLocation = llformat("%s %d,%d",
- mRegion->getName().c_str(),
- (int)center[VX], (int)center[VY]
- );
-
- mParcelSnapshot = parcel->getSnapshotID();
-
- updateNames();
-
- bool haveEnoughCash = mParcelPrice <= mAgentCashBalance;
- S32 cashBuy = haveEnoughCash ? 0 : (mParcelPrice - mAgentCashBalance);
- mCurrency.setAmount(cashBuy, true);
- mCurrency.setZeroMessage(haveEnoughCash ? getString("none_needed") : LLStringUtil::null);
-
- // checks that we can buy the land
-
- if(mIsForGroup && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED))
- {
- mCannotBuyReason = getString("cant_buy_for_group");
- return;
- }
-
- if (!mIsClaim)
- {
- const LLUUID& authorizedBuyer = parcel->getAuthorizedBuyerID();
- const LLUUID buyer = gAgent.getID();
- const LLUUID newOwner = mIsForGroup ? gAgent.getGroupID() : buyer;
-
- if (!mParcelIsForSale
- || (mParcelPrice == 0 && authorizedBuyer.isNull()))
- {
-
- mCannotBuyReason = getString("parcel_not_for_sale");
- return;
- }
-
- if (parcelOwner == newOwner)
- {
- if (mIsForGroup)
- {
- mCannotBuyReason = getString("group_already_owns");
- }
- else
- {
- mCannotBuyReason = getString("you_already_own");
- }
- return;
- }
-
- if (!authorizedBuyer.isNull() && buyer != authorizedBuyer)
- {
- // Maybe the parcel is set for sale to a group we are in.
- bool authorized_group =
- gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_DEED)
- && gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_SET_SALE_INFO);
-
- if (!authorized_group)
- {
- mCannotBuyReason = getString("set_to_sell_to_other");
- return;
- }
- }
- }
- else
- {
- if (mParcelActualArea == 0)
- {
- mCannotBuyReason = getString("no_public_land");
- return;
- }
-
- if (mParcel->hasOthersSelected())
- {
- // Policy: Must not have someone else's land selected
- mCannotBuyReason = getString("not_owned_by_you");
- return;
- }
- }
-
- mCanBuy = true;
-}
-
-void LLFloaterBuyLandUI::updateCovenantInfo()
-{
- LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
- if(!region) return;
-
- U8 sim_access = region->getSimAccess();
- std::string rating = LLViewerRegion::accessToString(sim_access);
-
- LLTextBox* region_name = getChild<LLTextBox>("region_name_text");
- if (region_name)
- {
- std::string region_name_txt = region->getName() + " ("+rating +")";
- region_name->setText(region_name_txt);
-
- LLIconCtrl* rating_icon = getChild<LLIconCtrl>("rating_icon");
- LLRect rect = rating_icon->getRect();
- S32 region_name_width = llmin(region_name->getRect().getWidth(), region_name->getTextBoundingRect().getWidth());
- S32 icon_left_pad = region_name->getRect().mLeft + region_name_width + ICON_PAD;
- region_name->setToolTip(region_name->getText());
- rating_icon->setRect(rect.setOriginAndSize(icon_left_pad, rect.mBottom, rect.getWidth(), rect.getHeight()));
-
- switch(sim_access)
- {
- case SIM_ACCESS_PG:
- rating_icon->setValue(getString("icon_PG"));
- break;
-
- case SIM_ACCESS_ADULT:
- rating_icon->setValue(getString("icon_R"));
- break;
-
- default:
- rating_icon->setValue(getString("icon_M"));
- }
- }
-
- LLTextBox* region_type = getChild<LLTextBox>("region_type_text");
- if (region_type)
- {
- region_type->setText(region->getLocalizedSimProductName());
- region_type->setToolTip(region->getLocalizedSimProductName());
- }
-
- LLTextBox* resellable_clause = getChild<LLTextBox>("resellable_clause");
- if (resellable_clause)
- {
- if (region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL))
- {
- resellable_clause->setText(getString("can_not_resell"));
- }
- else
- {
- resellable_clause->setText(getString("can_resell"));
- }
- }
-
- LLTextBox* changeable_clause = getChild<LLTextBox>("changeable_clause");
- if (changeable_clause)
- {
- if (region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES))
- {
- changeable_clause->setText(getString("can_change"));
- }
- else
- {
- changeable_clause->setText(getString("can_not_change"));
- }
- }
-
- LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant");
- if(check)
- {
- check->set(false);
- check->setEnabled(true);
- check->setCommitCallback(onChangeAgreeCovenant, this);
- }
-
- LLTextBox* box = getChild<LLTextBox>("covenant_text");
- if(box)
- {
- box->setVisible(false);
- }
-
- // send EstateCovenantInfo message
- LLMessageSystem *msg = gMessageSystem;
- msg->newMessage("EstateCovenantRequest");
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
- msg->sendReliable(region->getHost());
-}
-
-// static
-void LLFloaterBuyLandUI::onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data)
-{
- LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)user_data;
- if(self)
- {
- self->refreshUI();
- }
-}
-
-void LLFloaterBuyLandUI::updateFloaterCovenantText(const std::string &string, const LLUUID& asset_id)
-{
- LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("covenant_editor");
- editor->setText(string);
-
- LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant");
- LLTextBox* box = getChild<LLTextBox>("covenant_text");
- if (asset_id.isNull())
- {
- check->set(true);
- check->setEnabled(false);
- refreshUI();
-
- // remove the line stating that you must agree
- box->setVisible(false);
- }
- else
- {
- check->setEnabled(true);
-
- // remove the line stating that you must agree
- box->setVisible(true);
- }
-}
-
-void LLFloaterBuyLandUI::updateFloaterEstateName(const std::string& name)
-{
- LLTextBox* box = getChild<LLTextBox>("estate_name_text");
- box->setText(name);
- box->setToolTip(name);
-}
-
-void LLFloaterBuyLandUI::updateFloaterLastModified(const std::string& text)
-{
- LLTextBox* editor = getChild<LLTextBox>("covenant_timestamp_text");
- if (editor) editor->setText(text);
-}
-
-void LLFloaterBuyLandUI::updateFloaterEstateOwnerName(const std::string& name)
-{
- LLTextBox* box = getChild<LLTextBox>("estate_owner_text");
- if (box) box->setText(name);
-}
-
-void LLFloaterBuyLandUI::updateWebSiteInfo()
-{
- S32 askBillableArea = mIsForGroup ? 0 : mParcelBillableArea;
- S32 askCurrencyBuy = mCurrency.getAmount();
-
- if (mTransaction && mTransactionType == TransactionPreflight
- && mPreflightAskBillableArea == askBillableArea
- && mPreflightAskCurrencyBuy == askCurrencyBuy)
- {
- return;
- }
-
- mPreflightAskBillableArea = askBillableArea;
- mPreflightAskCurrencyBuy = askCurrencyBuy;
-
-#if 0
- // enable this code if you want the details to blank while we're talking
- // to the web site... it's kind of jarring
- mSiteValid = false;
- mSiteMembershipUpgrade = false;
- mSiteMembershipAction = "(waiting)";
- mSiteMembershipPlanIDs.clear();
- mSiteMembershipPlanNames.clear();
- mSiteLandUseUpgrade = false;
- mSiteLandUseAction = "(waiting)";
- mSiteCurrencyEstimated = false;
- mSiteCurrencyEstimatedCost = 0;
-#endif
-
- LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
- keywordArgs.appendString("agentId", gAgent.getID().asString());
- keywordArgs.appendString(
- "secureSessionId",
- gAgent.getSecureSessionID().asString());
- keywordArgs.appendString("language", LLUI::getLanguage());
- keywordArgs.appendInt("billableArea", mPreflightAskBillableArea);
- keywordArgs.appendInt("currencyBuy", mPreflightAskCurrencyBuy);
-
- LLXMLRPCValue params = LLXMLRPCValue::createArray();
- params.append(keywordArgs);
-
- startTransaction(TransactionPreflight, params);
-}
-
-void LLFloaterBuyLandUI::finishWebSiteInfo()
-{
-
- LLXMLRPCValue result = mTransaction->responseValue();
-
- mSiteValid = result["success"].asBool();
- if (!mSiteValid)
- {
- tellUserError(
- result["errorMessage"].asString(),
- result["errorURI"].asString()
- );
- return;
- }
-
- LLXMLRPCValue membership = result["membership"];
- mSiteMembershipUpgrade = membership["upgrade"].asBool();
- mSiteMembershipAction = membership["action"].asString();
- mSiteMembershipPlanIDs.clear();
- mSiteMembershipPlanNames.clear();
- LLXMLRPCValue levels = membership["levels"];
- for (LLXMLRPCValue level = levels.rewind();
- level.isValid();
- level = levels.next())
- {
- mSiteMembershipPlanIDs.push_back(level["id"].asString());
- mSiteMembershipPlanNames.push_back(level["description"].asString());
- }
- mUserPlanChoice = 0;
-
- LLXMLRPCValue landUse = result["landUse"];
- mSiteLandUseUpgrade = landUse["upgrade"].asBool();
- mSiteLandUseAction = landUse["action"].asString();
-
- LLXMLRPCValue currency = result["currency"];
- if (currency["estimatedCost"].isValid())
- {
- mCurrency.setUSDEstimate(currency["estimatedCost"].asInt());
- }
- if (currency["estimatedLocalCost"].isValid())
- {
- mCurrency.setLocalEstimate(currency["estimatedLocalCost"].asString());
- }
-
- mSiteConfirm = result["confirm"].asString();
-}
-
-void LLFloaterBuyLandUI::runWebSitePrep(const std::string& password)
-{
- if (!mCanBuy)
- {
- return;
- }
-
- bool remove_contribution = getChild<LLUICtrl>("remove_contribution")->getValue().asBoolean();
- mParcelBuyInfo = LLViewerParcelMgr::getInstance()->setupParcelBuy(gAgent.getID(), gAgent.getSessionID(),
- gAgent.getGroupID(), mIsForGroup, mIsClaim, remove_contribution);
-
- if (mParcelBuyInfo
- && !mSiteMembershipUpgrade
- && !mSiteLandUseUpgrade
- && mCurrency.getAmount() == 0
- && mSiteConfirm != "password")
- {
- sendBuyLand();
- return;
- }
-
-
- std::string newLevel = "noChange";
-
- if (mSiteMembershipUpgrade)
- {
- LLComboBox* levels = getChild<LLComboBox>( "account_level");
- if (levels)
- {
- mUserPlanChoice = levels->getCurrentIndex();
- newLevel = mSiteMembershipPlanIDs[mUserPlanChoice];
- }
- }
-
- LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
- keywordArgs.appendString("agentId", gAgent.getID().asString());
- keywordArgs.appendString(
- "secureSessionId",
- gAgent.getSecureSessionID().asString());
- keywordArgs.appendString("language", LLUI::getLanguage());
- keywordArgs.appendString("levelId", newLevel);
- keywordArgs.appendInt("billableArea",
- mIsForGroup ? 0 : mParcelBillableArea);
- keywordArgs.appendInt("currencyBuy", mCurrency.getAmount());
- keywordArgs.appendInt("estimatedCost", mCurrency.getUSDEstimate());
- keywordArgs.appendString("estimatedLocalCost", mCurrency.getLocalEstimate());
- keywordArgs.appendString("confirm", mSiteConfirm);
- if (!password.empty())
- {
- keywordArgs.appendString("password", password);
- }
-
- LLXMLRPCValue params = LLXMLRPCValue::createArray();
- params.append(keywordArgs);
-
- startTransaction(TransactionBuy, params);
-}
-
-void LLFloaterBuyLandUI::finishWebSitePrep()
-{
- LLXMLRPCValue result = mTransaction->responseValue();
-
- bool success = result["success"].asBool();
- if (!success)
- {
- tellUserError(
- result["errorMessage"].asString(),
- result["errorURI"].asString()
- );
- return;
- }
-
- sendBuyLand();
-}
-
-void LLFloaterBuyLandUI::sendBuyLand()
-{
- if (mParcelBuyInfo)
- {
- LLViewerParcelMgr::getInstance()->sendParcelBuy(mParcelBuyInfo);
- LLViewerParcelMgr::getInstance()->deleteParcelBuy(&mParcelBuyInfo);
- mBought = true;
- }
-}
-
-void LLFloaterBuyLandUI::updateNames()
-{
- LLParcel* parcelp = mParcel->getParcel();
-
- if (!parcelp)
- {
- mParcelSellerName = LLStringUtil::null;
- return;
- }
-
- if (mIsClaim)
- {
- mParcelSellerName = "Linden Lab";
- }
- else if (parcelp->getIsGroupOwned())
- {
- gCacheName->getGroup(parcelp->getGroupID(),
- boost::bind(&LLFloaterBuyLandUI::updateGroupName, this,
- _1, _2, _3));
- }
- else
- {
- mParcelSellerName = LLSLURL("agent", parcelp->getOwnerID(), "completename").getSLURLString();
- }
-}
-
-void LLFloaterBuyLandUI::updateGroupName(const LLUUID& id,
- const std::string& name,
- bool is_group)
-{
- LLParcel* parcelp = mParcel->getParcel();
- if (parcelp
- && parcelp->getGroupID() == id)
- {
- // request is current
- mParcelSellerName = name;
- }
-}
-
-void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCValue& params)
-{
- delete mTransaction;
- mTransaction = NULL;
-
- mTransactionType = type;
-
- // Select a URI and method appropriate for the transaction type.
- static std::string transaction_uri;
- if (transaction_uri.empty())
- {
- transaction_uri = LLGridManager::getInstance()->getHelperURI() + "landtool.php";
- }
-
- const char* method;
- switch (mTransactionType)
- {
- case TransactionPreflight:
- method = "preflightBuyLandPrep";
- break;
- case TransactionBuy:
- method = "buyLandPrep";
- break;
- default:
- LL_WARNS() << "LLFloaterBuyLandUI: Unknown transaction type!" << LL_ENDL;
- return;
- }
-
- mTransaction = new LLXMLRPCTransaction(
- transaction_uri,
- method,
- params,
- false /* don't use gzip */
- );
-}
-
-bool LLFloaterBuyLandUI::checkTransaction()
-{
- if (!mTransaction)
- {
- return false;
- }
-
- if (!mTransaction->process())
- {
- return false;
- }
-
- if (mTransaction->status(NULL) != LLXMLRPCTransaction::StatusComplete)
- {
- tellUserError(mTransaction->statusMessage(), mTransaction->statusURI());
- }
- else {
- switch (mTransactionType)
- {
- case TransactionPreflight: finishWebSiteInfo(); break;
- case TransactionBuy: finishWebSitePrep(); break;
- default: ;
- }
- }
-
- delete mTransaction;
- mTransaction = NULL;
-
- return true;
-}
-
-void LLFloaterBuyLandUI::tellUserError(
- const std::string& message, const std::string& uri)
-{
- mCanBuy = false;
- mCannotBuyIsError = true;
- mCannotBuyReason = getString("fetching_error");
- mCannotBuyReason += message;
- mCannotBuyURI = uri;
-}
-
-
-// virtual
-bool LLFloaterBuyLandUI::postBuild()
-{
- setVisibleCallback(boost::bind(&LLFloaterBuyLandUI::onVisibilityChanged, this, _2));
-
- mCurrency.prepare();
-
- getChild<LLUICtrl>("buy_btn")->setCommitCallback( boost::bind(&LLFloaterBuyLandUI::onClickBuy, this));
- getChild<LLUICtrl>("cancel_btn")->setCommitCallback( boost::bind(&LLFloaterBuyLandUI::onClickCancel, this));
- getChild<LLUICtrl>("error_web")->setCommitCallback( boost::bind(&LLFloaterBuyLandUI::onClickErrorWeb, this));
-
- center();
-
- return true;
-}
-
-void LLFloaterBuyLandUI::setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel)
-{
- if (mTransaction && mTransactionType == TransactionBuy)
- {
- // the user is buying, don't change the selection
- return;
- }
-
- mRegion = region;
- mParcel = parcel;
-
- updateAgentInfo();
- updateParcelInfo();
- updateCovenantInfo();
- if (mCanBuy)
- {
- updateWebSiteInfo();
- }
- refreshUI();
-}
-
-void LLFloaterBuyLandUI::setForGroup(bool forGroup)
-{
- mIsForGroup = forGroup;
-}
-
-void LLFloaterBuyLandUI::draw()
-{
- LLFloater::draw();
-
- bool needsUpdate = false;
- needsUpdate |= checkTransaction();
- needsUpdate |= mCurrency.process();
-
- if (mBought)
- {
- closeFloater();
- }
- else if (needsUpdate)
- {
- if (mCanBuy && mCurrency.hasError())
- {
- tellUserError(mCurrency.errorMessage(), mCurrency.errorURI());
- }
-
- refreshUI();
- }
-}
-
-// virtual
-bool LLFloaterBuyLandUI::canClose()
-{
- // mTransactionType check for pre-buy estimation stage and mCurrency to allow exit after transaction
- bool can_close = !mTransaction && (mTransactionType != TransactionBuy || mCurrency.canCancel());
- if (!can_close)
- {
- // explain to user why they can't do this, see DEV-9605
- LLNotificationsUtil::add("CannotCloseFloaterBuyLand");
- }
- return can_close;
-}
-
-void LLFloaterBuyLandUI::onVisibilityChanged ( const LLSD& new_visibility )
-{
- if (new_visibility.asBoolean())
- {
- refreshUI();
- }
-}
-
-void LLFloaterBuyLandUI::refreshUI()
-{
- // section zero: title area
- {
- LLTextureCtrl* snapshot = getChild<LLTextureCtrl>("info_image");
- if (snapshot)
- {
- snapshot->setImageAssetID(
- mParcelValid ? mParcelSnapshot : LLUUID::null);
- }
-
- if (mParcelValid)
- {
- getChild<LLUICtrl>("info_parcel")->setValue(mParcelLocation);
-
- LLStringUtil::format_map_t string_args;
- string_args["[AMOUNT]"] = llformat("%d", mParcelActualArea);
- string_args["[AMOUNT2]"] = llformat("%d", mParcelSupportedObjects);
-
- getChild<LLUICtrl>("info_size")->setValue(getString("meters_supports_object", string_args));
-
- F32 cost_per_sqm = 0.0f;
- if (mParcelActualArea > 0)
- {
- cost_per_sqm = (F32)mParcelPrice / (F32)mParcelActualArea;
- }
-
- LLStringUtil::format_map_t info_price_args;
- info_price_args["[PRICE]"] = llformat("%d", mParcelPrice);
- info_price_args["[PRICE_PER_SQM]"] = llformat("%.1f", cost_per_sqm);
- if (mParcelSoldWithObjects)
- {
- info_price_args["[SOLD_WITH_OBJECTS]"] = getString("sold_with_objects");
- }
- else
- {
- info_price_args["[SOLD_WITH_OBJECTS]"] = getString("sold_without_objects");
- }
- getChild<LLUICtrl>("info_price")->setValue(getString("info_price_string", info_price_args));
- getChildView("info_price")->setVisible( mParcelIsForSale);
- }
- else
- {
- getChild<LLUICtrl>("info_parcel")->setValue(getString("no_parcel_selected"));
- getChild<LLUICtrl>("info_size")->setValue(LLStringUtil::null);
- getChild<LLUICtrl>("info_price")->setValue(LLStringUtil::null);
- }
-
- getChild<LLUICtrl>("info_action")->setValue(
- mCanBuy
- ?
- mIsForGroup
- ? getString("buying_for_group")//"Buying land for group:"
- : getString("buying_will")//"Buying this land will:"
- :
- mCannotBuyIsError
- ? getString("cannot_buy_now")//"Cannot buy now:"
- : getString("not_for_sale")//"Not for sale:"
-
- );
- }
-
- bool showingError = !mCanBuy || !mSiteValid;
-
- // error section
- if (showingError)
- {
- mChildren.setBadge(std::string("step_error"),
- mCannotBuyIsError
- ? LLViewChildren::BADGE_ERROR
- : LLViewChildren::BADGE_WARN);
-
- LLTextBox* message = getChild<LLTextBox>("error_message");
- if (message)
- {
- message->setVisible(true);
- message->setValue(LLSD(!mCanBuy ? mCannotBuyReason : "(waiting for data)"));
- }
-
- getChildView("error_web")->setVisible(mCannotBuyIsError && !mCannotBuyURI.empty());
- }
- else
- {
- getChildView("step_error")->setVisible(false);
- getChildView("error_message")->setVisible(false);
- getChildView("error_web")->setVisible(false);
- }
-
-
- // section one: account
- if (!showingError)
- {
- mChildren.setBadge(std::string("step_1"),
- mSiteMembershipUpgrade
- ? LLViewChildren::BADGE_NOTE
- : LLViewChildren::BADGE_OK);
- getChild<LLUICtrl>("account_action")->setValue(mSiteMembershipAction);
- getChild<LLUICtrl>("account_reason")->setValue(
- mSiteMembershipUpgrade
- ? getString("must_upgrade")
- : getString("cant_own_land")
- );
-
- LLComboBox* levels = getChild<LLComboBox>( "account_level");
- if (levels)
- {
- levels->setVisible(mSiteMembershipUpgrade);
-
- levels->removeall();
- for(std::vector<std::string>::const_iterator i
- = mSiteMembershipPlanNames.begin();
- i != mSiteMembershipPlanNames.end();
- ++i)
- {
- levels->add(*i);
- }
-
- levels->setCurrentByIndex(mUserPlanChoice);
- }
-
- getChildView("step_1")->setVisible(true);
- getChildView("account_action")->setVisible(true);
- getChildView("account_reason")->setVisible(true);
- }
- else
- {
- getChildView("step_1")->setVisible(false);
- getChildView("account_action")->setVisible(false);
- getChildView("account_reason")->setVisible(false);
- getChildView("account_level")->setVisible(false);
- }
-
- // section two: land use fees
- if (!showingError)
- {
- mChildren.setBadge(std::string("step_2"),
- mSiteLandUseUpgrade
- ? LLViewChildren::BADGE_NOTE
- : LLViewChildren::BADGE_OK);
- getChild<LLUICtrl>("land_use_action")->setValue(mSiteLandUseAction);
-
- std::string message;
-
- if (mIsForGroup)
- {
- LLStringUtil::format_map_t string_args;
- string_args["[GROUP]"] = std::string(gAgent.getGroupName());
-
- message += getString("insufficient_land_credits", string_args);
-
- }
- else
- {
- LLStringUtil::format_map_t string_args;
- string_args["[BUYER]"] = llformat("%d", mAgentCommittedTier);
- message += getString("land_holdings", string_args);
- }
-
- if (!mParcelValid)
- {
- message += LLTrans::getString("sentences_separator") + getString("no_parcel_selected");
- }
- else if (mParcelBillableArea == mParcelActualArea)
- {
- LLStringUtil::format_map_t string_args;
- string_args["[AMOUNT]"] = llformat("%d ", mParcelActualArea);
- message += LLTrans::getString("sentences_separator") + getString("parcel_meters", string_args);
- }
- else
- {
-
- if (mParcelBillableArea > mParcelActualArea)
- {
- LLStringUtil::format_map_t string_args;
- string_args["[AMOUNT]"] = llformat("%d ", mParcelBillableArea);
- message += LLTrans::getString("sentences_separator") + getString("premium_land", string_args);
- }
- else
- {
- LLStringUtil::format_map_t string_args;
- string_args["[AMOUNT]"] = llformat("%d ", mParcelBillableArea);
- message += LLTrans::getString("sentences_separator") + getString("discounted_land", string_args);
- }
- }
-
- getChild<LLUICtrl>("land_use_reason")->setValue(message);
-
- getChildView("step_2")->setVisible(true);
- getChildView("land_use_action")->setVisible(true);
- getChildView("land_use_reason")->setVisible(true);
- }
- else
- {
- getChildView("step_2")->setVisible(false);
- getChildView("land_use_action")->setVisible(false);
- getChildView("land_use_reason")->setVisible(false);
- }
-
- // section three: purchase & currency
- S32 finalBalance = mAgentCashBalance + mCurrency.getAmount() - mParcelPrice;
- bool willHaveEnough = finalBalance >= 0;
- bool haveEnough = mAgentCashBalance >= mParcelPrice;
- S32 minContribution = llceil((F32)mParcelBillableArea / GROUP_LAND_BONUS_FACTOR);
- bool groupContributionEnough = mParcelGroupContribution >= minContribution;
-
- mCurrency.updateUI(!showingError && !haveEnough);
-
- if (!showingError)
- {
- mChildren.setBadge(std::string("step_3"),
- !willHaveEnough
- ? LLViewChildren::BADGE_WARN
- : mCurrency.getAmount() > 0
- ? LLViewChildren::BADGE_NOTE
- : LLViewChildren::BADGE_OK);
-
- LLStringUtil::format_map_t string_args;
- string_args["[AMOUNT]"] = llformat("%d", mParcelPrice);
- string_args["[SELLER]"] = mParcelSellerName;
- getChild<LLUICtrl>("purchase_action")->setValue(getString("pay_to_for_land", string_args));
- getChildView("purchase_action")->setVisible( mParcelValid);
-
- std::string reasonString;
-
- if (haveEnough)
- {
- LLStringUtil::format_map_t string_args;
- string_args["[AMOUNT]"] = llformat("%d", mAgentCashBalance);
-
- getChild<LLUICtrl>("currency_reason")->setValue(getString("have_enough_lindens", string_args));
- }
- else
- {
- LLStringUtil::format_map_t string_args;
- string_args["[AMOUNT]"] = llformat("%d", mAgentCashBalance);
- string_args["[AMOUNT2]"] = llformat("%d", mParcelPrice - mAgentCashBalance);
-
- getChild<LLUICtrl>("currency_reason")->setValue(getString("not_enough_lindens", string_args));
-
- getChild<LLUICtrl>("currency_est")->setTextArg("[LOCAL_AMOUNT]", mCurrency.getLocalEstimate());
- }
-
- if (willHaveEnough)
- {
- LLStringUtil::format_map_t string_args;
- string_args["[AMOUNT]"] = llformat("%d", finalBalance);
-
- getChild<LLUICtrl>("currency_balance")->setValue(getString("balance_left", string_args));
-
- }
- else
- {
- LLStringUtil::format_map_t string_args;
- string_args["[AMOUNT]"] = llformat("%d", mParcelPrice - mAgentCashBalance);
-
- getChild<LLUICtrl>("currency_balance")->setValue(getString("balance_needed", string_args));
-
- }
-
- getChild<LLUICtrl>("remove_contribution")->setValue(LLSD(groupContributionEnough));
- getChildView("remove_contribution")->setEnabled(groupContributionEnough);
- bool showRemoveContribution = mParcelIsGroupLand
- && (mParcelGroupContribution > 0);
- getChildView("remove_contribution")->setLabelArg("[AMOUNT]",
- llformat("%d", minContribution));
- getChildView("remove_contribution")->setVisible( showRemoveContribution);
-
- getChildView("step_3")->setVisible(true);
- getChildView("purchase_action")->setVisible(true);
- getChildView("currency_reason")->setVisible(true);
- getChildView("currency_balance")->setVisible(true);
- }
- else
- {
- getChildView("step_3")->setVisible(false);
- getChildView("purchase_action")->setVisible(false);
- getChildView("currency_reason")->setVisible(false);
- getChildView("currency_balance")->setVisible(false);
- getChildView("remove_group_donation")->setVisible(false);
- }
-
-
- bool agrees_to_covenant = false;
- LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant");
- if (check)
- {
- agrees_to_covenant = check->get();
- }
-
- getChildView("buy_btn")->setEnabled(mCanBuy && mSiteValid && willHaveEnough && !mTransaction && agrees_to_covenant);
-}
-
-void LLFloaterBuyLandUI::startBuyPreConfirm()
-{
- std::string action;
-
- if (mSiteMembershipUpgrade)
- {
- action += mSiteMembershipAction;
- action += "\n";
-
- LLComboBox* levels = getChild<LLComboBox>( "account_level");
- if (levels)
- {
- action += " * ";
- action += mSiteMembershipPlanNames[levels->getCurrentIndex()];
- action += "\n";
- }
- }
- if (mSiteLandUseUpgrade)
- {
- action += mSiteLandUseAction;
- action += "\n";
- }
- if (mCurrency.getAmount() > 0)
- {
- LLStringUtil::format_map_t string_args;
- string_args["[AMOUNT]"] = llformat("%d", mCurrency.getAmount());
- string_args["[LOCAL_AMOUNT]"] = mCurrency.getLocalEstimate();
-
- action += getString("buy_for_US", string_args);
- }
-
- LLStringUtil::format_map_t string_args;
- string_args["[AMOUNT]"] = llformat("%d", mParcelPrice);
- string_args["[SELLER]"] = mParcelSellerName;
- action += getString("pay_to_for_land", string_args);
-
-
- LLConfirmationManager::confirm(mSiteConfirm,
- action,
- *this,
- &LLFloaterBuyLandUI::startBuyPostConfirm);
-}
-
-void LLFloaterBuyLandUI::startBuyPostConfirm(const std::string& password)
-{
- runWebSitePrep(password);
-
- mCanBuy = false;
- mCannotBuyReason = getString("processing");
- refreshUI();
-}
-
-
-void LLFloaterBuyLandUI::onClickBuy()
-{
- startBuyPreConfirm();
-}
-
-void LLFloaterBuyLandUI::onClickCancel()
-{
- closeFloater();
-}
-
-void LLFloaterBuyLandUI::onClickErrorWeb()
-{
- LLWeb::loadURLExternal(mCannotBuyURI);
- closeFloater();
-}
-
-
-
+/** + * @file llfloaterbuyland.cpp + * @brief LLFloaterBuyLand 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$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterbuyland.h" + +// viewer includes +#include "llagent.h" +#include "llbutton.h" +#include "llcachename.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llconfirmationmanager.h" +#include "llcurrencyuimanager.h" +#include "llfloater.h" +#include "llfloaterreg.h" +#include "llfloatertools.h" +#include "llframetimer.h" +#include "lliconctrl.h" +#include "lllineeditor.h" +#include "llnotificationsutil.h" +#include "llparcel.h" +#include "llslurl.h" +#include "llstatusbar.h" +#include "lltextbox.h" +#include "lltexturectrl.h" +#include "lltrans.h" +#include "llviewchildren.h" +#include "llviewercontrol.h" +#include "lluictrlfactory.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewertexteditor.h" +#include "llviewerwindow.h" +#include "llweb.h" +#include "llwindow.h" +#include "llworld.h" +#include "llxmlrpctransaction.h" +#include "llviewernetwork.h" +#include "roles_constants.h" + +// NOTE: This is duplicated in lldatamoney.cpp ... +const F32 GROUP_LAND_BONUS_FACTOR = 1.1f; + +class LLFloaterBuyLandUI +: public LLFloater +{ +public: + LLFloaterBuyLandUI(const LLSD& key); + virtual ~LLFloaterBuyLandUI(); + + /*virtual*/ void onClose(bool app_quitting); + + // Left padding for maturity rating icon. + static const S32 ICON_PAD = 2; + +private: + class SelectionObserver : public LLParcelObserver + { + public: + SelectionObserver(LLFloaterBuyLandUI* floater) : mFloater(floater) {} + virtual void changed(); + private: + LLFloaterBuyLandUI* mFloater; + }; + +private: + SelectionObserver mParcelSelectionObserver; + LLViewerRegion* mRegion; + LLParcelSelectionHandle mParcel; + bool mIsClaim; + bool mIsForGroup; + + bool mCanBuy; + bool mCannotBuyIsError; + std::string mCannotBuyReason; + std::string mCannotBuyURI; + + bool mBought; + + // information about the agent + S32 mAgentCommittedTier; + S32 mAgentCashBalance; + bool mAgentHasNeverOwnedLand; + + // information about the parcel + bool mParcelValid; + bool mParcelIsForSale; + bool mParcelIsGroupLand; + S32 mParcelGroupContribution; + S32 mParcelPrice; + S32 mParcelActualArea; + S32 mParcelBillableArea; + S32 mParcelSupportedObjects; + bool mParcelSoldWithObjects; + std::string mParcelLocation; + LLUUID mParcelSnapshot; + std::string mParcelSellerName; + + // user's choices + S32 mUserPlanChoice; + + // from website + bool mSiteValid; + bool mSiteMembershipUpgrade; + std::string mSiteMembershipAction; + std::vector<std::string> + mSiteMembershipPlanIDs; + std::vector<std::string> + mSiteMembershipPlanNames; + bool mSiteLandUseUpgrade; + std::string mSiteLandUseAction; + std::string mSiteConfirm; + + // values in current Preflight transaction... used to avoid extra + // preflights when the parcel manager goes update crazy + S32 mPreflightAskBillableArea; + S32 mPreflightAskCurrencyBuy; + + LLViewChildren mChildren; + LLCurrencyUIManager mCurrency; + + enum TransactionType + { + TransactionPreflight, + TransactionCurrency, + TransactionBuy + }; + LLXMLRPCTransaction* mTransaction; + TransactionType mTransactionType; + + LLViewerParcelMgr::ParcelBuyInfo* mParcelBuyInfo; + +public: + void setForGroup(bool is_for_group); + void setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel); + + void updateAgentInfo(); + void updateParcelInfo(); + void updateCovenantInfo(); + static void onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data); + void updateFloaterCovenantText(const std::string& string, const LLUUID &asset_id); + void updateFloaterEstateName(const std::string& name); + void updateFloaterLastModified(const std::string& text); + void updateFloaterEstateOwnerName(const std::string& name); + void updateWebSiteInfo(); + void finishWebSiteInfo(); + + void runWebSitePrep(const std::string& password); + void finishWebSitePrep(); + void sendBuyLand(); + + void updateNames(); + // Name cache callback + void updateGroupName(const LLUUID& id, + const std::string& name, + bool is_group); + + void refreshUI(); + + void startTransaction(TransactionType type, const LLXMLRPCValue& params); + bool checkTransaction(); + + void tellUserError(const std::string& message, const std::string& uri); + + virtual bool postBuild(); + + void startBuyPreConfirm(); + void startBuyPostConfirm(const std::string& password); + + void onClickBuy(); + void onClickCancel(); + void onClickErrorWeb(); + + virtual void draw(); + virtual bool canClose(); + + void onVisibilityChanged ( const LLSD& new_visibility ); + +}; + +// static +void LLFloaterBuyLand::buyLand( + LLViewerRegion* region, LLParcelSelectionHandle parcel, bool is_for_group) +{ + if(is_for_group && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED)) + { + LLNotificationsUtil::add("OnlyOfficerCanBuyLand"); + return; + } + + LLFloaterBuyLandUI* ui = LLFloaterReg::showTypedInstance<LLFloaterBuyLandUI>("buy_land"); + if (ui) + { + ui->setForGroup(is_for_group); + ui->setParcel(region, parcel); + } +} + +// static +void LLFloaterBuyLand::updateCovenantText(const std::string& string, const LLUUID &asset_id) +{ + LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land"); + if (floater) + { + floater->updateFloaterCovenantText(string, asset_id); + } +} + +// static +void LLFloaterBuyLand::updateEstateName(const std::string& name) +{ + LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land"); + if (floater) + { + floater->updateFloaterEstateName(name); + } +} + +// static +void LLFloaterBuyLand::updateLastModified(const std::string& text) +{ + LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land"); + if (floater) + { + floater->updateFloaterLastModified(text); + } +} + +// static +void LLFloaterBuyLand::updateEstateOwnerName(const std::string& name) +{ + LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land"); + if (floater) + { + floater->updateFloaterEstateOwnerName(name); + } +} + +// static +LLFloater* LLFloaterBuyLand::buildFloater(const LLSD& key) +{ + LLFloaterBuyLandUI* floater = new LLFloaterBuyLandUI(key); + return floater; +} + +//---------------------------------------------------------------------------- +// LLFloaterBuyLandUI +//---------------------------------------------------------------------------- + +#if LL_WINDOWS +// passing 'this' during construction generates a warning. The callee +// only uses the pointer to hold a reference to 'this' which is +// already valid, so this call does the correct thing. Disable the +// warning so that we can compile without generating a warning. +#pragma warning(disable : 4355) +#endif +LLFloaterBuyLandUI::LLFloaterBuyLandUI(const LLSD& key) +: LLFloater(LLSD()), + mParcelSelectionObserver(this), + mParcel(0), + mBought(false), + mParcelValid(false), mSiteValid(false), + mChildren(*this), mCurrency(*this), mTransaction(0), + mParcelBuyInfo(0) +{ + LLViewerParcelMgr::getInstance()->addObserver(&mParcelSelectionObserver); + +} + +LLFloaterBuyLandUI::~LLFloaterBuyLandUI() +{ + LLViewerParcelMgr::getInstance()->removeObserver(&mParcelSelectionObserver); + LLViewerParcelMgr::getInstance()->deleteParcelBuy(&mParcelBuyInfo); + + delete mTransaction; +} + +// virtual +void LLFloaterBuyLandUI::onClose(bool app_quitting) +{ + // This object holds onto observer, transactions, and parcel state. + // Despite being single_instance, destroy it to call destructors and clean + // everything up. + setVisible(false); + destroy(); +} + +void LLFloaterBuyLandUI::SelectionObserver::changed() +{ + if (LLViewerParcelMgr::getInstance()->selectionEmpty()) + { + mFloater->closeFloater(); + } + else + { + mFloater->setParcel(LLViewerParcelMgr::getInstance()->getSelectionRegion(), + LLViewerParcelMgr::getInstance()->getParcelSelection()); + } +} + + +void LLFloaterBuyLandUI::updateAgentInfo() +{ + mAgentCommittedTier = gStatusBar->getSquareMetersCommitted(); + mAgentCashBalance = gStatusBar->getBalance(); + + // *TODO: This is an approximation, we should send this value down + // to the viewer. See SL-10728 for details. + mAgentHasNeverOwnedLand = mAgentCommittedTier == 0; +} + +void LLFloaterBuyLandUI::updateParcelInfo() +{ + LLParcel* parcel = mParcel->getParcel(); + mParcelValid = parcel && mRegion; + mParcelIsForSale = false; + mParcelIsGroupLand = false; + mParcelGroupContribution = 0; + mParcelPrice = 0; + mParcelActualArea = 0; + mParcelBillableArea = 0; + mParcelSupportedObjects = 0; + mParcelSoldWithObjects = false; + mParcelLocation = ""; + mParcelSnapshot.setNull(); + mParcelSellerName = ""; + + mCanBuy = false; + mCannotBuyIsError = false; + + if (!mParcelValid) + { + mCannotBuyReason = getString("no_land_selected"); + return; + } + + if (mParcel->getMultipleOwners()) + { + mCannotBuyReason = getString("multiple_parcels_selected"); + return; + } + + const LLUUID& parcelOwner = parcel->getOwnerID(); + + mIsClaim = parcel->isPublic(); + if (!mIsClaim) + { + mParcelActualArea = parcel->getArea(); + mParcelIsForSale = parcel->getForSale(); + mParcelIsGroupLand = parcel->getIsGroupOwned(); + mParcelPrice = mParcelIsForSale ? parcel->getSalePrice() : 0; + + if (mParcelIsGroupLand) + { + LLUUID group_id = parcel->getGroupID(); + mParcelGroupContribution = gAgent.getGroupContribution(group_id); + } + } + else + { + mParcelActualArea = mParcel->getClaimableArea(); + mParcelIsForSale = true; + mParcelPrice = mParcelActualArea * parcel->getClaimPricePerMeter(); + } + + mParcelBillableArea = + ll_round(mRegion->getBillableFactor() * mParcelActualArea); + + mParcelSupportedObjects = ll_round( + parcel->getMaxPrimCapacity() * parcel->getParcelPrimBonus()); + // Can't have more than region max tasks, regardless of parcel + // object bonus factor. + LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); + if(region) + { + S32 max_tasks_per_region = (S32)region->getMaxTasks(); + mParcelSupportedObjects = llmin( + mParcelSupportedObjects, max_tasks_per_region); + } + + mParcelSoldWithObjects = parcel->getSellWithObjects(); + + + LLVector3 center = parcel->getCenterpoint(); + mParcelLocation = llformat("%s %d,%d", + mRegion->getName().c_str(), + (int)center[VX], (int)center[VY] + ); + + mParcelSnapshot = parcel->getSnapshotID(); + + updateNames(); + + bool haveEnoughCash = mParcelPrice <= mAgentCashBalance; + S32 cashBuy = haveEnoughCash ? 0 : (mParcelPrice - mAgentCashBalance); + mCurrency.setAmount(cashBuy, true); + mCurrency.setZeroMessage(haveEnoughCash ? getString("none_needed") : LLStringUtil::null); + + // checks that we can buy the land + + if(mIsForGroup && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED)) + { + mCannotBuyReason = getString("cant_buy_for_group"); + return; + } + + if (!mIsClaim) + { + const LLUUID& authorizedBuyer = parcel->getAuthorizedBuyerID(); + const LLUUID buyer = gAgent.getID(); + const LLUUID newOwner = mIsForGroup ? gAgent.getGroupID() : buyer; + + if (!mParcelIsForSale + || (mParcelPrice == 0 && authorizedBuyer.isNull())) + { + + mCannotBuyReason = getString("parcel_not_for_sale"); + return; + } + + if (parcelOwner == newOwner) + { + if (mIsForGroup) + { + mCannotBuyReason = getString("group_already_owns"); + } + else + { + mCannotBuyReason = getString("you_already_own"); + } + return; + } + + if (!authorizedBuyer.isNull() && buyer != authorizedBuyer) + { + // Maybe the parcel is set for sale to a group we are in. + bool authorized_group = + gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_DEED) + && gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_SET_SALE_INFO); + + if (!authorized_group) + { + mCannotBuyReason = getString("set_to_sell_to_other"); + return; + } + } + } + else + { + if (mParcelActualArea == 0) + { + mCannotBuyReason = getString("no_public_land"); + return; + } + + if (mParcel->hasOthersSelected()) + { + // Policy: Must not have someone else's land selected + mCannotBuyReason = getString("not_owned_by_you"); + return; + } + } + + mCanBuy = true; +} + +void LLFloaterBuyLandUI::updateCovenantInfo() +{ + LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); + if(!region) return; + + U8 sim_access = region->getSimAccess(); + std::string rating = LLViewerRegion::accessToString(sim_access); + + LLTextBox* region_name = getChild<LLTextBox>("region_name_text"); + if (region_name) + { + std::string region_name_txt = region->getName() + " ("+rating +")"; + region_name->setText(region_name_txt); + + LLIconCtrl* rating_icon = getChild<LLIconCtrl>("rating_icon"); + LLRect rect = rating_icon->getRect(); + S32 region_name_width = llmin(region_name->getRect().getWidth(), region_name->getTextBoundingRect().getWidth()); + S32 icon_left_pad = region_name->getRect().mLeft + region_name_width + ICON_PAD; + region_name->setToolTip(region_name->getText()); + rating_icon->setRect(rect.setOriginAndSize(icon_left_pad, rect.mBottom, rect.getWidth(), rect.getHeight())); + + switch(sim_access) + { + case SIM_ACCESS_PG: + rating_icon->setValue(getString("icon_PG")); + break; + + case SIM_ACCESS_ADULT: + rating_icon->setValue(getString("icon_R")); + break; + + default: + rating_icon->setValue(getString("icon_M")); + } + } + + LLTextBox* region_type = getChild<LLTextBox>("region_type_text"); + if (region_type) + { + region_type->setText(region->getLocalizedSimProductName()); + region_type->setToolTip(region->getLocalizedSimProductName()); + } + + LLTextBox* resellable_clause = getChild<LLTextBox>("resellable_clause"); + if (resellable_clause) + { + if (region->getRegionFlag(REGION_FLAGS_BLOCK_LAND_RESELL)) + { + resellable_clause->setText(getString("can_not_resell")); + } + else + { + resellable_clause->setText(getString("can_resell")); + } + } + + LLTextBox* changeable_clause = getChild<LLTextBox>("changeable_clause"); + if (changeable_clause) + { + if (region->getRegionFlag(REGION_FLAGS_ALLOW_PARCEL_CHANGES)) + { + changeable_clause->setText(getString("can_change")); + } + else + { + changeable_clause->setText(getString("can_not_change")); + } + } + + LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant"); + if(check) + { + check->set(false); + check->setEnabled(true); + check->setCommitCallback(onChangeAgreeCovenant, this); + } + + LLTextBox* box = getChild<LLTextBox>("covenant_text"); + if(box) + { + box->setVisible(false); + } + + // send EstateCovenantInfo message + LLMessageSystem *msg = gMessageSystem; + msg->newMessage("EstateCovenantRequest"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); + msg->sendReliable(region->getHost()); +} + +// static +void LLFloaterBuyLandUI::onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data) +{ + LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)user_data; + if(self) + { + self->refreshUI(); + } +} + +void LLFloaterBuyLandUI::updateFloaterCovenantText(const std::string &string, const LLUUID& asset_id) +{ + LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("covenant_editor"); + editor->setText(string); + + LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant"); + LLTextBox* box = getChild<LLTextBox>("covenant_text"); + if (asset_id.isNull()) + { + check->set(true); + check->setEnabled(false); + refreshUI(); + + // remove the line stating that you must agree + box->setVisible(false); + } + else + { + check->setEnabled(true); + + // remove the line stating that you must agree + box->setVisible(true); + } +} + +void LLFloaterBuyLandUI::updateFloaterEstateName(const std::string& name) +{ + LLTextBox* box = getChild<LLTextBox>("estate_name_text"); + box->setText(name); + box->setToolTip(name); +} + +void LLFloaterBuyLandUI::updateFloaterLastModified(const std::string& text) +{ + LLTextBox* editor = getChild<LLTextBox>("covenant_timestamp_text"); + if (editor) editor->setText(text); +} + +void LLFloaterBuyLandUI::updateFloaterEstateOwnerName(const std::string& name) +{ + LLTextBox* box = getChild<LLTextBox>("estate_owner_text"); + if (box) box->setText(name); +} + +void LLFloaterBuyLandUI::updateWebSiteInfo() +{ + S32 askBillableArea = mIsForGroup ? 0 : mParcelBillableArea; + S32 askCurrencyBuy = mCurrency.getAmount(); + + if (mTransaction && mTransactionType == TransactionPreflight + && mPreflightAskBillableArea == askBillableArea + && mPreflightAskCurrencyBuy == askCurrencyBuy) + { + return; + } + + mPreflightAskBillableArea = askBillableArea; + mPreflightAskCurrencyBuy = askCurrencyBuy; + +#if 0 + // enable this code if you want the details to blank while we're talking + // to the web site... it's kind of jarring + mSiteValid = false; + mSiteMembershipUpgrade = false; + mSiteMembershipAction = "(waiting)"; + mSiteMembershipPlanIDs.clear(); + mSiteMembershipPlanNames.clear(); + mSiteLandUseUpgrade = false; + mSiteLandUseAction = "(waiting)"; + mSiteCurrencyEstimated = false; + mSiteCurrencyEstimatedCost = 0; +#endif + + LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct(); + keywordArgs.appendString("agentId", gAgent.getID().asString()); + keywordArgs.appendString( + "secureSessionId", + gAgent.getSecureSessionID().asString()); + keywordArgs.appendString("language", LLUI::getLanguage()); + keywordArgs.appendInt("billableArea", mPreflightAskBillableArea); + keywordArgs.appendInt("currencyBuy", mPreflightAskCurrencyBuy); + + LLXMLRPCValue params = LLXMLRPCValue::createArray(); + params.append(keywordArgs); + + startTransaction(TransactionPreflight, params); +} + +void LLFloaterBuyLandUI::finishWebSiteInfo() +{ + + LLXMLRPCValue result = mTransaction->responseValue(); + + mSiteValid = result["success"].asBool(); + if (!mSiteValid) + { + tellUserError( + result["errorMessage"].asString(), + result["errorURI"].asString() + ); + return; + } + + LLXMLRPCValue membership = result["membership"]; + mSiteMembershipUpgrade = membership["upgrade"].asBool(); + mSiteMembershipAction = membership["action"].asString(); + mSiteMembershipPlanIDs.clear(); + mSiteMembershipPlanNames.clear(); + LLXMLRPCValue levels = membership["levels"]; + for (LLXMLRPCValue level = levels.rewind(); + level.isValid(); + level = levels.next()) + { + mSiteMembershipPlanIDs.push_back(level["id"].asString()); + mSiteMembershipPlanNames.push_back(level["description"].asString()); + } + mUserPlanChoice = 0; + + LLXMLRPCValue landUse = result["landUse"]; + mSiteLandUseUpgrade = landUse["upgrade"].asBool(); + mSiteLandUseAction = landUse["action"].asString(); + + LLXMLRPCValue currency = result["currency"]; + if (currency["estimatedCost"].isValid()) + { + mCurrency.setUSDEstimate(currency["estimatedCost"].asInt()); + } + if (currency["estimatedLocalCost"].isValid()) + { + mCurrency.setLocalEstimate(currency["estimatedLocalCost"].asString()); + } + + mSiteConfirm = result["confirm"].asString(); +} + +void LLFloaterBuyLandUI::runWebSitePrep(const std::string& password) +{ + if (!mCanBuy) + { + return; + } + + bool remove_contribution = getChild<LLUICtrl>("remove_contribution")->getValue().asBoolean(); + mParcelBuyInfo = LLViewerParcelMgr::getInstance()->setupParcelBuy(gAgent.getID(), gAgent.getSessionID(), + gAgent.getGroupID(), mIsForGroup, mIsClaim, remove_contribution); + + if (mParcelBuyInfo + && !mSiteMembershipUpgrade + && !mSiteLandUseUpgrade + && mCurrency.getAmount() == 0 + && mSiteConfirm != "password") + { + sendBuyLand(); + return; + } + + + std::string newLevel = "noChange"; + + if (mSiteMembershipUpgrade) + { + LLComboBox* levels = getChild<LLComboBox>( "account_level"); + if (levels) + { + mUserPlanChoice = levels->getCurrentIndex(); + newLevel = mSiteMembershipPlanIDs[mUserPlanChoice]; + } + } + + LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct(); + keywordArgs.appendString("agentId", gAgent.getID().asString()); + keywordArgs.appendString( + "secureSessionId", + gAgent.getSecureSessionID().asString()); + keywordArgs.appendString("language", LLUI::getLanguage()); + keywordArgs.appendString("levelId", newLevel); + keywordArgs.appendInt("billableArea", + mIsForGroup ? 0 : mParcelBillableArea); + keywordArgs.appendInt("currencyBuy", mCurrency.getAmount()); + keywordArgs.appendInt("estimatedCost", mCurrency.getUSDEstimate()); + keywordArgs.appendString("estimatedLocalCost", mCurrency.getLocalEstimate()); + keywordArgs.appendString("confirm", mSiteConfirm); + if (!password.empty()) + { + keywordArgs.appendString("password", password); + } + + LLXMLRPCValue params = LLXMLRPCValue::createArray(); + params.append(keywordArgs); + + startTransaction(TransactionBuy, params); +} + +void LLFloaterBuyLandUI::finishWebSitePrep() +{ + LLXMLRPCValue result = mTransaction->responseValue(); + + bool success = result["success"].asBool(); + if (!success) + { + tellUserError( + result["errorMessage"].asString(), + result["errorURI"].asString() + ); + return; + } + + sendBuyLand(); +} + +void LLFloaterBuyLandUI::sendBuyLand() +{ + if (mParcelBuyInfo) + { + LLViewerParcelMgr::getInstance()->sendParcelBuy(mParcelBuyInfo); + LLViewerParcelMgr::getInstance()->deleteParcelBuy(&mParcelBuyInfo); + mBought = true; + } +} + +void LLFloaterBuyLandUI::updateNames() +{ + LLParcel* parcelp = mParcel->getParcel(); + + if (!parcelp) + { + mParcelSellerName = LLStringUtil::null; + return; + } + + if (mIsClaim) + { + mParcelSellerName = "Linden Lab"; + } + else if (parcelp->getIsGroupOwned()) + { + gCacheName->getGroup(parcelp->getGroupID(), + boost::bind(&LLFloaterBuyLandUI::updateGroupName, this, + _1, _2, _3)); + } + else + { + mParcelSellerName = LLSLURL("agent", parcelp->getOwnerID(), "completename").getSLURLString(); + } +} + +void LLFloaterBuyLandUI::updateGroupName(const LLUUID& id, + const std::string& name, + bool is_group) +{ + LLParcel* parcelp = mParcel->getParcel(); + if (parcelp + && parcelp->getGroupID() == id) + { + // request is current + mParcelSellerName = name; + } +} + +void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCValue& params) +{ + delete mTransaction; + mTransaction = NULL; + + mTransactionType = type; + + // Select a URI and method appropriate for the transaction type. + static std::string transaction_uri; + if (transaction_uri.empty()) + { + transaction_uri = LLGridManager::getInstance()->getHelperURI() + "landtool.php"; + } + + const char* method; + switch (mTransactionType) + { + case TransactionPreflight: + method = "preflightBuyLandPrep"; + break; + case TransactionBuy: + method = "buyLandPrep"; + break; + default: + LL_WARNS() << "LLFloaterBuyLandUI: Unknown transaction type!" << LL_ENDL; + return; + } + + mTransaction = new LLXMLRPCTransaction( + transaction_uri, + method, + params, + false /* don't use gzip */ + ); +} + +bool LLFloaterBuyLandUI::checkTransaction() +{ + if (!mTransaction) + { + return false; + } + + if (!mTransaction->process()) + { + return false; + } + + if (mTransaction->status(NULL) != LLXMLRPCTransaction::StatusComplete) + { + tellUserError(mTransaction->statusMessage(), mTransaction->statusURI()); + } + else { + switch (mTransactionType) + { + case TransactionPreflight: finishWebSiteInfo(); break; + case TransactionBuy: finishWebSitePrep(); break; + default: ; + } + } + + delete mTransaction; + mTransaction = NULL; + + return true; +} + +void LLFloaterBuyLandUI::tellUserError( + const std::string& message, const std::string& uri) +{ + mCanBuy = false; + mCannotBuyIsError = true; + mCannotBuyReason = getString("fetching_error"); + mCannotBuyReason += message; + mCannotBuyURI = uri; +} + + +// virtual +bool LLFloaterBuyLandUI::postBuild() +{ + setVisibleCallback(boost::bind(&LLFloaterBuyLandUI::onVisibilityChanged, this, _2)); + + mCurrency.prepare(); + + getChild<LLUICtrl>("buy_btn")->setCommitCallback( boost::bind(&LLFloaterBuyLandUI::onClickBuy, this)); + getChild<LLUICtrl>("cancel_btn")->setCommitCallback( boost::bind(&LLFloaterBuyLandUI::onClickCancel, this)); + getChild<LLUICtrl>("error_web")->setCommitCallback( boost::bind(&LLFloaterBuyLandUI::onClickErrorWeb, this)); + + center(); + + return true; +} + +void LLFloaterBuyLandUI::setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel) +{ + if (mTransaction && mTransactionType == TransactionBuy) + { + // the user is buying, don't change the selection + return; + } + + mRegion = region; + mParcel = parcel; + + updateAgentInfo(); + updateParcelInfo(); + updateCovenantInfo(); + if (mCanBuy) + { + updateWebSiteInfo(); + } + refreshUI(); +} + +void LLFloaterBuyLandUI::setForGroup(bool forGroup) +{ + mIsForGroup = forGroup; +} + +void LLFloaterBuyLandUI::draw() +{ + LLFloater::draw(); + + bool needsUpdate = false; + needsUpdate |= checkTransaction(); + needsUpdate |= mCurrency.process(); + + if (mBought) + { + closeFloater(); + } + else if (needsUpdate) + { + if (mCanBuy && mCurrency.hasError()) + { + tellUserError(mCurrency.errorMessage(), mCurrency.errorURI()); + } + + refreshUI(); + } +} + +// virtual +bool LLFloaterBuyLandUI::canClose() +{ + // mTransactionType check for pre-buy estimation stage and mCurrency to allow exit after transaction + bool can_close = !mTransaction && (mTransactionType != TransactionBuy || mCurrency.canCancel()); + if (!can_close) + { + // explain to user why they can't do this, see DEV-9605 + LLNotificationsUtil::add("CannotCloseFloaterBuyLand"); + } + return can_close; +} + +void LLFloaterBuyLandUI::onVisibilityChanged ( const LLSD& new_visibility ) +{ + if (new_visibility.asBoolean()) + { + refreshUI(); + } +} + +void LLFloaterBuyLandUI::refreshUI() +{ + // section zero: title area + { + LLTextureCtrl* snapshot = getChild<LLTextureCtrl>("info_image"); + if (snapshot) + { + snapshot->setImageAssetID( + mParcelValid ? mParcelSnapshot : LLUUID::null); + } + + if (mParcelValid) + { + getChild<LLUICtrl>("info_parcel")->setValue(mParcelLocation); + + LLStringUtil::format_map_t string_args; + string_args["[AMOUNT]"] = llformat("%d", mParcelActualArea); + string_args["[AMOUNT2]"] = llformat("%d", mParcelSupportedObjects); + + getChild<LLUICtrl>("info_size")->setValue(getString("meters_supports_object", string_args)); + + F32 cost_per_sqm = 0.0f; + if (mParcelActualArea > 0) + { + cost_per_sqm = (F32)mParcelPrice / (F32)mParcelActualArea; + } + + LLStringUtil::format_map_t info_price_args; + info_price_args["[PRICE]"] = llformat("%d", mParcelPrice); + info_price_args["[PRICE_PER_SQM]"] = llformat("%.1f", cost_per_sqm); + if (mParcelSoldWithObjects) + { + info_price_args["[SOLD_WITH_OBJECTS]"] = getString("sold_with_objects"); + } + else + { + info_price_args["[SOLD_WITH_OBJECTS]"] = getString("sold_without_objects"); + } + getChild<LLUICtrl>("info_price")->setValue(getString("info_price_string", info_price_args)); + getChildView("info_price")->setVisible( mParcelIsForSale); + } + else + { + getChild<LLUICtrl>("info_parcel")->setValue(getString("no_parcel_selected")); + getChild<LLUICtrl>("info_size")->setValue(LLStringUtil::null); + getChild<LLUICtrl>("info_price")->setValue(LLStringUtil::null); + } + + getChild<LLUICtrl>("info_action")->setValue( + mCanBuy + ? + mIsForGroup + ? getString("buying_for_group")//"Buying land for group:" + : getString("buying_will")//"Buying this land will:" + : + mCannotBuyIsError + ? getString("cannot_buy_now")//"Cannot buy now:" + : getString("not_for_sale")//"Not for sale:" + + ); + } + + bool showingError = !mCanBuy || !mSiteValid; + + // error section + if (showingError) + { + mChildren.setBadge(std::string("step_error"), + mCannotBuyIsError + ? LLViewChildren::BADGE_ERROR + : LLViewChildren::BADGE_WARN); + + LLTextBox* message = getChild<LLTextBox>("error_message"); + if (message) + { + message->setVisible(true); + message->setValue(LLSD(!mCanBuy ? mCannotBuyReason : "(waiting for data)")); + } + + getChildView("error_web")->setVisible(mCannotBuyIsError && !mCannotBuyURI.empty()); + } + else + { + getChildView("step_error")->setVisible(false); + getChildView("error_message")->setVisible(false); + getChildView("error_web")->setVisible(false); + } + + + // section one: account + if (!showingError) + { + mChildren.setBadge(std::string("step_1"), + mSiteMembershipUpgrade + ? LLViewChildren::BADGE_NOTE + : LLViewChildren::BADGE_OK); + getChild<LLUICtrl>("account_action")->setValue(mSiteMembershipAction); + getChild<LLUICtrl>("account_reason")->setValue( + mSiteMembershipUpgrade + ? getString("must_upgrade") + : getString("cant_own_land") + ); + + LLComboBox* levels = getChild<LLComboBox>( "account_level"); + if (levels) + { + levels->setVisible(mSiteMembershipUpgrade); + + levels->removeall(); + for(std::vector<std::string>::const_iterator i + = mSiteMembershipPlanNames.begin(); + i != mSiteMembershipPlanNames.end(); + ++i) + { + levels->add(*i); + } + + levels->setCurrentByIndex(mUserPlanChoice); + } + + getChildView("step_1")->setVisible(true); + getChildView("account_action")->setVisible(true); + getChildView("account_reason")->setVisible(true); + } + else + { + getChildView("step_1")->setVisible(false); + getChildView("account_action")->setVisible(false); + getChildView("account_reason")->setVisible(false); + getChildView("account_level")->setVisible(false); + } + + // section two: land use fees + if (!showingError) + { + mChildren.setBadge(std::string("step_2"), + mSiteLandUseUpgrade + ? LLViewChildren::BADGE_NOTE + : LLViewChildren::BADGE_OK); + getChild<LLUICtrl>("land_use_action")->setValue(mSiteLandUseAction); + + std::string message; + + if (mIsForGroup) + { + LLStringUtil::format_map_t string_args; + string_args["[GROUP]"] = std::string(gAgent.getGroupName()); + + message += getString("insufficient_land_credits", string_args); + + } + else + { + LLStringUtil::format_map_t string_args; + string_args["[BUYER]"] = llformat("%d", mAgentCommittedTier); + message += getString("land_holdings", string_args); + } + + if (!mParcelValid) + { + message += LLTrans::getString("sentences_separator") + getString("no_parcel_selected"); + } + else if (mParcelBillableArea == mParcelActualArea) + { + LLStringUtil::format_map_t string_args; + string_args["[AMOUNT]"] = llformat("%d ", mParcelActualArea); + message += LLTrans::getString("sentences_separator") + getString("parcel_meters", string_args); + } + else + { + + if (mParcelBillableArea > mParcelActualArea) + { + LLStringUtil::format_map_t string_args; + string_args["[AMOUNT]"] = llformat("%d ", mParcelBillableArea); + message += LLTrans::getString("sentences_separator") + getString("premium_land", string_args); + } + else + { + LLStringUtil::format_map_t string_args; + string_args["[AMOUNT]"] = llformat("%d ", mParcelBillableArea); + message += LLTrans::getString("sentences_separator") + getString("discounted_land", string_args); + } + } + + getChild<LLUICtrl>("land_use_reason")->setValue(message); + + getChildView("step_2")->setVisible(true); + getChildView("land_use_action")->setVisible(true); + getChildView("land_use_reason")->setVisible(true); + } + else + { + getChildView("step_2")->setVisible(false); + getChildView("land_use_action")->setVisible(false); + getChildView("land_use_reason")->setVisible(false); + } + + // section three: purchase & currency + S32 finalBalance = mAgentCashBalance + mCurrency.getAmount() - mParcelPrice; + bool willHaveEnough = finalBalance >= 0; + bool haveEnough = mAgentCashBalance >= mParcelPrice; + S32 minContribution = llceil((F32)mParcelBillableArea / GROUP_LAND_BONUS_FACTOR); + bool groupContributionEnough = mParcelGroupContribution >= minContribution; + + mCurrency.updateUI(!showingError && !haveEnough); + + if (!showingError) + { + mChildren.setBadge(std::string("step_3"), + !willHaveEnough + ? LLViewChildren::BADGE_WARN + : mCurrency.getAmount() > 0 + ? LLViewChildren::BADGE_NOTE + : LLViewChildren::BADGE_OK); + + LLStringUtil::format_map_t string_args; + string_args["[AMOUNT]"] = llformat("%d", mParcelPrice); + string_args["[SELLER]"] = mParcelSellerName; + getChild<LLUICtrl>("purchase_action")->setValue(getString("pay_to_for_land", string_args)); + getChildView("purchase_action")->setVisible( mParcelValid); + + std::string reasonString; + + if (haveEnough) + { + LLStringUtil::format_map_t string_args; + string_args["[AMOUNT]"] = llformat("%d", mAgentCashBalance); + + getChild<LLUICtrl>("currency_reason")->setValue(getString("have_enough_lindens", string_args)); + } + else + { + LLStringUtil::format_map_t string_args; + string_args["[AMOUNT]"] = llformat("%d", mAgentCashBalance); + string_args["[AMOUNT2]"] = llformat("%d", mParcelPrice - mAgentCashBalance); + + getChild<LLUICtrl>("currency_reason")->setValue(getString("not_enough_lindens", string_args)); + + getChild<LLUICtrl>("currency_est")->setTextArg("[LOCAL_AMOUNT]", mCurrency.getLocalEstimate()); + } + + if (willHaveEnough) + { + LLStringUtil::format_map_t string_args; + string_args["[AMOUNT]"] = llformat("%d", finalBalance); + + getChild<LLUICtrl>("currency_balance")->setValue(getString("balance_left", string_args)); + + } + else + { + LLStringUtil::format_map_t string_args; + string_args["[AMOUNT]"] = llformat("%d", mParcelPrice - mAgentCashBalance); + + getChild<LLUICtrl>("currency_balance")->setValue(getString("balance_needed", string_args)); + + } + + getChild<LLUICtrl>("remove_contribution")->setValue(LLSD(groupContributionEnough)); + getChildView("remove_contribution")->setEnabled(groupContributionEnough); + bool showRemoveContribution = mParcelIsGroupLand + && (mParcelGroupContribution > 0); + getChildView("remove_contribution")->setLabelArg("[AMOUNT]", + llformat("%d", minContribution)); + getChildView("remove_contribution")->setVisible( showRemoveContribution); + + getChildView("step_3")->setVisible(true); + getChildView("purchase_action")->setVisible(true); + getChildView("currency_reason")->setVisible(true); + getChildView("currency_balance")->setVisible(true); + } + else + { + getChildView("step_3")->setVisible(false); + getChildView("purchase_action")->setVisible(false); + getChildView("currency_reason")->setVisible(false); + getChildView("currency_balance")->setVisible(false); + getChildView("remove_group_donation")->setVisible(false); + } + + + bool agrees_to_covenant = false; + LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant"); + if (check) + { + agrees_to_covenant = check->get(); + } + + getChildView("buy_btn")->setEnabled(mCanBuy && mSiteValid && willHaveEnough && !mTransaction && agrees_to_covenant); +} + +void LLFloaterBuyLandUI::startBuyPreConfirm() +{ + std::string action; + + if (mSiteMembershipUpgrade) + { + action += mSiteMembershipAction; + action += "\n"; + + LLComboBox* levels = getChild<LLComboBox>( "account_level"); + if (levels) + { + action += " * "; + action += mSiteMembershipPlanNames[levels->getCurrentIndex()]; + action += "\n"; + } + } + if (mSiteLandUseUpgrade) + { + action += mSiteLandUseAction; + action += "\n"; + } + if (mCurrency.getAmount() > 0) + { + LLStringUtil::format_map_t string_args; + string_args["[AMOUNT]"] = llformat("%d", mCurrency.getAmount()); + string_args["[LOCAL_AMOUNT]"] = mCurrency.getLocalEstimate(); + + action += getString("buy_for_US", string_args); + } + + LLStringUtil::format_map_t string_args; + string_args["[AMOUNT]"] = llformat("%d", mParcelPrice); + string_args["[SELLER]"] = mParcelSellerName; + action += getString("pay_to_for_land", string_args); + + + LLConfirmationManager::confirm(mSiteConfirm, + action, + *this, + &LLFloaterBuyLandUI::startBuyPostConfirm); +} + +void LLFloaterBuyLandUI::startBuyPostConfirm(const std::string& password) +{ + runWebSitePrep(password); + + mCanBuy = false; + mCannotBuyReason = getString("processing"); + refreshUI(); +} + + +void LLFloaterBuyLandUI::onClickBuy() +{ + startBuyPreConfirm(); +} + +void LLFloaterBuyLandUI::onClickCancel() +{ + closeFloater(); +} + +void LLFloaterBuyLandUI::onClickErrorWeb() +{ + LLWeb::loadURLExternal(mCannotBuyURI); + closeFloater(); +} + + + |