PageRenderTime 166ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llfloaterbuyland.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1381 lines | 1088 code | 215 blank | 78 comment | 130 complexity | 7e60350f4994172fb97b4f50a0c72857 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llfloaterbuyland.cpp
  3. * @brief LLFloaterBuyLand class implementation
  4. *
  5. * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llfloaterbuyland.h"
  28. // viewer includes
  29. #include "llagent.h"
  30. #include "llbutton.h"
  31. #include "llcachename.h"
  32. #include "llcheckboxctrl.h"
  33. #include "llcombobox.h"
  34. #include "llconfirmationmanager.h"
  35. #include "llcurrencyuimanager.h"
  36. #include "llfloater.h"
  37. #include "llfloaterreg.h"
  38. #include "llfloatertools.h"
  39. #include "llframetimer.h"
  40. #include "lliconctrl.h"
  41. #include "lllineeditor.h"
  42. #include "llnotificationsutil.h"
  43. #include "llparcel.h"
  44. #include "llslurl.h"
  45. #include "llstatusbar.h"
  46. #include "lltextbox.h"
  47. #include "lltexturectrl.h"
  48. #include "lltrans.h"
  49. #include "llviewchildren.h"
  50. #include "llviewercontrol.h"
  51. #include "lluictrlfactory.h"
  52. #include "llviewerparcelmgr.h"
  53. #include "llviewerregion.h"
  54. #include "llviewertexteditor.h"
  55. #include "llviewerwindow.h"
  56. #include "llweb.h"
  57. #include "llwindow.h"
  58. #include "llworld.h"
  59. #include "llxmlrpctransaction.h"
  60. #include "llviewernetwork.h"
  61. #include "roles_constants.h"
  62. // NOTE: This is duplicated in lldatamoney.cpp ...
  63. const F32 GROUP_LAND_BONUS_FACTOR = 1.1f;
  64. const F64 CURRENCY_ESTIMATE_FREQUENCY = 0.5;
  65. // how long of a pause in typing a currency buy amount before an
  66. // estimate is fetched from the server
  67. class LLFloaterBuyLandUI
  68. : public LLFloater
  69. {
  70. public:
  71. LLFloaterBuyLandUI(const LLSD& key);
  72. virtual ~LLFloaterBuyLandUI();
  73. /*virtual*/ void onClose(bool app_quitting);
  74. // Left padding for maturity rating icon.
  75. static const S32 ICON_PAD = 2;
  76. private:
  77. class SelectionObserver : public LLParcelObserver
  78. {
  79. public:
  80. SelectionObserver(LLFloaterBuyLandUI* floater) : mFloater(floater) {}
  81. virtual void changed();
  82. private:
  83. LLFloaterBuyLandUI* mFloater;
  84. };
  85. private:
  86. SelectionObserver mParcelSelectionObserver;
  87. LLViewerRegion* mRegion;
  88. LLParcelSelectionHandle mParcel;
  89. bool mIsClaim;
  90. bool mIsForGroup;
  91. bool mCanBuy;
  92. bool mCannotBuyIsError;
  93. std::string mCannotBuyReason;
  94. std::string mCannotBuyURI;
  95. bool mBought;
  96. // information about the agent
  97. S32 mAgentCommittedTier;
  98. S32 mAgentCashBalance;
  99. bool mAgentHasNeverOwnedLand;
  100. // information about the parcel
  101. bool mParcelValid;
  102. bool mParcelIsForSale;
  103. bool mParcelIsGroupLand;
  104. S32 mParcelGroupContribution;
  105. S32 mParcelPrice;
  106. S32 mParcelActualArea;
  107. S32 mParcelBillableArea;
  108. S32 mParcelSupportedObjects;
  109. bool mParcelSoldWithObjects;
  110. std::string mParcelLocation;
  111. LLUUID mParcelSnapshot;
  112. std::string mParcelSellerName;
  113. // user's choices
  114. S32 mUserPlanChoice;
  115. // from website
  116. bool mSiteValid;
  117. bool mSiteMembershipUpgrade;
  118. std::string mSiteMembershipAction;
  119. std::vector<std::string>
  120. mSiteMembershipPlanIDs;
  121. std::vector<std::string>
  122. mSiteMembershipPlanNames;
  123. bool mSiteLandUseUpgrade;
  124. std::string mSiteLandUseAction;
  125. std::string mSiteConfirm;
  126. // values in current Preflight transaction... used to avoid extra
  127. // preflights when the parcel manager goes update crazy
  128. S32 mPreflightAskBillableArea;
  129. S32 mPreflightAskCurrencyBuy;
  130. LLViewChildren mChildren;
  131. LLCurrencyUIManager mCurrency;
  132. enum TransactionType
  133. {
  134. TransactionPreflight,
  135. TransactionCurrency,
  136. TransactionBuy
  137. };
  138. LLXMLRPCTransaction* mTransaction;
  139. TransactionType mTransactionType;
  140. LLViewerParcelMgr::ParcelBuyInfo* mParcelBuyInfo;
  141. public:
  142. void setForGroup(bool is_for_group);
  143. void setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel);
  144. void updateAgentInfo();
  145. void updateParcelInfo();
  146. void updateCovenantInfo();
  147. static void onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data);
  148. void updateFloaterCovenantText(const std::string& string, const LLUUID &asset_id);
  149. void updateFloaterEstateName(const std::string& name);
  150. void updateFloaterLastModified(const std::string& text);
  151. void updateFloaterEstateOwnerName(const std::string& name);
  152. void updateWebSiteInfo();
  153. void finishWebSiteInfo();
  154. void runWebSitePrep(const std::string& password);
  155. void finishWebSitePrep();
  156. void sendBuyLand();
  157. void updateNames();
  158. // Name cache callback
  159. void updateGroupName(const LLUUID& id,
  160. const std::string& name,
  161. bool is_group);
  162. void refreshUI();
  163. void startTransaction(TransactionType type, const LLXMLRPCValue& params);
  164. bool checkTransaction();
  165. void tellUserError(const std::string& message, const std::string& uri);
  166. virtual BOOL postBuild();
  167. void startBuyPreConfirm();
  168. void startBuyPostConfirm(const std::string& password);
  169. void onClickBuy();
  170. void onClickCancel();
  171. void onClickErrorWeb();
  172. virtual void draw();
  173. virtual BOOL canClose();
  174. void onVisibilityChange ( const LLSD& new_visibility );
  175. };
  176. // static
  177. void LLFloaterBuyLand::buyLand(
  178. LLViewerRegion* region, LLParcelSelectionHandle parcel, bool is_for_group)
  179. {
  180. if(is_for_group && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED))
  181. {
  182. LLNotificationsUtil::add("OnlyOfficerCanBuyLand");
  183. return;
  184. }
  185. LLFloaterBuyLandUI* ui = LLFloaterReg::showTypedInstance<LLFloaterBuyLandUI>("buy_land");
  186. if (ui)
  187. {
  188. ui->setForGroup(is_for_group);
  189. ui->setParcel(region, parcel);
  190. }
  191. }
  192. // static
  193. void LLFloaterBuyLand::updateCovenantText(const std::string& string, const LLUUID &asset_id)
  194. {
  195. LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land");
  196. if (floater)
  197. {
  198. floater->updateFloaterCovenantText(string, asset_id);
  199. }
  200. }
  201. // static
  202. void LLFloaterBuyLand::updateEstateName(const std::string& name)
  203. {
  204. LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land");
  205. if (floater)
  206. {
  207. floater->updateFloaterEstateName(name);
  208. }
  209. }
  210. // static
  211. void LLFloaterBuyLand::updateLastModified(const std::string& text)
  212. {
  213. LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land");
  214. if (floater)
  215. {
  216. floater->updateFloaterLastModified(text);
  217. }
  218. }
  219. // static
  220. void LLFloaterBuyLand::updateEstateOwnerName(const std::string& name)
  221. {
  222. LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance<LLFloaterBuyLandUI>("buy_land");
  223. if (floater)
  224. {
  225. floater->updateFloaterEstateOwnerName(name);
  226. }
  227. }
  228. // static
  229. LLFloater* LLFloaterBuyLand::buildFloater(const LLSD& key)
  230. {
  231. LLFloaterBuyLandUI* floater = new LLFloaterBuyLandUI(key);
  232. return floater;
  233. }
  234. //----------------------------------------------------------------------------
  235. // LLFloaterBuyLandUI
  236. //----------------------------------------------------------------------------
  237. #if LL_WINDOWS
  238. // passing 'this' during construction generates a warning. The callee
  239. // only uses the pointer to hold a reference to 'this' which is
  240. // already valid, so this call does the correct thing. Disable the
  241. // warning so that we can compile without generating a warning.
  242. #pragma warning(disable : 4355)
  243. #endif
  244. LLFloaterBuyLandUI::LLFloaterBuyLandUI(const LLSD& key)
  245. : LLFloater(LLSD()),
  246. mParcelSelectionObserver(this),
  247. mParcel(0),
  248. mBought(false),
  249. mParcelValid(false), mSiteValid(false),
  250. mChildren(*this), mCurrency(*this), mTransaction(0),
  251. mParcelBuyInfo(0)
  252. {
  253. LLViewerParcelMgr::getInstance()->addObserver(&mParcelSelectionObserver);
  254. }
  255. LLFloaterBuyLandUI::~LLFloaterBuyLandUI()
  256. {
  257. LLViewerParcelMgr::getInstance()->removeObserver(&mParcelSelectionObserver);
  258. LLViewerParcelMgr::getInstance()->deleteParcelBuy(&mParcelBuyInfo);
  259. delete mTransaction;
  260. }
  261. // virtual
  262. void LLFloaterBuyLandUI::onClose(bool app_quitting)
  263. {
  264. // This object holds onto observer, transactions, and parcel state.
  265. // Despite being single_instance, destroy it to call destructors and clean
  266. // everything up.
  267. setVisible(FALSE);
  268. destroy();
  269. }
  270. void LLFloaterBuyLandUI::SelectionObserver::changed()
  271. {
  272. if (LLViewerParcelMgr::getInstance()->selectionEmpty())
  273. {
  274. mFloater->closeFloater();
  275. }
  276. else
  277. {
  278. mFloater->setParcel(LLViewerParcelMgr::getInstance()->getSelectionRegion(),
  279. LLViewerParcelMgr::getInstance()->getParcelSelection());
  280. }
  281. }
  282. void LLFloaterBuyLandUI::updateAgentInfo()
  283. {
  284. mAgentCommittedTier = gStatusBar->getSquareMetersCommitted();
  285. mAgentCashBalance = gStatusBar->getBalance();
  286. // *TODO: This is an approximation, we should send this value down
  287. // to the viewer. See SL-10728 for details.
  288. mAgentHasNeverOwnedLand = mAgentCommittedTier == 0;
  289. }
  290. void LLFloaterBuyLandUI::updateParcelInfo()
  291. {
  292. LLParcel* parcel = mParcel->getParcel();
  293. mParcelValid = parcel && mRegion;
  294. mParcelIsForSale = false;
  295. mParcelIsGroupLand = false;
  296. mParcelGroupContribution = 0;
  297. mParcelPrice = 0;
  298. mParcelActualArea = 0;
  299. mParcelBillableArea = 0;
  300. mParcelSupportedObjects = 0;
  301. mParcelSoldWithObjects = false;
  302. mParcelLocation = "";
  303. mParcelSnapshot.setNull();
  304. mParcelSellerName = "";
  305. mCanBuy = false;
  306. mCannotBuyIsError = false;
  307. if (!mParcelValid)
  308. {
  309. mCannotBuyReason = getString("no_land_selected");
  310. return;
  311. }
  312. if (mParcel->getMultipleOwners())
  313. {
  314. mCannotBuyReason = getString("multiple_parcels_selected");
  315. return;
  316. }
  317. const LLUUID& parcelOwner = parcel->getOwnerID();
  318. mIsClaim = parcel->isPublic();
  319. if (!mIsClaim)
  320. {
  321. mParcelActualArea = parcel->getArea();
  322. mParcelIsForSale = parcel->getForSale();
  323. mParcelIsGroupLand = parcel->getIsGroupOwned();
  324. mParcelPrice = mParcelIsForSale ? parcel->getSalePrice() : 0;
  325. if (mParcelIsGroupLand)
  326. {
  327. LLUUID group_id = parcel->getGroupID();
  328. mParcelGroupContribution = gAgent.getGroupContribution(group_id);
  329. }
  330. }
  331. else
  332. {
  333. mParcelActualArea = mParcel->getClaimableArea();
  334. mParcelIsForSale = true;
  335. mParcelPrice = mParcelActualArea * parcel->getClaimPricePerMeter();
  336. }
  337. mParcelBillableArea =
  338. llround(mRegion->getBillableFactor() * mParcelActualArea);
  339. mParcelSupportedObjects = llround(
  340. parcel->getMaxPrimCapacity() * parcel->getParcelPrimBonus());
  341. // Can't have more than region max tasks, regardless of parcel
  342. // object bonus factor.
  343. LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
  344. if(region)
  345. {
  346. S32 max_tasks_per_region = (S32)region->getMaxTasks();
  347. mParcelSupportedObjects = llmin(
  348. mParcelSupportedObjects, max_tasks_per_region);
  349. }
  350. mParcelSoldWithObjects = parcel->getSellWithObjects();
  351. LLVector3 center = parcel->getCenterpoint();
  352. mParcelLocation = llformat("%s %d,%d",
  353. mRegion->getName().c_str(),
  354. (int)center[VX], (int)center[VY]
  355. );
  356. mParcelSnapshot = parcel->getSnapshotID();
  357. updateNames();
  358. bool haveEnoughCash = mParcelPrice <= mAgentCashBalance;
  359. S32 cashBuy = haveEnoughCash ? 0 : (mParcelPrice - mAgentCashBalance);
  360. mCurrency.setAmount(cashBuy, true);
  361. mCurrency.setZeroMessage(haveEnoughCash ? getString("none_needed") : LLStringUtil::null);
  362. // checks that we can buy the land
  363. if(mIsForGroup && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED))
  364. {
  365. mCannotBuyReason = getString("cant_buy_for_group");
  366. return;
  367. }
  368. if (!mIsClaim)
  369. {
  370. const LLUUID& authorizedBuyer = parcel->getAuthorizedBuyerID();
  371. const LLUUID buyer = gAgent.getID();
  372. const LLUUID newOwner = mIsForGroup ? gAgent.getGroupID() : buyer;
  373. if (!mParcelIsForSale
  374. || (mParcelPrice == 0 && authorizedBuyer.isNull()))
  375. {
  376. mCannotBuyReason = getString("parcel_not_for_sale");
  377. return;
  378. }
  379. if (parcelOwner == newOwner)
  380. {
  381. if (mIsForGroup)
  382. {
  383. mCannotBuyReason = getString("group_already_owns");
  384. }
  385. else
  386. {
  387. mCannotBuyReason = getString("you_already_own");
  388. }
  389. return;
  390. }
  391. if (!authorizedBuyer.isNull() && buyer != authorizedBuyer)
  392. {
  393. // Maybe the parcel is set for sale to a group we are in.
  394. bool authorized_group =
  395. gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_DEED)
  396. && gAgent.hasPowerInGroup(authorizedBuyer,GP_LAND_SET_SALE_INFO);
  397. if (!authorized_group)
  398. {
  399. mCannotBuyReason = getString("set_to_sell_to_other");
  400. return;
  401. }
  402. }
  403. }
  404. else
  405. {
  406. if (mParcelActualArea == 0)
  407. {
  408. mCannotBuyReason = getString("no_public_land");
  409. return;
  410. }
  411. if (mParcel->hasOthersSelected())
  412. {
  413. // Policy: Must not have someone else's land selected
  414. mCannotBuyReason = getString("not_owned_by_you");
  415. return;
  416. }
  417. }
  418. mCanBuy = true;
  419. }
  420. void LLFloaterBuyLandUI::updateCovenantInfo()
  421. {
  422. LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion();
  423. if(!region) return;
  424. U8 sim_access = region->getSimAccess();
  425. std::string rating = LLViewerRegion::accessToString(sim_access);
  426. LLTextBox* region_name = getChild<LLTextBox>("region_name_text");
  427. if (region_name)
  428. {
  429. std::string region_name_txt = region->getName() + " ("+rating +")";
  430. region_name->setText(region_name_txt);
  431. LLIconCtrl* rating_icon = getChild<LLIconCtrl>("rating_icon");
  432. LLRect rect = rating_icon->getRect();
  433. S32 region_name_width = llmin(region_name->getRect().getWidth(), region_name->getTextBoundingRect().getWidth());
  434. S32 icon_left_pad = region_name->getRect().mLeft + region_name_width + ICON_PAD;
  435. region_name->setToolTip(region_name->getText());
  436. rating_icon->setRect(rect.setOriginAndSize(icon_left_pad, rect.mBottom, rect.getWidth(), rect.getHeight()));
  437. switch(sim_access)
  438. {
  439. case SIM_ACCESS_PG:
  440. rating_icon->setValue(getString("icon_PG"));
  441. break;
  442. case SIM_ACCESS_ADULT:
  443. rating_icon->setValue(getString("icon_R"));
  444. break;
  445. default:
  446. rating_icon->setValue(getString("icon_M"));
  447. }
  448. }
  449. LLTextBox* region_type = getChild<LLTextBox>("region_type_text");
  450. if (region_type)
  451. {
  452. region_type->setText(region->getLocalizedSimProductName());
  453. region_type->setToolTip(region->getLocalizedSimProductName());
  454. }
  455. LLTextBox* resellable_clause = getChild<LLTextBox>("resellable_clause");
  456. if (resellable_clause)
  457. {
  458. if (region->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL)
  459. {
  460. resellable_clause->setText(getString("can_not_resell"));
  461. }
  462. else
  463. {
  464. resellable_clause->setText(getString("can_resell"));
  465. }
  466. }
  467. LLTextBox* changeable_clause = getChild<LLTextBox>("changeable_clause");
  468. if (changeable_clause)
  469. {
  470. if (region->getRegionFlags() & REGION_FLAGS_ALLOW_PARCEL_CHANGES)
  471. {
  472. changeable_clause->setText(getString("can_change"));
  473. }
  474. else
  475. {
  476. changeable_clause->setText(getString("can_not_change"));
  477. }
  478. }
  479. LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant");
  480. if(check)
  481. {
  482. check->set(false);
  483. check->setEnabled(true);
  484. check->setCommitCallback(onChangeAgreeCovenant, this);
  485. }
  486. LLTextBox* box = getChild<LLTextBox>("covenant_text");
  487. if(box)
  488. {
  489. box->setVisible(FALSE);
  490. }
  491. // send EstateCovenantInfo message
  492. LLMessageSystem *msg = gMessageSystem;
  493. msg->newMessage("EstateCovenantRequest");
  494. msg->nextBlockFast(_PREHASH_AgentData);
  495. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  496. msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
  497. msg->sendReliable(region->getHost());
  498. }
  499. // static
  500. void LLFloaterBuyLandUI::onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data)
  501. {
  502. LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)user_data;
  503. if(self)
  504. {
  505. self->refreshUI();
  506. }
  507. }
  508. void LLFloaterBuyLandUI::updateFloaterCovenantText(const std::string &string, const LLUUID& asset_id)
  509. {
  510. LLViewerTextEditor* editor = getChild<LLViewerTextEditor>("covenant_editor");
  511. editor->setText(string);
  512. LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant");
  513. LLTextBox* box = getChild<LLTextBox>("covenant_text");
  514. if (asset_id.isNull())
  515. {
  516. check->set(true);
  517. check->setEnabled(false);
  518. refreshUI();
  519. // remove the line stating that you must agree
  520. box->setVisible(FALSE);
  521. }
  522. else
  523. {
  524. check->setEnabled(true);
  525. // remove the line stating that you must agree
  526. box->setVisible(TRUE);
  527. }
  528. }
  529. void LLFloaterBuyLandUI::updateFloaterEstateName(const std::string& name)
  530. {
  531. LLTextBox* box = getChild<LLTextBox>("estate_name_text");
  532. box->setText(name);
  533. box->setToolTip(name);
  534. }
  535. void LLFloaterBuyLandUI::updateFloaterLastModified(const std::string& text)
  536. {
  537. LLTextBox* editor = getChild<LLTextBox>("covenant_timestamp_text");
  538. if (editor) editor->setText(text);
  539. }
  540. void LLFloaterBuyLandUI::updateFloaterEstateOwnerName(const std::string& name)
  541. {
  542. LLTextBox* box = getChild<LLTextBox>("estate_owner_text");
  543. if (box) box->setText(name);
  544. }
  545. void LLFloaterBuyLandUI::updateWebSiteInfo()
  546. {
  547. S32 askBillableArea = mIsForGroup ? 0 : mParcelBillableArea;
  548. S32 askCurrencyBuy = mCurrency.getAmount();
  549. if (mTransaction && mTransactionType == TransactionPreflight
  550. && mPreflightAskBillableArea == askBillableArea
  551. && mPreflightAskCurrencyBuy == askCurrencyBuy)
  552. {
  553. return;
  554. }
  555. mPreflightAskBillableArea = askBillableArea;
  556. mPreflightAskCurrencyBuy = askCurrencyBuy;
  557. #if 0
  558. // enable this code if you want the details to blank while we're talking
  559. // to the web site... it's kind of jarring
  560. mSiteValid = false;
  561. mSiteMembershipUpgrade = false;
  562. mSiteMembershipAction = "(waiting)";
  563. mSiteMembershipPlanIDs.clear();
  564. mSiteMembershipPlanNames.clear();
  565. mSiteLandUseUpgrade = false;
  566. mSiteLandUseAction = "(waiting)";
  567. mSiteCurrencyEstimated = false;
  568. mSiteCurrencyEstimatedCost = 0;
  569. #endif
  570. LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
  571. keywordArgs.appendString("agentId", gAgent.getID().asString());
  572. keywordArgs.appendString(
  573. "secureSessionId",
  574. gAgent.getSecureSessionID().asString());
  575. keywordArgs.appendString("language", LLUI::getLanguage());
  576. keywordArgs.appendInt("billableArea", mPreflightAskBillableArea);
  577. keywordArgs.appendInt("currencyBuy", mPreflightAskCurrencyBuy);
  578. LLXMLRPCValue params = LLXMLRPCValue::createArray();
  579. params.append(keywordArgs);
  580. startTransaction(TransactionPreflight, params);
  581. }
  582. void LLFloaterBuyLandUI::finishWebSiteInfo()
  583. {
  584. LLXMLRPCValue result = mTransaction->responseValue();
  585. mSiteValid = result["success"].asBool();
  586. if (!mSiteValid)
  587. {
  588. tellUserError(
  589. result["errorMessage"].asString(),
  590. result["errorURI"].asString()
  591. );
  592. return;
  593. }
  594. LLXMLRPCValue membership = result["membership"];
  595. mSiteMembershipUpgrade = membership["upgrade"].asBool();
  596. mSiteMembershipAction = membership["action"].asString();
  597. mSiteMembershipPlanIDs.clear();
  598. mSiteMembershipPlanNames.clear();
  599. LLXMLRPCValue levels = membership["levels"];
  600. for (LLXMLRPCValue level = levels.rewind();
  601. level.isValid();
  602. level = levels.next())
  603. {
  604. mSiteMembershipPlanIDs.push_back(level["id"].asString());
  605. mSiteMembershipPlanNames.push_back(level["description"].asString());
  606. }
  607. mUserPlanChoice = 0;
  608. LLXMLRPCValue landUse = result["landUse"];
  609. mSiteLandUseUpgrade = landUse["upgrade"].asBool();
  610. mSiteLandUseAction = landUse["action"].asString();
  611. LLXMLRPCValue currency = result["currency"];
  612. if (currency["estimatedCost"].isValid())
  613. {
  614. mCurrency.setUSDEstimate(currency["estimatedCost"].asInt());
  615. }
  616. if (currency["estimatedLocalCost"].isValid())
  617. {
  618. mCurrency.setLocalEstimate(currency["estimatedLocalCost"].asString());
  619. }
  620. mSiteConfirm = result["confirm"].asString();
  621. }
  622. void LLFloaterBuyLandUI::runWebSitePrep(const std::string& password)
  623. {
  624. if (!mCanBuy)
  625. {
  626. return;
  627. }
  628. BOOL remove_contribution = getChild<LLUICtrl>("remove_contribution")->getValue().asBoolean();
  629. mParcelBuyInfo = LLViewerParcelMgr::getInstance()->setupParcelBuy(gAgent.getID(), gAgent.getSessionID(),
  630. gAgent.getGroupID(), mIsForGroup, mIsClaim, remove_contribution);
  631. if (mParcelBuyInfo
  632. && !mSiteMembershipUpgrade
  633. && !mSiteLandUseUpgrade
  634. && mCurrency.getAmount() == 0
  635. && mSiteConfirm != "password")
  636. {
  637. sendBuyLand();
  638. return;
  639. }
  640. std::string newLevel = "noChange";
  641. if (mSiteMembershipUpgrade)
  642. {
  643. LLComboBox* levels = getChild<LLComboBox>( "account_level");
  644. if (levels)
  645. {
  646. mUserPlanChoice = levels->getCurrentIndex();
  647. newLevel = mSiteMembershipPlanIDs[mUserPlanChoice];
  648. }
  649. }
  650. LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
  651. keywordArgs.appendString("agentId", gAgent.getID().asString());
  652. keywordArgs.appendString(
  653. "secureSessionId",
  654. gAgent.getSecureSessionID().asString());
  655. keywordArgs.appendString("language", LLUI::getLanguage());
  656. keywordArgs.appendString("levelId", newLevel);
  657. keywordArgs.appendInt("billableArea",
  658. mIsForGroup ? 0 : mParcelBillableArea);
  659. keywordArgs.appendInt("currencyBuy", mCurrency.getAmount());
  660. keywordArgs.appendInt("estimatedCost", mCurrency.getUSDEstimate());
  661. keywordArgs.appendString("estimatedLocalCost", mCurrency.getLocalEstimate());
  662. keywordArgs.appendString("confirm", mSiteConfirm);
  663. if (!password.empty())
  664. {
  665. keywordArgs.appendString("password", password);
  666. }
  667. LLXMLRPCValue params = LLXMLRPCValue::createArray();
  668. params.append(keywordArgs);
  669. startTransaction(TransactionBuy, params);
  670. }
  671. void LLFloaterBuyLandUI::finishWebSitePrep()
  672. {
  673. LLXMLRPCValue result = mTransaction->responseValue();
  674. bool success = result["success"].asBool();
  675. if (!success)
  676. {
  677. tellUserError(
  678. result["errorMessage"].asString(),
  679. result["errorURI"].asString()
  680. );
  681. return;
  682. }
  683. sendBuyLand();
  684. }
  685. void LLFloaterBuyLandUI::sendBuyLand()
  686. {
  687. if (mParcelBuyInfo)
  688. {
  689. LLViewerParcelMgr::getInstance()->sendParcelBuy(mParcelBuyInfo);
  690. LLViewerParcelMgr::getInstance()->deleteParcelBuy(&mParcelBuyInfo);
  691. mBought = true;
  692. }
  693. }
  694. void LLFloaterBuyLandUI::updateNames()
  695. {
  696. LLParcel* parcelp = mParcel->getParcel();
  697. if (!parcelp)
  698. {
  699. mParcelSellerName = LLStringUtil::null;
  700. return;
  701. }
  702. if (mIsClaim)
  703. {
  704. mParcelSellerName = "Linden Lab";
  705. }
  706. else if (parcelp->getIsGroupOwned())
  707. {
  708. gCacheName->getGroup(parcelp->getGroupID(),
  709. boost::bind(&LLFloaterBuyLandUI::updateGroupName, this,
  710. _1, _2, _3));
  711. }
  712. else
  713. {
  714. mParcelSellerName = LLSLURL("agent", parcelp->getOwnerID(), "completename").getSLURLString();
  715. }
  716. }
  717. void LLFloaterBuyLandUI::updateGroupName(const LLUUID& id,
  718. const std::string& name,
  719. bool is_group)
  720. {
  721. LLParcel* parcelp = mParcel->getParcel();
  722. if (parcelp
  723. && parcelp->getGroupID() == id)
  724. {
  725. // request is current
  726. mParcelSellerName = name;
  727. }
  728. }
  729. void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCValue& params)
  730. {
  731. delete mTransaction;
  732. mTransaction = NULL;
  733. mTransactionType = type;
  734. // Select a URI and method appropriate for the transaction type.
  735. static std::string transaction_uri;
  736. if (transaction_uri.empty())
  737. {
  738. transaction_uri = LLGridManager::getInstance()->getHelperURI() + "landtool.php";
  739. }
  740. const char* method;
  741. switch (mTransactionType)
  742. {
  743. case TransactionPreflight:
  744. method = "preflightBuyLandPrep";
  745. break;
  746. case TransactionBuy:
  747. method = "buyLandPrep";
  748. break;
  749. default:
  750. llwarns << "LLFloaterBuyLandUI: Unknown transaction type!" << llendl;
  751. return;
  752. }
  753. mTransaction = new LLXMLRPCTransaction(
  754. transaction_uri,
  755. method,
  756. params,
  757. false /* don't use gzip */
  758. );
  759. }
  760. bool LLFloaterBuyLandUI::checkTransaction()
  761. {
  762. if (!mTransaction)
  763. {
  764. return false;
  765. }
  766. if (!mTransaction->process())
  767. {
  768. return false;
  769. }
  770. if (mTransaction->status(NULL) != LLXMLRPCTransaction::StatusComplete)
  771. {
  772. tellUserError(mTransaction->statusMessage(), mTransaction->statusURI());
  773. }
  774. else {
  775. switch (mTransactionType)
  776. {
  777. case TransactionPreflight: finishWebSiteInfo(); break;
  778. case TransactionBuy: finishWebSitePrep(); break;
  779. default: ;
  780. }
  781. }
  782. delete mTransaction;
  783. mTransaction = NULL;
  784. return true;
  785. }
  786. void LLFloaterBuyLandUI::tellUserError(
  787. const std::string& message, const std::string& uri)
  788. {
  789. mCanBuy = false;
  790. mCannotBuyIsError = true;
  791. mCannotBuyReason = getString("fetching_error");
  792. mCannotBuyReason += message;
  793. mCannotBuyURI = uri;
  794. }
  795. // virtual
  796. BOOL LLFloaterBuyLandUI::postBuild()
  797. {
  798. setVisibleCallback(boost::bind(&LLFloaterBuyLandUI::onVisibilityChange, this, _2));
  799. mCurrency.prepare();
  800. getChild<LLUICtrl>("buy_btn")->setCommitCallback( boost::bind(&LLFloaterBuyLandUI::onClickBuy, this));
  801. getChild<LLUICtrl>("cancel_btn")->setCommitCallback( boost::bind(&LLFloaterBuyLandUI::onClickCancel, this));
  802. getChild<LLUICtrl>("error_web")->setCommitCallback( boost::bind(&LLFloaterBuyLandUI::onClickErrorWeb, this));
  803. center();
  804. return TRUE;
  805. }
  806. void LLFloaterBuyLandUI::setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel)
  807. {
  808. if (mTransaction && mTransactionType == TransactionBuy)
  809. {
  810. // the user is buying, don't change the selection
  811. return;
  812. }
  813. mRegion = region;
  814. mParcel = parcel;
  815. updateAgentInfo();
  816. updateParcelInfo();
  817. updateCovenantInfo();
  818. if (mCanBuy)
  819. {
  820. updateWebSiteInfo();
  821. }
  822. refreshUI();
  823. }
  824. void LLFloaterBuyLandUI::setForGroup(bool forGroup)
  825. {
  826. mIsForGroup = forGroup;
  827. }
  828. void LLFloaterBuyLandUI::draw()
  829. {
  830. LLFloater::draw();
  831. bool needsUpdate = false;
  832. needsUpdate |= checkTransaction();
  833. needsUpdate |= mCurrency.process();
  834. if (mBought)
  835. {
  836. closeFloater();
  837. }
  838. else if (needsUpdate)
  839. {
  840. if (mCanBuy && mCurrency.hasError())
  841. {
  842. tellUserError(mCurrency.errorMessage(), mCurrency.errorURI());
  843. }
  844. refreshUI();
  845. }
  846. }
  847. // virtual
  848. BOOL LLFloaterBuyLandUI::canClose()
  849. {
  850. bool can_close = (mTransaction ? FALSE : TRUE) && mCurrency.canCancel();
  851. if (!can_close)
  852. {
  853. // explain to user why they can't do this, see DEV-9605
  854. LLNotificationsUtil::add("CannotCloseFloaterBuyLand");
  855. }
  856. return can_close;
  857. }
  858. void LLFloaterBuyLandUI::onVisibilityChange ( const LLSD& new_visibility )
  859. {
  860. if (new_visibility.asBoolean())
  861. {
  862. refreshUI();
  863. }
  864. }
  865. void LLFloaterBuyLandUI::refreshUI()
  866. {
  867. // section zero: title area
  868. {
  869. LLTextureCtrl* snapshot = getChild<LLTextureCtrl>("info_image");
  870. if (snapshot)
  871. {
  872. snapshot->setImageAssetID(
  873. mParcelValid ? mParcelSnapshot : LLUUID::null);
  874. }
  875. if (mParcelValid)
  876. {
  877. getChild<LLUICtrl>("info_parcel")->setValue(mParcelLocation);
  878. LLStringUtil::format_map_t string_args;
  879. string_args["[AMOUNT]"] = llformat("%d", mParcelActualArea);
  880. string_args["[AMOUNT2]"] = llformat("%d", mParcelSupportedObjects);
  881. getChild<LLUICtrl>("info_size")->setValue(getString("meters_supports_object", string_args));
  882. F32 cost_per_sqm = 0.0f;
  883. if (mParcelActualArea > 0)
  884. {
  885. cost_per_sqm = (F32)mParcelPrice / (F32)mParcelActualArea;
  886. }
  887. LLStringUtil::format_map_t info_price_args;
  888. info_price_args["[PRICE]"] = llformat("%d", mParcelPrice);
  889. info_price_args["[PRICE_PER_SQM]"] = llformat("%.1f", cost_per_sqm);
  890. if (mParcelSoldWithObjects)
  891. {
  892. info_price_args["[SOLD_WITH_OBJECTS]"] = getString("sold_with_objects");
  893. }
  894. else
  895. {
  896. info_price_args["[SOLD_WITH_OBJECTS]"] = getString("sold_without_objects");
  897. }
  898. getChild<LLUICtrl>("info_price")->setValue(getString("info_price_string", info_price_args));
  899. getChildView("info_price")->setVisible( mParcelIsForSale);
  900. }
  901. else
  902. {
  903. getChild<LLUICtrl>("info_parcel")->setValue(getString("no_parcel_selected"));
  904. getChild<LLUICtrl>("info_size")->setValue(LLStringUtil::null);
  905. getChild<LLUICtrl>("info_price")->setValue(LLStringUtil::null);
  906. }
  907. getChild<LLUICtrl>("info_action")->setValue(
  908. mCanBuy
  909. ?
  910. mIsForGroup
  911. ? getString("buying_for_group")//"Buying land for group:"
  912. : getString("buying_will")//"Buying this land will:"
  913. :
  914. mCannotBuyIsError
  915. ? getString("cannot_buy_now")//"Cannot buy now:"
  916. : getString("not_for_sale")//"Not for sale:"
  917. );
  918. }
  919. bool showingError = !mCanBuy || !mSiteValid;
  920. // error section
  921. if (showingError)
  922. {
  923. mChildren.setBadge(std::string("step_error"),
  924. mCannotBuyIsError
  925. ? LLViewChildren::BADGE_ERROR
  926. : LLViewChildren::BADGE_WARN);
  927. LLTextBox* message = getChild<LLTextBox>("error_message");
  928. if (message)
  929. {
  930. message->setVisible(true);
  931. message->setValue(LLSD(!mCanBuy ? mCannotBuyReason : "(waiting for data)"));
  932. }
  933. getChildView("error_web")->setVisible(mCannotBuyIsError && !mCannotBuyURI.empty());
  934. }
  935. else
  936. {
  937. getChildView("step_error")->setVisible(FALSE);
  938. getChildView("error_message")->setVisible(FALSE);
  939. getChildView("error_web")->setVisible(FALSE);
  940. }
  941. // section one: account
  942. if (!showingError)
  943. {
  944. mChildren.setBadge(std::string("step_1"),
  945. mSiteMembershipUpgrade
  946. ? LLViewChildren::BADGE_NOTE
  947. : LLViewChildren::BADGE_OK);
  948. getChild<LLUICtrl>("account_action")->setValue(mSiteMembershipAction);
  949. getChild<LLUICtrl>("account_reason")->setValue(
  950. mSiteMembershipUpgrade
  951. ? getString("must_upgrade")
  952. : getString("cant_own_land")
  953. );
  954. LLComboBox* levels = getChild<LLComboBox>( "account_level");
  955. if (levels)
  956. {
  957. levels->setVisible(mSiteMembershipUpgrade);
  958. levels->removeall();
  959. for(std::vector<std::string>::const_iterator i
  960. = mSiteMembershipPlanNames.begin();
  961. i != mSiteMembershipPlanNames.end();
  962. ++i)
  963. {
  964. levels->add(*i);
  965. }
  966. levels->setCurrentByIndex(mUserPlanChoice);
  967. }
  968. getChildView("step_1")->setVisible(TRUE);
  969. getChildView("account_action")->setVisible(TRUE);
  970. getChildView("account_reason")->setVisible(TRUE);
  971. }
  972. else
  973. {
  974. getChildView("step_1")->setVisible(FALSE);
  975. getChildView("account_action")->setVisible(FALSE);
  976. getChildView("account_reason")->setVisible(FALSE);
  977. getChildView("account_level")->setVisible(FALSE);
  978. }
  979. // section two: land use fees
  980. if (!showingError)
  981. {
  982. mChildren.setBadge(std::string("step_2"),
  983. mSiteLandUseUpgrade
  984. ? LLViewChildren::BADGE_NOTE
  985. : LLViewChildren::BADGE_OK);
  986. getChild<LLUICtrl>("land_use_action")->setValue(mSiteLandUseAction);
  987. std::string message;
  988. if (mIsForGroup)
  989. {
  990. LLStringUtil::format_map_t string_args;
  991. string_args["[GROUP]"] = std::string(gAgent.getGroupName());
  992. message += getString("insufficient_land_credits", string_args);
  993. }
  994. else
  995. {
  996. LLStringUtil::format_map_t string_args;
  997. string_args["[BUYER]"] = llformat("%d", mAgentCommittedTier);
  998. message += getString("land_holdings", string_args);
  999. }
  1000. if (!mParcelValid)
  1001. {
  1002. message += LLTrans::getString("sentences_separator") + getString("no_parcel_selected");
  1003. }
  1004. else if (mParcelBillableArea == mParcelActualArea)
  1005. {
  1006. LLStringUtil::format_map_t string_args;
  1007. string_args["[AMOUNT]"] = llformat("%d ", mParcelActualArea);
  1008. message += LLTrans::getString("sentences_separator") + getString("parcel_meters", string_args);
  1009. }
  1010. else
  1011. {
  1012. if (mParcelBillableArea > mParcelActualArea)
  1013. {
  1014. LLStringUtil::format_map_t string_args;
  1015. string_args["[AMOUNT]"] = llformat("%d ", mParcelBillableArea);
  1016. message += LLTrans::getString("sentences_separator") + getString("premium_land", string_args);
  1017. }
  1018. else
  1019. {
  1020. LLStringUtil::format_map_t string_args;
  1021. string_args["[AMOUNT]"] = llformat("%d ", mParcelBillableArea);
  1022. message += LLTrans::getString("sentences_separator") + getString("discounted_land", string_args);
  1023. }
  1024. }
  1025. getChild<LLUICtrl>("land_use_reason")->setValue(message);
  1026. getChildView("step_2")->setVisible(TRUE);
  1027. getChildView("land_use_action")->setVisible(TRUE);
  1028. getChildView("land_use_reason")->setVisible(TRUE);
  1029. }
  1030. else
  1031. {
  1032. getChildView("step_2")->setVisible(FALSE);
  1033. getChildView("land_use_action")->setVisible(FALSE);
  1034. getChildView("land_use_reason")->setVisible(FALSE);
  1035. }
  1036. // section three: purchase & currency
  1037. S32 finalBalance = mAgentCashBalance + mCurrency.getAmount() - mParcelPrice;
  1038. bool willHaveEnough = finalBalance >= 0;
  1039. bool haveEnough = mAgentCashBalance >= mParcelPrice;
  1040. S32 minContribution = llceil((F32)mParcelBillableArea / GROUP_LAND_BONUS_FACTOR);
  1041. bool groupContributionEnough = mParcelGroupContribution >= minContribution;
  1042. mCurrency.updateUI(!showingError && !haveEnough);
  1043. if (!showingError)
  1044. {
  1045. mChildren.setBadge(std::string("step_3"),
  1046. !willHaveEnough
  1047. ? LLViewChildren::BADGE_WARN
  1048. : mCurrency.getAmount() > 0
  1049. ? LLViewChildren::BADGE_NOTE
  1050. : LLViewChildren::BADGE_OK);
  1051. LLStringUtil::format_map_t string_args;
  1052. string_args["[AMOUNT]"] = llformat("%d", mParcelPrice);
  1053. string_args["[SELLER]"] = mParcelSellerName;
  1054. getChild<LLUICtrl>("purchase_action")->setValue(getString("pay_to_for_land", string_args));
  1055. getChildView("purchase_action")->setVisible( mParcelValid);
  1056. std::string reasonString;
  1057. if (haveEnough)
  1058. {
  1059. LLStringUtil::format_map_t string_args;
  1060. string_args["[AMOUNT]"] = llformat("%d", mAgentCashBalance);
  1061. getChild<LLUICtrl>("currency_reason")->setValue(getString("have_enough_lindens", string_args));
  1062. }
  1063. else
  1064. {
  1065. LLStringUtil::format_map_t string_args;
  1066. string_args["[AMOUNT]"] = llformat("%d", mAgentCashBalance);
  1067. string_args["[AMOUNT2]"] = llformat("%d", mParcelPrice - mAgentCashBalance);
  1068. getChild<LLUICtrl>("currency_reason")->setValue(getString("not_enough_lindens", string_args));
  1069. getChild<LLUICtrl>("currency_est")->setTextArg("[LOCAL_AMOUNT]", mCurrency.getLocalEstimate());
  1070. }
  1071. if (willHaveEnough)
  1072. {
  1073. LLStringUtil::format_map_t string_args;
  1074. string_args["[AMOUNT]"] = llformat("%d", finalBalance);
  1075. getChild<LLUICtrl>("currency_balance")->setValue(getString("balance_left", string_args));
  1076. }
  1077. else
  1078. {
  1079. LLStringUtil::format_map_t string_args;
  1080. string_args["[AMOUNT]"] = llformat("%d", mParcelPrice - mAgentCashBalance);
  1081. getChild<LLUICtrl>("currency_balance")->setValue(getString("balance_needed", string_args));
  1082. }
  1083. getChild<LLUICtrl>("remove_contribution")->setValue(LLSD(groupContributionEnough));
  1084. getChildView("remove_contribution")->setEnabled(groupContributionEnough);
  1085. bool showRemoveContribution = mParcelIsGroupLand
  1086. && (mParcelGroupContribution > 0);
  1087. getChildView("remove_contribution")->setLabelArg("[AMOUNT]",
  1088. llformat("%d", minContribution));
  1089. getChildView("remove_contribution")->setVisible( showRemoveContribution);
  1090. getChildView("step_3")->setVisible(TRUE);
  1091. getChildView("purchase_action")->setVisible(TRUE);
  1092. getChildView("currency_reason")->setVisible(TRUE);
  1093. getChildView("currency_balance")->setVisible(TRUE);
  1094. }
  1095. else
  1096. {
  1097. getChildView("step_3")->setVisible(FALSE);
  1098. getChildView("purchase_action")->setVisible(FALSE);
  1099. getChildView("currency_reason")->setVisible(FALSE);
  1100. getChildView("currency_balance")->setVisible(FALSE);
  1101. getChildView("remove_group_donation")->setVisible(FALSE);
  1102. }
  1103. bool agrees_to_covenant = false;
  1104. LLCheckBoxCtrl* check = getChild<LLCheckBoxCtrl>("agree_covenant");
  1105. if (check)
  1106. {
  1107. agrees_to_covenant = check->get();
  1108. }
  1109. getChildView("buy_btn")->setEnabled(mCanBuy && mSiteValid && willHaveEnough && !mTransaction && agrees_to_covenant);
  1110. }
  1111. void LLFloaterBuyLandUI::startBuyPreConfirm()
  1112. {
  1113. std::string action;
  1114. if (mSiteMembershipUpgrade)
  1115. {
  1116. action += mSiteMembershipAction;
  1117. action += "\n";
  1118. LLComboBox* levels = getChild<LLComboBox>( "account_level");
  1119. if (levels)
  1120. {
  1121. action += " * ";
  1122. action += mSiteMembershipPlanNames[levels->getCurrentIndex()];
  1123. action += "\n";
  1124. }
  1125. }
  1126. if (mSiteLandUseUpgrade)
  1127. {
  1128. action += mSiteLandUseAction;
  1129. action += "\n";
  1130. }
  1131. if (mCurrency.getAmount() > 0)
  1132. {
  1133. LLStringUtil::format_map_t string_args;
  1134. string_args["[AMOUNT]"] = llformat("%d", mCurrency.getAmount());
  1135. string_args["[LOCAL_AMOUNT]"] = mCurrency.getLocalEstimate();
  1136. action += getString("buy_for_US", string_args);
  1137. }
  1138. LLStringUtil::format_map_t string_args;
  1139. string_args["[AMOUNT]"] = llformat("%d", mParcelPrice);
  1140. string_args["[SELLER]"] = mParcelSellerName;
  1141. action += getString("pay_to_for_land", string_args);
  1142. LLConfirmationManager::confirm(mSiteConfirm,
  1143. action,
  1144. *this,
  1145. &LLFloaterBuyLandUI::startBuyPostConfirm);
  1146. }
  1147. void LLFloaterBuyLandUI::startBuyPostConfirm(const std::string& password)
  1148. {
  1149. runWebSitePrep(password);
  1150. mCanBuy = false;
  1151. mCannotBuyReason = getString("processing");
  1152. refreshUI();
  1153. }
  1154. void LLFloaterBuyLandUI::onClickBuy()
  1155. {
  1156. startBuyPreConfirm();
  1157. }
  1158. void LLFloaterBuyLandUI::onClickCancel()
  1159. {
  1160. closeFloater();
  1161. }
  1162. void LLFloaterBuyLandUI::onClickErrorWeb()
  1163. {
  1164. LLWeb::loadURLExternal(mCannotBuyURI);
  1165. closeFloater();
  1166. }