aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llfloaterbuyland.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llfloaterbuyland.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/llfloaterbuyland.cpp1377
1 files changed, 1377 insertions, 0 deletions
diff --git a/linden/indra/newview/llfloaterbuyland.cpp b/linden/indra/newview/llfloaterbuyland.cpp
new file mode 100644
index 0000000..ca5f677
--- /dev/null
+++ b/linden/indra/newview/llfloaterbuyland.cpp
@@ -0,0 +1,1377 @@
1/**
2 * @file llfloaterbuyland.cpp
3 * @brief LLFloaterBuyLand class implementation
4 *
5 * Copyright (c) 2005-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "llfloaterbuyland.h"
31
32// viewer includes
33#include "llagent.h"
34#include "llbutton.h"
35#include "llcachename.h"
36#include "llcheckboxctrl.h"
37#include "llcombobox.h"
38#include "llconfirmationmanager.h"
39#include "llcurrencyuimanager.h"
40#include "llfloater.h"
41#include "llfloatertools.h"
42#include "llframetimer.h"
43#include "lliconctrl.h"
44#include "lllineeditor.h"
45#include "llnotify.h"
46#include "llparcel.h"
47#include "llstatusbar.h"
48#include "lltextbox.h"
49#include "lltexturectrl.h"
50#include "llviewchildren.h"
51#include "llviewercontrol.h"
52#include "llvieweruictrlfactory.h"
53#include "llviewerparcelmgr.h"
54#include "llviewerregion.h"
55#include "llviewertexteditor.h"
56#include "llviewerwindow.h"
57#include "llweb.h"
58#include "llwindow.h"
59#include "llworld.h"
60#include "llxmlrpctransaction.h"
61#include "viewer.h"
62#include "roles_constants.h"
63
64// NOTE: This is duplicated in lldatamoney.cpp ...
65const F32 GROUP_LAND_BONUS_FACTOR = 1.1f;
66const F64 CURRENCY_ESTIMATE_FREQUENCY = 0.5;
67 // how long of a pause in typing a currency buy amount before an
68 // esimate is fetched from the server
69
70class LLFloaterBuyLandUI
71: public LLFloater
72{
73private:
74 LLFloaterBuyLandUI();
75 virtual ~LLFloaterBuyLandUI();
76
77 LLViewerRegion* mRegion;
78 LLParcel* mParcel;
79 bool mIsClaim;
80 bool mIsForGroup;
81
82 bool mCanBuy;
83 bool mCannotBuyIsError;
84 std::string mCannotBuyReason;
85 std::string mCannotBuyURI;
86
87 bool mBought;
88
89 // information about the agent
90 S32 mAgentCommittedTier;
91 S32 mAgentCashBalance;
92 bool mAgentHasNeverOwnedLand;
93
94 // information about the parcel
95 bool mParcelValid;
96 bool mParcelIsForSale;
97 bool mParcelIsFirstLand;
98 bool mParcelIsGroupLand;
99 S32 mParcelGroupContribution;
100 S32 mParcelPrice;
101 S32 mParcelActualArea;
102 S32 mParcelBillableArea;
103 S32 mParcelSupportedObjects;
104 bool mParcelSoldWithObjects;
105 std::string mParcelLocation;
106 LLUUID mParcelSnapshot;
107 std::string mParcelSellerName;
108
109 // user's choices
110 S32 mUserPlanChoice;
111
112 // from website
113 bool mSiteValid;
114 bool mSiteMembershipUpgrade;
115 std::string mSiteMembershipAction;
116 std::vector<std::string>
117 mSiteMembershipPlanIDs;
118 std::vector<std::string>
119 mSiteMembershipPlanNames;
120 bool mSiteLandUseUpgrade;
121 std::string mSiteLandUseAction;
122 std::string mSiteConfirm;
123
124 // values in current Preflight transaction... used to avoid extra
125 // preflights when the parcel manager goes update crazy
126 S32 mPreflightAskBillableArea;
127 S32 mPreflightAskCurrencyBuy;
128
129 LLViewChildren mChildren;
130 LLCurrencyUIManager mCurrency;
131
132 enum TransactionType
133 {
134 TransactionPreflight,
135 TransactionCurrency,
136 TransactionBuy
137 };
138 LLXMLRPCTransaction* mTransaction;
139 TransactionType mTransactionType;
140
141 LLViewerParcelMgr::ParcelBuyInfo* mParcelBuyInfo;
142
143 static LLFloaterBuyLandUI* sInstance;
144
145public:
146 static LLFloaterBuyLandUI* soleInstance(bool createIfNeeded);
147
148 void setForGroup(bool is_for_group);
149 void setParcel(LLViewerRegion* region, LLParcel* parcel);
150
151 void updateAgentInfo();
152 void updateParcelInfo();
153 void updateCovenantInfo();
154 static void onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data);
155 void updateCovenantText(const std::string& string, const LLUUID &asset_id);
156 void updateEstateName(const std::string& name);
157 void updateLastModified(const std::string& text);
158 void updateEstateOwnerName(const std::string& name);
159 void updateWebSiteInfo();
160 void finishWebSiteInfo();
161
162 void runWebSitePrep(const std::string& password);
163 void finishWebSitePrep();
164 void sendBuyLand();
165
166 void updateNames();
167
168 void refreshUI();
169
170 void startTransaction(TransactionType type, LLXMLRPCValue params);
171 bool checkTransaction();
172
173 void tellUserError(const std::string& message, const std::string& uri);
174
175 virtual BOOL postBuild();
176
177 void startBuyPreConfirm();
178 void startBuyPostConfirm(const std::string& password);
179
180 static void onClickBuy(void* data);
181 static void onClickCancel(void* data);
182 static void onClickErrorWeb(void* data);
183
184 virtual void draw();
185 virtual BOOL canClose();
186 virtual void onClose(bool app_quitting);
187
188private:
189 class SelectionObserver : public LLParcelObserver
190 {
191 public:
192 virtual void changed();
193 };
194};
195
196static void cacheNameUpdateRefreshesBuyLand(const LLUUID&,
197 const char*, const char*, BOOL, void* data)
198{
199 LLFloaterBuyLandUI* ui = LLFloaterBuyLandUI::soleInstance(false);
200 if (ui)
201 {
202 ui->updateNames();
203 }
204}
205
206// static
207void LLFloaterBuyLand::buyLand(
208 LLViewerRegion* region, LLParcel* parcel, bool is_for_group)
209{
210 if(is_for_group && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED))
211 {
212 gViewerWindow->alertXml("OnlyOfficerCanBuyLand");
213 return;
214 }
215
216 LLFloaterBuyLandUI* ui = LLFloaterBuyLandUI::soleInstance(true);
217 ui->setForGroup(is_for_group);
218 ui->setParcel(region, parcel);
219 ui->open();
220}
221
222// static
223void LLFloaterBuyLand::updateCovenantText(const std::string& string, const LLUUID &asset_id)
224{
225 LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE);
226 if (floater)
227 {
228 floater->updateCovenantText(string, asset_id);
229 }
230}
231
232// static
233void LLFloaterBuyLand::updateEstateName(const std::string& name)
234{
235 LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE);
236 if (floater)
237 {
238 floater->updateEstateName(name);
239 }
240}
241
242// static
243void LLFloaterBuyLand::updateLastModified(const std::string& text)
244{
245 LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE);
246 if (floater)
247 {
248 floater->updateLastModified(text);
249 }
250}
251
252// static
253void LLFloaterBuyLand::updateEstateOwnerName(const std::string& name)
254{
255 LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE);
256 if (floater)
257 {
258 floater->updateEstateOwnerName(name);
259 }
260}
261
262// static
263BOOL LLFloaterBuyLand::isOpen()
264{
265 LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE);
266 if (floater)
267 {
268 return floater->getVisible();
269 }
270 return FALSE;
271}
272
273// static
274LLFloaterBuyLandUI* LLFloaterBuyLandUI::sInstance = NULL;
275
276// static
277LLFloaterBuyLandUI* LLFloaterBuyLandUI::soleInstance(bool createIfNeeded)
278{
279#if !LL_RELEASE_FOR_DOWNLOAD
280 if (createIfNeeded)
281 {
282 delete sInstance;
283 sInstance = NULL;
284 }
285#endif
286 if (!sInstance && createIfNeeded)
287 {
288 sInstance = new LLFloaterBuyLandUI();
289
290 gUICtrlFactory->buildFloater(sInstance, "floater_buy_land.xml");
291 sInstance->center();
292
293 static bool observingCacheName = false;
294 if (!observingCacheName)
295 {
296 gCacheName->addObserver(cacheNameUpdateRefreshesBuyLand);
297 observingCacheName = true;
298 }
299
300 static SelectionObserver* parcelSelectionObserver = NULL;
301 if (!parcelSelectionObserver)
302 {
303 parcelSelectionObserver = new SelectionObserver;
304 gParcelMgr->addObserver(parcelSelectionObserver);
305 }
306 }
307
308 return sInstance;
309}
310
311
312#if LL_WINDOWS
313// passing 'this' during construction generates a warning. The callee
314// only uses the pointer to hold a reference to 'this' which is
315// already valid, so this call does the correct thing. Disable the
316// warning so that we can compile without generating a warning.
317#pragma warning(disable : 4355)
318#endif
319LLFloaterBuyLandUI::LLFloaterBuyLandUI()
320: LLFloater("Buy Land"),
321 mParcel(0),
322 mBought(false),
323 mParcelValid(false), mSiteValid(false),
324 mChildren(*this), mCurrency(*this), mTransaction(0),
325 mParcelBuyInfo(0)
326{
327}
328
329LLFloaterBuyLandUI::~LLFloaterBuyLandUI()
330{
331 delete mTransaction;
332
333 gParcelMgr->deleteParcelBuy(mParcelBuyInfo);
334
335 if (sInstance == this)
336 {
337 sInstance = NULL;
338 }
339}
340
341void LLFloaterBuyLandUI::SelectionObserver::changed()
342{
343 LLFloaterBuyLandUI* ui = LLFloaterBuyLandUI::soleInstance(false);
344 if (ui)
345 {
346 if (gParcelMgr->selectionEmpty())
347 {
348 ui->close();
349 }
350 else {
351 ui->setParcel(
352 gParcelMgr->getSelectionRegion(),
353 gParcelMgr->getSelectedParcel());
354 }
355 }
356}
357
358
359void LLFloaterBuyLandUI::updateAgentInfo()
360{
361 mAgentCommittedTier = gStatusBar->getSquareMetersCommitted();
362 mAgentCashBalance = gStatusBar->getBalance();
363
364 // *TODO: This is an approximation, we should send this value down
365 // to the viewer. See SL-10728 for details.
366 mAgentHasNeverOwnedLand = mAgentCommittedTier == 0;
367}
368
369void LLFloaterBuyLandUI::updateParcelInfo()
370{
371 mParcelValid = mParcel && mRegion;
372 mParcelIsForSale = false;
373 mParcelIsFirstLand = false;
374 mParcelIsGroupLand = false;
375 mParcelGroupContribution = 0;
376 mParcelPrice = 0;
377 mParcelActualArea = 0;
378 mParcelBillableArea = 0;
379 mParcelSupportedObjects = 0;
380 mParcelSoldWithObjects = false;
381 mParcelLocation = "";
382 mParcelSnapshot.setNull();
383 mParcelSellerName = "";
384
385 mCanBuy = false;
386 mCannotBuyIsError = false;
387
388 if (!mParcelValid)
389 {
390 mCannotBuyReason= childGetText("no_land_selected");
391 return;
392 }
393
394 if (gParcelMgr->getMultipleOwners())
395 {
396 mCannotBuyReason = childGetText("multiple_parcels_selected");
397 return;
398 }
399
400
401 const LLUUID& parcelOwner = mParcel->getOwnerID();
402
403 mIsClaim = mParcel->isPublic();
404 if (!mIsClaim)
405 {
406 mParcelActualArea = mParcel->getArea();
407 mParcelIsForSale = mParcel->getForSale();
408 mParcelIsFirstLand = mParcel->getReservedForNewbie();
409 mParcelIsGroupLand = mParcel->getIsGroupOwned();
410 mParcelPrice = mParcelIsForSale ? mParcel->getSalePrice() : 0;
411
412 if (mParcelIsGroupLand)
413 {
414 LLUUID group_id = mParcel->getGroupID();
415 mParcelGroupContribution = gAgent.getGroupContribution(group_id);
416 }
417 }
418 else
419 {
420 mParcelActualArea = gParcelMgr->getClaimableArea();
421 mParcelIsForSale = true;
422 mParcelPrice = mParcelActualArea * mParcel->getClaimPricePerMeter();
423 }
424
425 mParcelBillableArea =
426 llround(mRegion->getBillableFactor() * mParcelActualArea);
427
428 mParcelSupportedObjects = mParcel->getMaxPrimCapacity();
429 mParcelSoldWithObjects = mParcel->getSellWithObjects();
430
431 LLVector3 center = mParcel->getCenterpoint();
432 mParcelLocation = llformat("%s %d,%d",
433 mRegion->getName().c_str(),
434 (int)center[VX], (int)center[VY]
435 );
436
437 mParcelSnapshot = mParcel->getSnapshotID();
438
439 updateNames();
440
441 bool haveEnoughCash = mParcelPrice <= mAgentCashBalance;
442 S32 cashBuy = haveEnoughCash ? 0 : (mParcelPrice - mAgentCashBalance);
443 mCurrency.setAmount(cashBuy, true);
444 mCurrency.setZeroMessage(haveEnoughCash ? childGetText("none_needed") : "");
445
446 // checks that we can buy the land
447
448 if(mIsForGroup && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED))
449 {
450 mCannotBuyReason = childGetText("cant_buy_for_group");
451 return;
452 }
453
454 if (!mIsClaim)
455 {
456 const LLUUID& authorizedBuyer = mParcel->getAuthorizedBuyerID();
457 const LLUUID buyer = gAgent.getID();
458 const LLUUID newOwner = mIsForGroup ? gAgent.getGroupID() : buyer;
459
460 if (!mParcelIsForSale
461 || (mParcelPrice == 0 && authorizedBuyer.isNull()))
462 {
463
464 mCannotBuyReason = childGetText("parcel_not_for_sale");
465 return;
466 }
467
468 if (parcelOwner == newOwner)
469 {
470 if (mIsForGroup)
471 {
472 mCannotBuyReason = childGetText("group_already_owns");
473 }
474 else
475 {
476 mCannotBuyReason = childGetText("you_already_own");
477 }
478 return;
479 }
480
481 if (!authorizedBuyer.isNull() && buyer != authorizedBuyer)
482 {
483 mCannotBuyReason = childGetText("set_to_sell_to_other");
484 return;
485 }
486 }
487 else
488 {
489 if (mParcelActualArea == 0)
490 {
491 mCannotBuyReason = childGetText("no_public_land");
492 return;
493 }
494
495 if (gParcelMgr->hasOthersSelected())
496 {
497 // Policy: Must not have someone else's land selected
498 mCannotBuyReason = childGetText("not_owned_by_you");
499 return;
500 }
501 }
502
503 /*
504 if ((mRegion->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL)
505 && !gAgent.isGodlike())
506 {
507 mCannotBuyReason = llformat(
508 "The region %s does not allow transfer of land.",
509 mRegion->getName().c_str() );
510 return;
511 }
512 */
513
514 if (mParcel->getReservedForNewbie())
515 {
516 if (mIsForGroup)
517 {
518 mCannotBuyReason = childGetText("first_time_group");
519 return;
520 }
521
522 if (gStatusBar->getSquareMetersCommitted() > 0)
523 {
524 mCannotBuyReason == childGetText("first_time");
525 return;
526 }
527
528 // *TODO: There should be a check based on the database value
529 // indra.user.ever_owned_land, only that value never makes it
530 // to the viewer, see SL-10728
531 }
532
533 mCanBuy = true;
534}
535
536void LLFloaterBuyLandUI::updateCovenantInfo()
537{
538 LLViewerRegion* region = gParcelMgr->getSelectionRegion();
539 if(!region) return;
540
541 LLTextBox* region_name = (LLTextBox*)getChildByName("region_name_text");
542 if (region_name)
543 {
544 region_name->setText(region->getName());
545 }
546
547 LLTextBox* resellable_clause = (LLTextBox*)getChildByName("resellable_clause");
548 if (resellable_clause)
549 {
550 if (region->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL)
551 {
552 resellable_clause->setText(childGetText("can_not_resell"));
553 }
554 else
555 {
556 resellable_clause->setText(childGetText("can_resell"));
557 }
558 }
559
560 LLTextBox* changeable_clause = (LLTextBox*)getChildByName("changeable_clause");
561 if (changeable_clause)
562 {
563 if (region->getRegionFlags() & REGION_FLAGS_ALLOW_PARCEL_CHANGES)
564 {
565 changeable_clause->setText(childGetText("can_change"));
566 }
567 else
568 {
569 changeable_clause->setText(childGetText("can_not_change"));
570 }
571 }
572
573 LLCheckBoxCtrl* check = (LLCheckBoxCtrl*)getChildByName("agree_covenant");
574 if(check)
575 {
576 check->set(false);
577 check->setEnabled(true);
578 check->setCallbackUserData(this);
579 check->setCommitCallback(onChangeAgreeCovenant);
580 }
581
582 LLTextBox* box = (LLTextBox*)getChildByName("covenant_text");
583 if(box)
584 {
585 box->setVisible(FALSE);
586 }
587
588 // send EstateCovenantInfo message
589 LLMessageSystem *msg = gMessageSystem;
590 msg->newMessage("EstateCovenantRequest");
591 msg->nextBlockFast(_PREHASH_AgentData);
592 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
593 msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
594 msg->sendReliable(region->getHost());
595}
596
597// static
598void LLFloaterBuyLandUI::onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data)
599{
600 LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)user_data;
601 if(self)
602 {
603 self->refreshUI();
604 }
605}
606
607void LLFloaterBuyLandUI::updateCovenantText(const std::string &string, const LLUUID& asset_id)
608{
609 LLViewerTextEditor* editor = (LLViewerTextEditor*)getChildByName("covenant_editor");
610 if (editor)
611 {
612 editor->setHandleEditKeysDirectly(FALSE);
613 editor->setText(string);
614
615 LLCheckBoxCtrl* check = (LLCheckBoxCtrl*)getChildByName("agree_covenant");
616 LLTextBox* box = (LLTextBox*)getChildByName("covenant_text");
617 if(check && box)
618 {
619 if (asset_id.isNull())
620 {
621 check->set(true);
622 check->setEnabled(false);
623 refreshUI();
624
625 // remove the line stating that you must agree
626 box->setVisible(FALSE);
627 }
628 else
629 {
630 check->setEnabled(true);
631
632 // remove the line stating that you must agree
633 box->setVisible(TRUE);
634 }
635 }
636 }
637}
638
639void LLFloaterBuyLandUI::updateEstateName(const std::string& name)
640{
641 LLTextBox* box = (LLTextBox*)getChildByName("estate_name_text");
642 if (box) box->setText(name);
643}
644
645void LLFloaterBuyLandUI::updateLastModified(const std::string& text)
646{
647 LLTextBox* editor = (LLTextBox*)getChildByName("covenant_timestamp_text");
648 if (editor) editor->setText(text);
649}
650
651void LLFloaterBuyLandUI::updateEstateOwnerName(const std::string& name)
652{
653 LLTextBox* box = (LLTextBox*)getChildByName("estate_owner_text");
654 if (box) box->setText(name);
655}
656
657void LLFloaterBuyLandUI::updateWebSiteInfo()
658{
659 S32 askBillableArea = mIsForGroup ? 0 : mParcelBillableArea;
660 S32 askCurrencyBuy = mCurrency.getAmount();
661
662 if (mTransaction && mTransactionType == TransactionPreflight
663 && mPreflightAskBillableArea == askBillableArea
664 && mPreflightAskCurrencyBuy == askCurrencyBuy)
665 {
666 return;
667 }
668
669 mPreflightAskBillableArea = askBillableArea;
670 mPreflightAskCurrencyBuy = askCurrencyBuy;
671
672#if 0
673 // enable this code if you want the details to blank while we're talking
674 // to the web site... it's kind of jarring
675 mSiteValid = false;
676 mSiteMembershipUpgrade = false;
677 mSiteMembershipAction = "(waiting)";
678 mSiteMembershipPlanIDs.clear();
679 mSiteMembershipPlanNames.clear();
680 mSiteLandUseUpgrade = false;
681 mSiteLandUseAction = "(waiting)";
682 mSiteCurrencyEstimated = false;
683 mSiteCurrencyEstimatedCost = 0;
684#endif
685
686 LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
687 keywordArgs.appendString("agentId", gAgent.getID().getString());
688 keywordArgs.appendString("secureSessionId",
689 gAgent.getSecureSessionID().getString());
690 keywordArgs.appendInt("billableArea", mPreflightAskBillableArea);
691 keywordArgs.appendInt("currencyBuy", mPreflightAskCurrencyBuy);
692
693 LLXMLRPCValue params = LLXMLRPCValue::createArray();
694 params.append(keywordArgs);
695
696 startTransaction(TransactionPreflight, params);
697}
698
699void LLFloaterBuyLandUI::finishWebSiteInfo()
700{
701
702 LLXMLRPCValue result = mTransaction->responseValue();
703
704 mSiteValid = result["success"].asBool();
705 if (!mSiteValid)
706 {
707 tellUserError(
708 result["errorMessage"].asString(),
709 result["errorURI"].asString()
710 );
711 return;
712 }
713
714 LLXMLRPCValue membership = result["membership"];
715 mSiteMembershipUpgrade = membership["upgrade"].asBool();
716 mSiteMembershipAction = membership["action"].asString();
717 mSiteMembershipPlanIDs.clear();
718 mSiteMembershipPlanNames.clear();
719 LLXMLRPCValue levels = membership["levels"];
720 for (LLXMLRPCValue level = levels.rewind();
721 level.isValid();
722 level = levels.next())
723 {
724 mSiteMembershipPlanIDs.push_back(level["id"].asString());
725 mSiteMembershipPlanNames.push_back(level["description"].asString());
726 }
727 mUserPlanChoice = 0;
728
729 LLXMLRPCValue landUse = result["landUse"];
730 mSiteLandUseUpgrade = landUse["upgrade"].asBool();
731 mSiteLandUseAction = landUse["action"].asString();
732
733 LLXMLRPCValue currency = result["currency"];
734 mCurrency.setEstimate(currency["estimatedCost"].asInt());
735
736 mSiteConfirm = result["confirm"].asString();
737}
738
739void LLFloaterBuyLandUI::runWebSitePrep(const std::string& password)
740{
741 if (!mCanBuy)
742 {
743 return;
744 }
745
746 BOOL remove_contribution = childGetValue("remove_contribution").asBoolean();
747 mParcelBuyInfo = gParcelMgr->setupParcelBuy(gAgent.getID(), gAgent.getSessionID(),
748 gAgent.getGroupID(), mIsForGroup, mIsClaim, remove_contribution);
749
750 if (mParcelBuyInfo
751 && !mSiteMembershipUpgrade
752 && !mSiteLandUseUpgrade
753 && mCurrency.getAmount() == 0
754 && mSiteConfirm != "password")
755 {
756 sendBuyLand();
757 return;
758 }
759
760
761 std::string newLevel = "noChange";
762
763 if (mSiteMembershipUpgrade)
764 {
765 LLComboBox* levels = LLUICtrlFactory::getComboBoxByName(this, "account_level");
766 if (levels)
767 {
768 mUserPlanChoice = levels->getCurrentIndex();
769 newLevel = mSiteMembershipPlanIDs[mUserPlanChoice];
770 }
771 }
772
773 LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
774 keywordArgs.appendString("agentId", gAgent.getID().getString());
775 keywordArgs.appendString("secureSessionId",
776 gAgent.getSecureSessionID().getString());
777 keywordArgs.appendString("levelId", newLevel);
778 keywordArgs.appendInt("billableArea",
779 mIsForGroup ? 0 : mParcelBillableArea);
780 keywordArgs.appendInt("currencyBuy", mCurrency.getAmount());
781 keywordArgs.appendInt("estimatedCost", mCurrency.getEstimate());
782 keywordArgs.appendString("confirm", mSiteConfirm);
783 if (!password.empty())
784 {
785 keywordArgs.appendString("password", password);
786 }
787
788 LLXMLRPCValue params = LLXMLRPCValue::createArray();
789 params.append(keywordArgs);
790
791 startTransaction(TransactionBuy, params);
792}
793
794void LLFloaterBuyLandUI::finishWebSitePrep()
795{
796 LLXMLRPCValue result = mTransaction->responseValue();
797
798 bool success = result["success"].asBool();
799 if (!success)
800 {
801 tellUserError(
802 result["errorMessage"].asString(),
803 result["errorURI"].asString()
804 );
805 return;
806 }
807
808 sendBuyLand();
809}
810
811void LLFloaterBuyLandUI::sendBuyLand()
812{
813 if (mParcelBuyInfo)
814 {
815 gParcelMgr->sendParcelBuy(mParcelBuyInfo);
816 gParcelMgr->deleteParcelBuy(mParcelBuyInfo);
817 mBought = true;
818 }
819}
820
821void LLFloaterBuyLandUI::updateNames()
822{
823 if (!mParcelValid)
824 {
825 mParcelSellerName = "";
826 return;
827 }
828
829 if (mIsClaim)
830 {
831 mParcelSellerName = "Linden Lab";
832 }
833 else if (mParcel->getIsGroupOwned())
834 {
835 char groupName[DB_LAST_NAME_BUF_SIZE];
836
837 gCacheName->getGroupName(mParcel->getGroupID(), &groupName[0]);
838 mParcelSellerName = groupName;
839 }
840 else
841 {
842 char firstName[DB_LAST_NAME_BUF_SIZE];
843 char lastName[DB_LAST_NAME_BUF_SIZE];
844
845 gCacheName->getName(mParcel->getOwnerID(), firstName, lastName);
846 mParcelSellerName = llformat("%s %s", firstName, lastName);
847 }
848}
849
850
851void LLFloaterBuyLandUI::startTransaction(TransactionType type,
852 LLXMLRPCValue params)
853{
854 delete mTransaction;
855 mTransaction = NULL;
856
857 mTransactionType = type;
858
859 // Select a URI and method appropriate for the transaction type.
860 static std::string transaction_uri;
861 if (transaction_uri.empty())
862 {
863 transaction_uri = getHelperURI() + "landtool.php";
864 }
865
866 const char* method;
867 switch (mTransactionType)
868 {
869 case TransactionPreflight:
870 method = "preflightBuyLandPrep";
871 break;
872 case TransactionBuy:
873 method = "buyLandPrep";
874 break;
875 default:
876 llwarns << "LLFloaterBuyLandUI: Unknown transaction type!" << llendl;
877 return;
878 }
879
880 mTransaction = new LLXMLRPCTransaction(
881 transaction_uri,
882 method,
883 params,
884 false /* don't use gzip */
885 );
886}
887
888bool LLFloaterBuyLandUI::checkTransaction()
889{
890 if (!mTransaction)
891 {
892 return false;
893 }
894
895 if (!mTransaction->process())
896 {
897 return false;
898 }
899
900 if (mTransaction->status(NULL) != LLXMLRPCTransaction::StatusComplete)
901 {
902 tellUserError(mTransaction->statusMessage(), mTransaction->statusURI());
903 }
904 else {
905 switch (mTransactionType)
906 {
907 case TransactionPreflight: finishWebSiteInfo(); break;
908 case TransactionBuy: finishWebSitePrep(); break;
909 default: ;
910 }
911 }
912
913 delete mTransaction;
914 mTransaction = NULL;
915
916 return true;
917}
918
919void LLFloaterBuyLandUI::tellUserError(
920 const std::string& message, const std::string& uri)
921{
922 mCanBuy = false;
923 mCannotBuyIsError = true;
924 mCannotBuyReason = childGetText("fetching_error");
925 mCannotBuyReason += message;
926 mCannotBuyURI = uri;
927}
928
929
930// virtual
931BOOL LLFloaterBuyLandUI::postBuild()
932{
933 mCurrency.prepare();
934
935 childSetAction("buy_btn", onClickBuy, this);
936 childSetAction("cancel_btn", onClickCancel, this);
937 childSetAction("error_web", onClickErrorWeb, this);
938
939 return TRUE;
940}
941
942void LLFloaterBuyLandUI::setParcel(LLViewerRegion* region, LLParcel* parcel)
943{
944 if (mTransaction && mTransactionType == TransactionBuy)
945 {
946 // the user is buying, don't change the selection
947 return;
948 }
949
950 mRegion = region;
951 mParcel = parcel;
952
953 updateAgentInfo();
954 updateParcelInfo();
955 updateCovenantInfo();
956 if (mCanBuy)
957 {
958 updateWebSiteInfo();
959 }
960 refreshUI();
961}
962
963void LLFloaterBuyLandUI::setForGroup(bool forGroup)
964{
965 mIsForGroup = forGroup;
966}
967
968void LLFloaterBuyLandUI::draw()
969{
970 LLFloater::draw();
971
972 bool needsUpdate = false;
973 needsUpdate |= checkTransaction();
974 needsUpdate |= mCurrency.process();
975
976 if (mBought)
977 {
978 close();
979 }
980 else if (needsUpdate)
981 {
982 if (mCanBuy && mCurrency.hasError())
983 {
984 tellUserError(mCurrency.errorMessage(), mCurrency.errorURI());
985 }
986
987 refreshUI();
988 }
989}
990
991BOOL LLFloaterBuyLandUI::canClose()
992{
993 return (mTransaction ? FALSE : TRUE) && mCurrency.canCancel();
994}
995
996void LLFloaterBuyLandUI::onClose(bool app_quitting)
997{
998 LLFloater::onClose(app_quitting);
999 delete this;
1000}
1001
1002
1003void LLFloaterBuyLandUI::refreshUI()
1004{
1005 // section zero: title area
1006 {
1007 LLTextureCtrl* snapshot = LLViewerUICtrlFactory::getTexturePickerByName(this, "info_image");
1008 if (snapshot)
1009 {
1010 snapshot->setImageAssetID(
1011 mParcelValid ? mParcelSnapshot : LLUUID::null);
1012 }
1013
1014
1015
1016 if (mParcelValid)
1017 {
1018 childSetText("info_parcel", mParcelLocation);
1019
1020
1021 childSetTextArg("meters_supports_object", "[AMOUNT]", llformat("%d", mParcelActualArea));
1022 childSetTextArg("meters_supports_object", "[AMOUNT2]", llformat("%d", mParcelSupportedObjects));
1023
1024 childSetText("info_size", childGetText("meters_supports_object"));
1025
1026
1027 childSetText("info_price",
1028 llformat(
1029 "L$ %d%s",
1030 mParcelPrice,
1031 mParcelSoldWithObjects
1032 ? "\nsold with objects"
1033 : ""));
1034 childSetVisible("info_price", mParcelIsForSale);
1035 }
1036 else
1037 {
1038 childSetText("info_parcel", "(no parcel selected)");
1039 childSetText("info_size", "");
1040 childSetText("info_price", "");
1041 }
1042
1043 childSetText("info_action",
1044 mCanBuy
1045 ?
1046 mIsForGroup
1047 ? childGetText("buying_for_group")//"Buying land for group:"
1048 : childGetText("buying_will")//"Buying this land will:"
1049 :
1050 mCannotBuyIsError
1051 ? childGetText("cannot_buy_now")//"Cannot buy now:"
1052 : childGetText("not_for_sale")//"Not for sale:"
1053
1054 );
1055 }
1056
1057 bool showingError = !mCanBuy || !mSiteValid;
1058
1059 // error section
1060 if (showingError)
1061 {
1062 mChildren.setBadge("step_error",
1063 mCannotBuyIsError
1064 ? LLViewChildren::BADGE_ERROR
1065 : LLViewChildren::BADGE_WARN);
1066
1067 LLTextBox* message = LLUICtrlFactory::getTextBoxByName(this, "error_message");
1068 if (message)
1069 {
1070 message->setVisible(true);
1071 message->setWrappedText(
1072 !mCanBuy ? mCannotBuyReason : "(waiting for data)"
1073 );
1074 }
1075
1076 childSetVisible("error_web",
1077 mCannotBuyIsError && !mCannotBuyURI.empty());
1078 }
1079 else
1080 {
1081 childHide("step_error");
1082 childHide("error_message");
1083 childHide("error_web");
1084 }
1085
1086
1087 // section one: account
1088 if (!showingError)
1089 {
1090 mChildren.setBadge("step_1",
1091 mSiteMembershipUpgrade
1092 ? LLViewChildren::BADGE_NOTE
1093 : LLViewChildren::BADGE_OK);
1094 childSetText("account_action", mSiteMembershipAction);
1095 childSetText("account_reason",
1096 mSiteMembershipUpgrade
1097 ? childGetText("must_upgrade")
1098 : childGetText("cant_own_land")
1099 );
1100
1101 LLComboBox* levels = LLUICtrlFactory::getComboBoxByName(this, "account_level");
1102 if (levels)
1103 {
1104 levels->setVisible(mSiteMembershipUpgrade);
1105
1106 levels->removeall();
1107 for(std::vector<std::string>::const_iterator i
1108 = mSiteMembershipPlanNames.begin();
1109 i != mSiteMembershipPlanNames.end();
1110 ++i)
1111 {
1112 levels->add(*i);
1113 }
1114
1115 levels->setCurrentByIndex(mUserPlanChoice);
1116 }
1117
1118 childShow("step_1");
1119 childShow("account_action");
1120 childShow("account_reason");
1121 }
1122 else
1123 {
1124 childHide("step_1");
1125 childHide("account_action");
1126 childHide("account_reason");
1127 childHide("account_level");
1128 }
1129
1130 // section two: land use fees
1131 if (!showingError)
1132 {
1133 mChildren.setBadge("step_2",
1134 mSiteLandUseUpgrade
1135 ? LLViewChildren::BADGE_NOTE
1136 : LLViewChildren::BADGE_OK);
1137 childSetText("land_use_action", mSiteLandUseAction);
1138
1139 std::string message;
1140
1141 if (mIsForGroup)
1142 {
1143 childSetTextArg("insufficient_land_credits", "[GROUP]", gAgent.mGroupName);
1144
1145
1146 message += childGetText("insufficient_land_credits");
1147
1148 }
1149 else if (mAgentHasNeverOwnedLand)
1150 {
1151 if (mParcelIsFirstLand)
1152 {
1153 message += childGetText("first_purchase");
1154 }
1155 else
1156 {
1157 message += childGetText("first_time_but_not_first_land");
1158 }
1159 }
1160 else
1161 {
1162
1163 childSetTextArg("land_holdings", "[BUYER]", llformat("%d", mAgentCommittedTier));
1164 message += childGetText("land_holdings");
1165
1166 }
1167
1168 if (!mParcelValid)
1169 {
1170 message += "(no parcel selected)";
1171 }
1172 else if (mParcelBillableArea == mParcelActualArea)
1173 {
1174 childSetTextArg("parcel_meters", "[AMOUNT]", llformat("%d", mParcelActualArea));
1175 message += childGetText("parcel_meters");
1176 }
1177 else
1178 {
1179
1180 if (mParcelBillableArea > mParcelActualArea)
1181 {
1182 childSetTextArg("premium_land", "[AMOUNT]", llformat("%d", mParcelBillableArea) );
1183 message += childGetText("premium_land");
1184 }
1185 else
1186 {
1187 childSetTextArg("discounted_land", "[AMOUNT]", llformat("%d", mParcelBillableArea) );
1188 message += childGetText("discounted_land");
1189 }
1190 }
1191
1192 childSetWrappedText("land_use_reason", message);
1193
1194 childShow("step_2");
1195 childShow("land_use_action");
1196 childShow("land_use_reason");
1197 }
1198 else
1199 {
1200 childHide("step_2");
1201 childHide("land_use_action");
1202 childHide("land_use_reason");
1203 }
1204
1205 // section three: purchase & currency
1206 S32 finalBalance = mAgentCashBalance + mCurrency.getAmount() - mParcelPrice;
1207 bool willHaveEnough = finalBalance >= 0;
1208 bool haveEnough = mAgentCashBalance >= mParcelPrice;
1209 S32 minContribution = llceil((F32)mParcelBillableArea / GROUP_LAND_BONUS_FACTOR);
1210 bool groupContributionEnough = mParcelGroupContribution >= minContribution;
1211
1212 mCurrency.updateUI(!showingError && !haveEnough);
1213
1214 if (!showingError)
1215 {
1216 mChildren.setBadge("step_3",
1217 !willHaveEnough
1218 ? LLViewChildren::BADGE_WARN
1219 : mCurrency.getAmount() > 0
1220 ? LLViewChildren::BADGE_NOTE
1221 : LLViewChildren::BADGE_OK);
1222
1223 childSetText("purchase_action",
1224 llformat(
1225 "Pay L$ %d to %s for this land",
1226 mParcelPrice,
1227 mParcelSellerName.c_str()
1228 ));
1229 childSetVisible("purchase_action", mParcelValid);
1230
1231 std::string reasonString;
1232
1233 if (haveEnough)
1234 {
1235
1236 childSetTextArg("have_enough_lindens", "[AMOUNT]", llformat("%d", mAgentCashBalance));
1237 childSetText("currency_reason", childGetText("have_enough_lindens"));
1238 }
1239 else
1240 {
1241 childSetTextArg("not_enough_lindens", "[AMOUNT]", llformat("%d", mAgentCashBalance));
1242 childSetTextArg("not_enough_lindens", "[AMOUNT2]", llformat("%d", mParcelPrice - mAgentCashBalance));
1243
1244 childSetText("currency_reason", childGetText("not_enough_lindens"));
1245
1246 childSetTextArg("currency_est", "[AMOUNT2]", llformat("%#.2f", mCurrency.getEstimate() / 100.0));
1247
1248 }
1249
1250 if (willHaveEnough)
1251 {
1252
1253 childSetTextArg("balance_left", "[AMOUNT]", llformat("%d", finalBalance));
1254
1255 childSetText("currency_balance", childGetText("balance_left"));
1256
1257 }
1258 else
1259 {
1260
1261 childSetTextArg("balance_needed", "[AMOUNT]", llformat("%d", mParcelPrice - mAgentCashBalance));
1262
1263 childSetText("currency_balance", childGetText("balance_needed"));
1264
1265 }
1266
1267 //remove_contribution not in XML - ?!
1268 childSetValue("remove_contribution", LLSD(groupContributionEnough));
1269 childSetEnabled("remove_contribution", groupContributionEnough);
1270 bool showRemoveContribution = mParcelIsGroupLand
1271 && (mParcelGroupContribution > 0);
1272 childSetText("remove_contribution",
1273 llformat("Remove %d square meters of contribution from group",
1274 minContribution));
1275 childSetVisible("remove_contribution", showRemoveContribution);
1276
1277 childShow("step_3");
1278 childShow("purchase_action");
1279 childShow("currency_reason");
1280 childShow("currency_balance");
1281 }
1282 else
1283 {
1284 childHide("step_3");
1285 childHide("purchase_action");
1286 childHide("currency_reason");
1287 childHide("currency_balance");
1288 childHide("remove_group_donation");
1289 }
1290
1291
1292 bool agrees_to_covenant = false;
1293 LLCheckBoxCtrl* check = (LLCheckBoxCtrl*)getChildByName("agree_covenant");
1294 if (check)
1295 {
1296 agrees_to_covenant = check->get();
1297 }
1298
1299 childSetEnabled("buy_btn",
1300 mCanBuy && mSiteValid && willHaveEnough && !mTransaction && agrees_to_covenant);
1301}
1302
1303void LLFloaterBuyLandUI::startBuyPreConfirm()
1304{
1305 std::string action;
1306
1307 if (mSiteMembershipUpgrade)
1308 {
1309 action += mSiteMembershipAction;
1310 action += "\n";
1311
1312 LLComboBox* levels = LLUICtrlFactory::getComboBoxByName(this, "account_level");
1313 if (levels)
1314 {
1315 action += " * ";
1316 action += mSiteMembershipPlanNames[levels->getCurrentIndex()];
1317 action += "\n";
1318 }
1319 }
1320 if (mSiteLandUseUpgrade)
1321 {
1322 action += mSiteLandUseAction;
1323 action += "\n";
1324 }
1325 if (mCurrency.getAmount() > 0)
1326 {
1327
1328 childSetTextArg("buy_for_US", "[AMOUNT]", llformat("%d", mCurrency.getAmount()));
1329 childSetTextArg("buy_for_US", "[AMOUNT2]", llformat("%#.2f", mCurrency.getEstimate() / 100.0));
1330
1331 action += childGetText("buy_for_US");
1332 }
1333
1334 childSetTextArg("pay_to_for_land", "[AMOUNT]", llformat("%d", mParcelPrice));
1335 childSetTextArg("pay_to_for_land", "[SELLER]", mParcelSellerName.c_str());
1336
1337 action += childGetText("pay_to_for_land");
1338
1339
1340 LLConfirmationManager::confirm(mSiteConfirm,
1341 action,
1342 *this,
1343 &LLFloaterBuyLandUI::startBuyPostConfirm);
1344}
1345
1346void LLFloaterBuyLandUI::startBuyPostConfirm(const std::string& password)
1347{
1348 runWebSitePrep(password);
1349
1350 mCanBuy = false;
1351 mCannotBuyReason = childGetText("processing");
1352 refreshUI();
1353}
1354
1355
1356// static
1357void LLFloaterBuyLandUI::onClickBuy(void* data)
1358{
1359 LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data;
1360 self->startBuyPreConfirm();
1361}
1362
1363// static
1364void LLFloaterBuyLandUI::onClickCancel(void* data)
1365{
1366 LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data;
1367 self->close();
1368}
1369
1370// static
1371void LLFloaterBuyLandUI::onClickErrorWeb(void* data)
1372{
1373 LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data;
1374 LLWeb::loadURLExternal(self->mCannotBuyURI);
1375 self->close();
1376}
1377