00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llfloaterbuyland.h"
00035
00036
00037 #include "llagent.h"
00038 #include "llbutton.h"
00039 #include "llcachename.h"
00040 #include "llcheckboxctrl.h"
00041 #include "llcombobox.h"
00042 #include "llconfirmationmanager.h"
00043 #include "llcurrencyuimanager.h"
00044 #include "llfloater.h"
00045 #include "llfloatertools.h"
00046 #include "llframetimer.h"
00047 #include "lliconctrl.h"
00048 #include "lllineeditor.h"
00049 #include "llnotify.h"
00050 #include "llparcel.h"
00051 #include "llstatusbar.h"
00052 #include "lltextbox.h"
00053 #include "lltexturectrl.h"
00054 #include "llviewchildren.h"
00055 #include "llviewercontrol.h"
00056 #include "llvieweruictrlfactory.h"
00057 #include "llviewerparcelmgr.h"
00058 #include "llviewerregion.h"
00059 #include "llviewertexteditor.h"
00060 #include "llviewerwindow.h"
00061 #include "llweb.h"
00062 #include "llwindow.h"
00063 #include "llworld.h"
00064 #include "llxmlrpctransaction.h"
00065 #include "viewer.h"
00066 #include "roles_constants.h"
00067
00068
00069 const F32 GROUP_LAND_BONUS_FACTOR = 1.1f;
00070 const F64 CURRENCY_ESTIMATE_FREQUENCY = 0.5;
00071
00072
00073
00074 class LLFloaterBuyLandUI
00075 : public LLFloater
00076 {
00077 private:
00078 LLFloaterBuyLandUI();
00079 virtual ~LLFloaterBuyLandUI();
00080
00081 LLViewerRegion* mRegion;
00082 LLParcelSelectionHandle mParcel;
00083 bool mIsClaim;
00084 bool mIsForGroup;
00085
00086 bool mCanBuy;
00087 bool mCannotBuyIsError;
00088 std::string mCannotBuyReason;
00089 std::string mCannotBuyURI;
00090
00091 bool mBought;
00092
00093
00094 S32 mAgentCommittedTier;
00095 S32 mAgentCashBalance;
00096 bool mAgentHasNeverOwnedLand;
00097
00098
00099 bool mParcelValid;
00100 bool mParcelIsForSale;
00101 bool mParcelIsGroupLand;
00102 S32 mParcelGroupContribution;
00103 S32 mParcelPrice;
00104 S32 mParcelActualArea;
00105 S32 mParcelBillableArea;
00106 S32 mParcelSupportedObjects;
00107 bool mParcelSoldWithObjects;
00108 std::string mParcelLocation;
00109 LLUUID mParcelSnapshot;
00110 std::string mParcelSellerName;
00111
00112
00113 S32 mUserPlanChoice;
00114
00115
00116 bool mSiteValid;
00117 bool mSiteMembershipUpgrade;
00118 std::string mSiteMembershipAction;
00119 std::vector<std::string>
00120 mSiteMembershipPlanIDs;
00121 std::vector<std::string>
00122 mSiteMembershipPlanNames;
00123 bool mSiteLandUseUpgrade;
00124 std::string mSiteLandUseAction;
00125 std::string mSiteConfirm;
00126
00127
00128
00129 S32 mPreflightAskBillableArea;
00130 S32 mPreflightAskCurrencyBuy;
00131
00132 LLViewChildren mChildren;
00133 LLCurrencyUIManager mCurrency;
00134
00135 enum TransactionType
00136 {
00137 TransactionPreflight,
00138 TransactionCurrency,
00139 TransactionBuy
00140 };
00141 LLXMLRPCTransaction* mTransaction;
00142 TransactionType mTransactionType;
00143
00144 LLViewerParcelMgr::ParcelBuyInfo* mParcelBuyInfo;
00145
00146 static LLFloaterBuyLandUI* sInstance;
00147
00148 public:
00149 static LLFloaterBuyLandUI* soleInstance(bool createIfNeeded);
00150
00151 void setForGroup(bool is_for_group);
00152 void setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel);
00153
00154 void updateAgentInfo();
00155 void updateParcelInfo();
00156 void updateCovenantInfo();
00157 static void onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data);
00158 void updateCovenantText(const std::string& string, const LLUUID &asset_id);
00159 void updateEstateName(const std::string& name);
00160 void updateLastModified(const std::string& text);
00161 void updateEstateOwnerName(const std::string& name);
00162 void updateWebSiteInfo();
00163 void finishWebSiteInfo();
00164
00165 void runWebSitePrep(const std::string& password);
00166 void finishWebSitePrep();
00167 void sendBuyLand();
00168
00169 void updateNames();
00170
00171 void refreshUI();
00172
00173 void startTransaction(TransactionType type, LLXMLRPCValue params);
00174 bool checkTransaction();
00175
00176 void tellUserError(const std::string& message, const std::string& uri);
00177
00178 virtual BOOL postBuild();
00179
00180 void startBuyPreConfirm();
00181 void startBuyPostConfirm(const std::string& password);
00182
00183 static void onClickBuy(void* data);
00184 static void onClickCancel(void* data);
00185 static void onClickErrorWeb(void* data);
00186
00187 virtual void draw();
00188 virtual BOOL canClose();
00189 virtual void onClose(bool app_quitting);
00190
00191 private:
00192 class SelectionObserver : public LLParcelObserver
00193 {
00194 public:
00195 virtual void changed();
00196 };
00197 };
00198
00199 static void cacheNameUpdateRefreshesBuyLand(const LLUUID&,
00200 const char*, const char*, BOOL, void* data)
00201 {
00202 LLFloaterBuyLandUI* ui = LLFloaterBuyLandUI::soleInstance(false);
00203 if (ui)
00204 {
00205 ui->updateNames();
00206 }
00207 }
00208
00209
00210 void LLFloaterBuyLand::buyLand(
00211 LLViewerRegion* region, LLParcelSelectionHandle parcel, bool is_for_group)
00212 {
00213 if(is_for_group && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED))
00214 {
00215 gViewerWindow->alertXml("OnlyOfficerCanBuyLand");
00216 return;
00217 }
00218
00219 LLFloaterBuyLandUI* ui = LLFloaterBuyLandUI::soleInstance(true);
00220 ui->setForGroup(is_for_group);
00221 ui->setParcel(region, parcel);
00222 ui->open();
00223 }
00224
00225
00226 void LLFloaterBuyLand::updateCovenantText(const std::string& string, const LLUUID &asset_id)
00227 {
00228 LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE);
00229 if (floater)
00230 {
00231 floater->updateCovenantText(string, asset_id);
00232 }
00233 }
00234
00235
00236 void LLFloaterBuyLand::updateEstateName(const std::string& name)
00237 {
00238 LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE);
00239 if (floater)
00240 {
00241 floater->updateEstateName(name);
00242 }
00243 }
00244
00245
00246 void LLFloaterBuyLand::updateLastModified(const std::string& text)
00247 {
00248 LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE);
00249 if (floater)
00250 {
00251 floater->updateLastModified(text);
00252 }
00253 }
00254
00255
00256 void LLFloaterBuyLand::updateEstateOwnerName(const std::string& name)
00257 {
00258 LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE);
00259 if (floater)
00260 {
00261 floater->updateEstateOwnerName(name);
00262 }
00263 }
00264
00265
00266 BOOL LLFloaterBuyLand::isOpen()
00267 {
00268 LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE);
00269 if (floater)
00270 {
00271 return floater->getVisible();
00272 }
00273 return FALSE;
00274 }
00275
00276
00277 LLFloaterBuyLandUI* LLFloaterBuyLandUI::sInstance = NULL;
00278
00279
00280 LLFloaterBuyLandUI* LLFloaterBuyLandUI::soleInstance(bool createIfNeeded)
00281 {
00282 #if !LL_RELEASE_FOR_DOWNLOAD
00283 if (createIfNeeded)
00284 {
00285 delete sInstance;
00286 sInstance = NULL;
00287 }
00288 #endif
00289 if (!sInstance && createIfNeeded)
00290 {
00291 sInstance = new LLFloaterBuyLandUI();
00292
00293 gUICtrlFactory->buildFloater(sInstance, "floater_buy_land.xml");
00294 sInstance->center();
00295
00296 static bool observingCacheName = false;
00297 if (!observingCacheName)
00298 {
00299 gCacheName->addObserver(cacheNameUpdateRefreshesBuyLand);
00300 observingCacheName = true;
00301 }
00302
00303 static SelectionObserver* parcelSelectionObserver = NULL;
00304 if (!parcelSelectionObserver)
00305 {
00306 parcelSelectionObserver = new SelectionObserver;
00307 gParcelMgr->addObserver(parcelSelectionObserver);
00308 }
00309 }
00310
00311 return sInstance;
00312 }
00313
00314
00315 #if LL_WINDOWS
00316
00317
00318
00319
00320 #pragma warning(disable : 4355)
00321 #endif
00322 LLFloaterBuyLandUI::LLFloaterBuyLandUI()
00323 : LLFloater("Buy Land"),
00324 mParcel(0),
00325 mBought(false),
00326 mParcelValid(false), mSiteValid(false),
00327 mChildren(*this), mCurrency(*this), mTransaction(0),
00328 mParcelBuyInfo(0)
00329 {
00330 }
00331
00332 LLFloaterBuyLandUI::~LLFloaterBuyLandUI()
00333 {
00334 delete mTransaction;
00335
00336 gParcelMgr->deleteParcelBuy(mParcelBuyInfo);
00337
00338 if (sInstance == this)
00339 {
00340 sInstance = NULL;
00341 }
00342 }
00343
00344 void LLFloaterBuyLandUI::SelectionObserver::changed()
00345 {
00346 LLFloaterBuyLandUI* ui = LLFloaterBuyLandUI::soleInstance(false);
00347 if (ui)
00348 {
00349 if (gParcelMgr->selectionEmpty())
00350 {
00351 ui->close();
00352 }
00353 else {
00354 ui->setParcel(
00355 gParcelMgr->getSelectionRegion(),
00356 gParcelMgr->getParcelSelection());
00357 }
00358 }
00359 }
00360
00361
00362 void LLFloaterBuyLandUI::updateAgentInfo()
00363 {
00364 mAgentCommittedTier = gStatusBar->getSquareMetersCommitted();
00365 mAgentCashBalance = gStatusBar->getBalance();
00366
00367
00368
00369 mAgentHasNeverOwnedLand = mAgentCommittedTier == 0;
00370 }
00371
00372 void LLFloaterBuyLandUI::updateParcelInfo()
00373 {
00374 LLParcel* parcel = mParcel->getParcel();
00375 mParcelValid = parcel && mRegion;
00376 mParcelIsForSale = false;
00377 mParcelIsGroupLand = false;
00378 mParcelGroupContribution = 0;
00379 mParcelPrice = 0;
00380 mParcelActualArea = 0;
00381 mParcelBillableArea = 0;
00382 mParcelSupportedObjects = 0;
00383 mParcelSoldWithObjects = false;
00384 mParcelLocation = "";
00385 mParcelSnapshot.setNull();
00386 mParcelSellerName = "";
00387
00388 mCanBuy = false;
00389 mCannotBuyIsError = false;
00390
00391 if (!mParcelValid)
00392 {
00393 mCannotBuyReason= childGetText("no_land_selected");
00394 return;
00395 }
00396
00397 if (mParcel->getMultipleOwners())
00398 {
00399 mCannotBuyReason = childGetText("multiple_parcels_selected");
00400 return;
00401 }
00402
00403 const LLUUID& parcelOwner = parcel->getOwnerID();
00404
00405 mIsClaim = parcel->isPublic();
00406 if (!mIsClaim)
00407 {
00408 mParcelActualArea = parcel->getArea();
00409 mParcelIsForSale = parcel->getForSale();
00410 mParcelIsGroupLand = parcel->getIsGroupOwned();
00411 mParcelPrice = mParcelIsForSale ? parcel->getSalePrice() : 0;
00412
00413 if (mParcelIsGroupLand)
00414 {
00415 LLUUID group_id = parcel->getGroupID();
00416 mParcelGroupContribution = gAgent.getGroupContribution(group_id);
00417 }
00418 }
00419 else
00420 {
00421 mParcelActualArea = mParcel->getClaimableArea();
00422 mParcelIsForSale = true;
00423 mParcelPrice = mParcelActualArea * parcel->getClaimPricePerMeter();
00424 }
00425
00426 mParcelBillableArea =
00427 llround(mRegion->getBillableFactor() * mParcelActualArea);
00428
00429 mParcelSupportedObjects = llround(
00430 parcel->getMaxPrimCapacity() * parcel->getParcelPrimBonus());
00431
00432
00433 LLViewerRegion* region = gParcelMgr->getSelectionRegion();
00434 if(region)
00435 {
00436 S32 max_tasks_per_region = (S32)region->getMaxTasks();
00437 mParcelSupportedObjects = llmin(
00438 mParcelSupportedObjects, max_tasks_per_region);
00439 }
00440
00441 mParcelSoldWithObjects = parcel->getSellWithObjects();
00442
00443
00444 LLVector3 center = parcel->getCenterpoint();
00445 mParcelLocation = llformat("%s %d,%d",
00446 mRegion->getName().c_str(),
00447 (int)center[VX], (int)center[VY]
00448 );
00449
00450 mParcelSnapshot = parcel->getSnapshotID();
00451
00452 updateNames();
00453
00454 bool haveEnoughCash = mParcelPrice <= mAgentCashBalance;
00455 S32 cashBuy = haveEnoughCash ? 0 : (mParcelPrice - mAgentCashBalance);
00456 mCurrency.setAmount(cashBuy, true);
00457 mCurrency.setZeroMessage(haveEnoughCash ? childGetText("none_needed") : "");
00458
00459
00460
00461 if(mIsForGroup && !gAgent.hasPowerInActiveGroup(GP_LAND_DEED))
00462 {
00463 mCannotBuyReason = childGetText("cant_buy_for_group");
00464 return;
00465 }
00466
00467 if (!mIsClaim)
00468 {
00469 const LLUUID& authorizedBuyer = parcel->getAuthorizedBuyerID();
00470 const LLUUID buyer = gAgent.getID();
00471 const LLUUID newOwner = mIsForGroup ? gAgent.getGroupID() : buyer;
00472
00473 if (!mParcelIsForSale
00474 || (mParcelPrice == 0 && authorizedBuyer.isNull()))
00475 {
00476
00477 mCannotBuyReason = childGetText("parcel_not_for_sale");
00478 return;
00479 }
00480
00481 if (parcelOwner == newOwner)
00482 {
00483 if (mIsForGroup)
00484 {
00485 mCannotBuyReason = childGetText("group_already_owns");
00486 }
00487 else
00488 {
00489 mCannotBuyReason = childGetText("you_already_own");
00490 }
00491 return;
00492 }
00493
00494 if (!authorizedBuyer.isNull() && buyer != authorizedBuyer)
00495 {
00496 mCannotBuyReason = childGetText("set_to_sell_to_other");
00497 return;
00498 }
00499 }
00500 else
00501 {
00502 if (mParcelActualArea == 0)
00503 {
00504 mCannotBuyReason = childGetText("no_public_land");
00505 return;
00506 }
00507
00508 if (mParcel->hasOthersSelected())
00509 {
00510
00511 mCannotBuyReason = childGetText("not_owned_by_you");
00512 return;
00513 }
00514 }
00515
00516 mCanBuy = true;
00517 }
00518
00519 void LLFloaterBuyLandUI::updateCovenantInfo()
00520 {
00521 LLViewerRegion* region = gParcelMgr->getSelectionRegion();
00522 if(!region) return;
00523
00524 LLTextBox* region_name = (LLTextBox*)getChildByName("region_name_text");
00525 if (region_name)
00526 {
00527 region_name->setText(region->getName());
00528 }
00529
00530 LLTextBox* resellable_clause = (LLTextBox*)getChildByName("resellable_clause");
00531 if (resellable_clause)
00532 {
00533 if (region->getRegionFlags() & REGION_FLAGS_BLOCK_LAND_RESELL)
00534 {
00535 resellable_clause->setText(childGetText("can_not_resell"));
00536 }
00537 else
00538 {
00539 resellable_clause->setText(childGetText("can_resell"));
00540 }
00541 }
00542
00543 LLTextBox* changeable_clause = (LLTextBox*)getChildByName("changeable_clause");
00544 if (changeable_clause)
00545 {
00546 if (region->getRegionFlags() & REGION_FLAGS_ALLOW_PARCEL_CHANGES)
00547 {
00548 changeable_clause->setText(childGetText("can_change"));
00549 }
00550 else
00551 {
00552 changeable_clause->setText(childGetText("can_not_change"));
00553 }
00554 }
00555
00556 LLCheckBoxCtrl* check = (LLCheckBoxCtrl*)getChildByName("agree_covenant");
00557 if(check)
00558 {
00559 check->set(false);
00560 check->setEnabled(true);
00561 check->setCallbackUserData(this);
00562 check->setCommitCallback(onChangeAgreeCovenant);
00563 }
00564
00565 LLTextBox* box = (LLTextBox*)getChildByName("covenant_text");
00566 if(box)
00567 {
00568 box->setVisible(FALSE);
00569 }
00570
00571
00572 LLMessageSystem *msg = gMessageSystem;
00573 msg->newMessage("EstateCovenantRequest");
00574 msg->nextBlockFast(_PREHASH_AgentData);
00575 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00576 msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID());
00577 msg->sendReliable(region->getHost());
00578 }
00579
00580
00581 void LLFloaterBuyLandUI::onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data)
00582 {
00583 LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)user_data;
00584 if(self)
00585 {
00586 self->refreshUI();
00587 }
00588 }
00589
00590 void LLFloaterBuyLandUI::updateCovenantText(const std::string &string, const LLUUID& asset_id)
00591 {
00592 LLViewerTextEditor* editor = (LLViewerTextEditor*)getChildByName("covenant_editor");
00593 if (editor)
00594 {
00595 editor->setHandleEditKeysDirectly(FALSE);
00596 editor->setText(string);
00597
00598 LLCheckBoxCtrl* check = (LLCheckBoxCtrl*)getChildByName("agree_covenant");
00599 LLTextBox* box = (LLTextBox*)getChildByName("covenant_text");
00600 if(check && box)
00601 {
00602 if (asset_id.isNull())
00603 {
00604 check->set(true);
00605 check->setEnabled(false);
00606 refreshUI();
00607
00608
00609 box->setVisible(FALSE);
00610 }
00611 else
00612 {
00613 check->setEnabled(true);
00614
00615
00616 box->setVisible(TRUE);
00617 }
00618 }
00619 }
00620 }
00621
00622 void LLFloaterBuyLandUI::updateEstateName(const std::string& name)
00623 {
00624 LLTextBox* box = (LLTextBox*)getChildByName("estate_name_text");
00625 if (box) box->setText(name);
00626 }
00627
00628 void LLFloaterBuyLandUI::updateLastModified(const std::string& text)
00629 {
00630 LLTextBox* editor = (LLTextBox*)getChildByName("covenant_timestamp_text");
00631 if (editor) editor->setText(text);
00632 }
00633
00634 void LLFloaterBuyLandUI::updateEstateOwnerName(const std::string& name)
00635 {
00636 LLTextBox* box = (LLTextBox*)getChildByName("estate_owner_text");
00637 if (box) box->setText(name);
00638 }
00639
00640 void LLFloaterBuyLandUI::updateWebSiteInfo()
00641 {
00642 S32 askBillableArea = mIsForGroup ? 0 : mParcelBillableArea;
00643 S32 askCurrencyBuy = mCurrency.getAmount();
00644
00645 if (mTransaction && mTransactionType == TransactionPreflight
00646 && mPreflightAskBillableArea == askBillableArea
00647 && mPreflightAskCurrencyBuy == askCurrencyBuy)
00648 {
00649 return;
00650 }
00651
00652 mPreflightAskBillableArea = askBillableArea;
00653 mPreflightAskCurrencyBuy = askCurrencyBuy;
00654
00655 #if 0
00656
00657
00658 mSiteValid = false;
00659 mSiteMembershipUpgrade = false;
00660 mSiteMembershipAction = "(waiting)";
00661 mSiteMembershipPlanIDs.clear();
00662 mSiteMembershipPlanNames.clear();
00663 mSiteLandUseUpgrade = false;
00664 mSiteLandUseAction = "(waiting)";
00665 mSiteCurrencyEstimated = false;
00666 mSiteCurrencyEstimatedCost = 0;
00667 #endif
00668
00669 LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
00670 keywordArgs.appendString("agentId", gAgent.getID().asString());
00671 keywordArgs.appendString(
00672 "secureSessionId",
00673 gAgent.getSecureSessionID().asString());
00674 keywordArgs.appendInt("billableArea", mPreflightAskBillableArea);
00675 keywordArgs.appendInt("currencyBuy", mPreflightAskCurrencyBuy);
00676
00677 LLXMLRPCValue params = LLXMLRPCValue::createArray();
00678 params.append(keywordArgs);
00679
00680 startTransaction(TransactionPreflight, params);
00681 }
00682
00683 void LLFloaterBuyLandUI::finishWebSiteInfo()
00684 {
00685
00686 LLXMLRPCValue result = mTransaction->responseValue();
00687
00688 mSiteValid = result["success"].asBool();
00689 if (!mSiteValid)
00690 {
00691 tellUserError(
00692 result["errorMessage"].asString(),
00693 result["errorURI"].asString()
00694 );
00695 return;
00696 }
00697
00698 LLXMLRPCValue membership = result["membership"];
00699 mSiteMembershipUpgrade = membership["upgrade"].asBool();
00700 mSiteMembershipAction = membership["action"].asString();
00701 mSiteMembershipPlanIDs.clear();
00702 mSiteMembershipPlanNames.clear();
00703 LLXMLRPCValue levels = membership["levels"];
00704 for (LLXMLRPCValue level = levels.rewind();
00705 level.isValid();
00706 level = levels.next())
00707 {
00708 mSiteMembershipPlanIDs.push_back(level["id"].asString());
00709 mSiteMembershipPlanNames.push_back(level["description"].asString());
00710 }
00711 mUserPlanChoice = 0;
00712
00713 LLXMLRPCValue landUse = result["landUse"];
00714 mSiteLandUseUpgrade = landUse["upgrade"].asBool();
00715 mSiteLandUseAction = landUse["action"].asString();
00716
00717 LLXMLRPCValue currency = result["currency"];
00718 mCurrency.setEstimate(currency["estimatedCost"].asInt());
00719
00720 mSiteConfirm = result["confirm"].asString();
00721 }
00722
00723 void LLFloaterBuyLandUI::runWebSitePrep(const std::string& password)
00724 {
00725 if (!mCanBuy)
00726 {
00727 return;
00728 }
00729
00730 BOOL remove_contribution = childGetValue("remove_contribution").asBoolean();
00731 mParcelBuyInfo = gParcelMgr->setupParcelBuy(gAgent.getID(), gAgent.getSessionID(),
00732 gAgent.getGroupID(), mIsForGroup, mIsClaim, remove_contribution);
00733
00734 if (mParcelBuyInfo
00735 && !mSiteMembershipUpgrade
00736 && !mSiteLandUseUpgrade
00737 && mCurrency.getAmount() == 0
00738 && mSiteConfirm != "password")
00739 {
00740 sendBuyLand();
00741 return;
00742 }
00743
00744
00745 std::string newLevel = "noChange";
00746
00747 if (mSiteMembershipUpgrade)
00748 {
00749 LLComboBox* levels = LLUICtrlFactory::getComboBoxByName(this, "account_level");
00750 if (levels)
00751 {
00752 mUserPlanChoice = levels->getCurrentIndex();
00753 newLevel = mSiteMembershipPlanIDs[mUserPlanChoice];
00754 }
00755 }
00756
00757 LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
00758 keywordArgs.appendString("agentId", gAgent.getID().asString());
00759 keywordArgs.appendString(
00760 "secureSessionId",
00761 gAgent.getSecureSessionID().asString());
00762 keywordArgs.appendString("levelId", newLevel);
00763 keywordArgs.appendInt("billableArea",
00764 mIsForGroup ? 0 : mParcelBillableArea);
00765 keywordArgs.appendInt("currencyBuy", mCurrency.getAmount());
00766 keywordArgs.appendInt("estimatedCost", mCurrency.getEstimate());
00767 keywordArgs.appendString("confirm", mSiteConfirm);
00768 if (!password.empty())
00769 {
00770 keywordArgs.appendString("password", password);
00771 }
00772
00773 LLXMLRPCValue params = LLXMLRPCValue::createArray();
00774 params.append(keywordArgs);
00775
00776 startTransaction(TransactionBuy, params);
00777 }
00778
00779 void LLFloaterBuyLandUI::finishWebSitePrep()
00780 {
00781 LLXMLRPCValue result = mTransaction->responseValue();
00782
00783 bool success = result["success"].asBool();
00784 if (!success)
00785 {
00786 tellUserError(
00787 result["errorMessage"].asString(),
00788 result["errorURI"].asString()
00789 );
00790 return;
00791 }
00792
00793 sendBuyLand();
00794 }
00795
00796 void LLFloaterBuyLandUI::sendBuyLand()
00797 {
00798 if (mParcelBuyInfo)
00799 {
00800 gParcelMgr->sendParcelBuy(mParcelBuyInfo);
00801 gParcelMgr->deleteParcelBuy(mParcelBuyInfo);
00802 mBought = true;
00803 }
00804 }
00805
00806 void LLFloaterBuyLandUI::updateNames()
00807 {
00808 LLParcel* parcelp = mParcel->getParcel();
00809
00810 if (!parcelp)
00811 {
00812 mParcelSellerName = "";
00813 return;
00814 }
00815
00816 if (mIsClaim)
00817 {
00818 mParcelSellerName = "Linden Lab";
00819 }
00820 else if (parcelp->getIsGroupOwned())
00821 {
00822 char groupName[DB_LAST_NAME_BUF_SIZE];
00823
00824 gCacheName->getGroupName(parcelp->getGroupID(), &groupName[0]);
00825 mParcelSellerName = groupName;
00826 }
00827 else
00828 {
00829 char firstName[DB_LAST_NAME_BUF_SIZE];
00830 char lastName[DB_LAST_NAME_BUF_SIZE];
00831
00832 gCacheName->getName(parcelp->getOwnerID(), firstName, lastName);
00833 mParcelSellerName = llformat("%s %s", firstName, lastName);
00834 }
00835 }
00836
00837
00838 void LLFloaterBuyLandUI::startTransaction(TransactionType type,
00839 LLXMLRPCValue params)
00840 {
00841 delete mTransaction;
00842 mTransaction = NULL;
00843
00844 mTransactionType = type;
00845
00846
00847 static std::string transaction_uri;
00848 if (transaction_uri.empty())
00849 {
00850 transaction_uri = getHelperURI() + "landtool.php";
00851 }
00852
00853 const char* method;
00854 switch (mTransactionType)
00855 {
00856 case TransactionPreflight:
00857 method = "preflightBuyLandPrep";
00858 break;
00859 case TransactionBuy:
00860 method = "buyLandPrep";
00861 break;
00862 default:
00863 llwarns << "LLFloaterBuyLandUI: Unknown transaction type!" << llendl;
00864 return;
00865 }
00866
00867 mTransaction = new LLXMLRPCTransaction(
00868 transaction_uri,
00869 method,
00870 params,
00871 false
00872 );
00873 }
00874
00875 bool LLFloaterBuyLandUI::checkTransaction()
00876 {
00877 if (!mTransaction)
00878 {
00879 return false;
00880 }
00881
00882 if (!mTransaction->process())
00883 {
00884 return false;
00885 }
00886
00887 if (mTransaction->status(NULL) != LLXMLRPCTransaction::StatusComplete)
00888 {
00889 tellUserError(mTransaction->statusMessage(), mTransaction->statusURI());
00890 }
00891 else {
00892 switch (mTransactionType)
00893 {
00894 case TransactionPreflight: finishWebSiteInfo(); break;
00895 case TransactionBuy: finishWebSitePrep(); break;
00896 default: ;
00897 }
00898 }
00899
00900 delete mTransaction;
00901 mTransaction = NULL;
00902
00903 return true;
00904 }
00905
00906 void LLFloaterBuyLandUI::tellUserError(
00907 const std::string& message, const std::string& uri)
00908 {
00909 mCanBuy = false;
00910 mCannotBuyIsError = true;
00911 mCannotBuyReason = childGetText("fetching_error");
00912 mCannotBuyReason += message;
00913 mCannotBuyURI = uri;
00914 }
00915
00916
00917
00918 BOOL LLFloaterBuyLandUI::postBuild()
00919 {
00920 mCurrency.prepare();
00921
00922 childSetAction("buy_btn", onClickBuy, this);
00923 childSetAction("cancel_btn", onClickCancel, this);
00924 childSetAction("error_web", onClickErrorWeb, this);
00925
00926 return TRUE;
00927 }
00928
00929 void LLFloaterBuyLandUI::setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel)
00930 {
00931 if (mTransaction && mTransactionType == TransactionBuy)
00932 {
00933
00934 return;
00935 }
00936
00937 mRegion = region;
00938 mParcel = parcel;
00939
00940 updateAgentInfo();
00941 updateParcelInfo();
00942 updateCovenantInfo();
00943 if (mCanBuy)
00944 {
00945 updateWebSiteInfo();
00946 }
00947 refreshUI();
00948 }
00949
00950 void LLFloaterBuyLandUI::setForGroup(bool forGroup)
00951 {
00952 mIsForGroup = forGroup;
00953 }
00954
00955 void LLFloaterBuyLandUI::draw()
00956 {
00957 LLFloater::draw();
00958
00959 bool needsUpdate = false;
00960 needsUpdate |= checkTransaction();
00961 needsUpdate |= mCurrency.process();
00962
00963 if (mBought)
00964 {
00965 close();
00966 }
00967 else if (needsUpdate)
00968 {
00969 if (mCanBuy && mCurrency.hasError())
00970 {
00971 tellUserError(mCurrency.errorMessage(), mCurrency.errorURI());
00972 }
00973
00974 refreshUI();
00975 }
00976 }
00977
00978 BOOL LLFloaterBuyLandUI::canClose()
00979 {
00980 return (mTransaction ? FALSE : TRUE) && mCurrency.canCancel();
00981 }
00982
00983 void LLFloaterBuyLandUI::onClose(bool app_quitting)
00984 {
00985 LLFloater::onClose(app_quitting);
00986 destroy();
00987 }
00988
00989
00990 void LLFloaterBuyLandUI::refreshUI()
00991 {
00992
00993 {
00994 LLTextureCtrl* snapshot = LLViewerUICtrlFactory::getTexturePickerByName(this, "info_image");
00995 if (snapshot)
00996 {
00997 snapshot->setImageAssetID(
00998 mParcelValid ? mParcelSnapshot : LLUUID::null);
00999 }
01000
01001
01002
01003 if (mParcelValid)
01004 {
01005 childSetText("info_parcel", mParcelLocation);
01006
01007
01008 childSetTextArg("meters_supports_object", "[AMOUNT]", llformat("%d", mParcelActualArea));
01009 childSetTextArg("meters_supports_object", "[AMOUNT2]", llformat("%d", mParcelSupportedObjects));
01010
01011 childSetText("info_size", childGetText("meters_supports_object"));
01012
01013
01014 childSetText("info_price",
01015 llformat(
01016 "L$ %d%s",
01017 mParcelPrice,
01018 mParcelSoldWithObjects
01019 ? "\nsold with objects"
01020 : ""));
01021 childSetVisible("info_price", mParcelIsForSale);
01022 }
01023 else
01024 {
01025 childSetText("info_parcel", childGetText("no_parcel_selected"));
01026 childSetText("info_size", LLString::null);
01027 childSetText("info_price", LLString::null);
01028 }
01029
01030 childSetText("info_action",
01031 mCanBuy
01032 ?
01033 mIsForGroup
01034 ? childGetText("buying_for_group")
01035 : childGetText("buying_will")
01036 :
01037 mCannotBuyIsError
01038 ? childGetText("cannot_buy_now")
01039 : childGetText("not_for_sale")
01040
01041 );
01042 }
01043
01044 bool showingError = !mCanBuy || !mSiteValid;
01045
01046
01047 if (showingError)
01048 {
01049 mChildren.setBadge("step_error",
01050 mCannotBuyIsError
01051 ? LLViewChildren::BADGE_ERROR
01052 : LLViewChildren::BADGE_WARN);
01053
01054 LLTextBox* message = LLUICtrlFactory::getTextBoxByName(this, "error_message");
01055 if (message)
01056 {
01057 message->setVisible(true);
01058 message->setWrappedText(
01059 !mCanBuy ? mCannotBuyReason : "(waiting for data)"
01060 );
01061 }
01062
01063 childSetVisible("error_web",
01064 mCannotBuyIsError && !mCannotBuyURI.empty());
01065 }
01066 else
01067 {
01068 childHide("step_error");
01069 childHide("error_message");
01070 childHide("error_web");
01071 }
01072
01073
01074
01075 if (!showingError)
01076 {
01077 mChildren.setBadge("step_1",
01078 mSiteMembershipUpgrade
01079 ? LLViewChildren::BADGE_NOTE
01080 : LLViewChildren::BADGE_OK);
01081 childSetText("account_action", mSiteMembershipAction);
01082 childSetText("account_reason",
01083 mSiteMembershipUpgrade
01084 ? childGetText("must_upgrade")
01085 : childGetText("cant_own_land")
01086 );
01087
01088 LLComboBox* levels = LLUICtrlFactory::getComboBoxByName(this, "account_level");
01089 if (levels)
01090 {
01091 levels->setVisible(mSiteMembershipUpgrade);
01092
01093 levels->removeall();
01094 for(std::vector<std::string>::const_iterator i
01095 = mSiteMembershipPlanNames.begin();
01096 i != mSiteMembershipPlanNames.end();
01097 ++i)
01098 {
01099 levels->add(*i);
01100 }
01101
01102 levels->setCurrentByIndex(mUserPlanChoice);
01103 }
01104
01105 childShow("step_1");
01106 childShow("account_action");
01107 childShow("account_reason");
01108 }
01109 else
01110 {
01111 childHide("step_1");
01112 childHide("account_action");
01113 childHide("account_reason");
01114 childHide("account_level");
01115 }
01116
01117
01118 if (!showingError)
01119 {
01120 mChildren.setBadge("step_2",
01121 mSiteLandUseUpgrade
01122 ? LLViewChildren::BADGE_NOTE
01123 : LLViewChildren::BADGE_OK);
01124 childSetText("land_use_action", mSiteLandUseAction);
01125
01126 std::string message;
01127
01128 if (mIsForGroup)
01129 {
01130 childSetTextArg("insufficient_land_credits", "[GROUP]", LLString(gAgent.mGroupName));
01131
01132
01133 message += childGetText("insufficient_land_credits");
01134
01135 }
01136 else
01137 {
01138
01139 childSetTextArg("land_holdings", "[BUYER]", llformat("%d", mAgentCommittedTier));
01140 message += childGetText("land_holdings");
01141
01142 }
01143
01144 if (!mParcelValid)
01145 {
01146 message += "(no parcel selected)";
01147 }
01148 else if (mParcelBillableArea == mParcelActualArea)
01149 {
01150 childSetTextArg("parcel_meters", "[AMOUNT]", llformat("%d", mParcelActualArea));
01151 message += childGetText("parcel_meters");
01152 }
01153 else
01154 {
01155
01156 if (mParcelBillableArea > mParcelActualArea)
01157 {
01158 childSetTextArg("premium_land", "[AMOUNT]", llformat("%d", mParcelBillableArea) );
01159 message += childGetText("premium_land");
01160 }
01161 else
01162 {
01163 childSetTextArg("discounted_land", "[AMOUNT]", llformat("%d", mParcelBillableArea) );
01164 message += childGetText("discounted_land");
01165 }
01166 }
01167
01168 childSetWrappedText("land_use_reason", message);
01169
01170 childShow("step_2");
01171 childShow("land_use_action");
01172 childShow("land_use_reason");
01173 }
01174 else
01175 {
01176 childHide("step_2");
01177 childHide("land_use_action");
01178 childHide("land_use_reason");
01179 }
01180
01181
01182 S32 finalBalance = mAgentCashBalance + mCurrency.getAmount() - mParcelPrice;
01183 bool willHaveEnough = finalBalance >= 0;
01184 bool haveEnough = mAgentCashBalance >= mParcelPrice;
01185 S32 minContribution = llceil((F32)mParcelBillableArea / GROUP_LAND_BONUS_FACTOR);
01186 bool groupContributionEnough = mParcelGroupContribution >= minContribution;
01187
01188 mCurrency.updateUI(!showingError && !haveEnough);
01189
01190 if (!showingError)
01191 {
01192 mChildren.setBadge("step_3",
01193 !willHaveEnough
01194 ? LLViewChildren::BADGE_WARN
01195 : mCurrency.getAmount() > 0
01196 ? LLViewChildren::BADGE_NOTE
01197 : LLViewChildren::BADGE_OK);
01198
01199 childSetText("purchase_action",
01200 llformat(
01201 "Pay L$ %d to %s for this land",
01202 mParcelPrice,
01203 mParcelSellerName.c_str()
01204 ));
01205 childSetVisible("purchase_action", mParcelValid);
01206
01207 std::string reasonString;
01208
01209 if (haveEnough)
01210 {
01211
01212 childSetTextArg("have_enough_lindens", "[AMOUNT]", llformat("%d", mAgentCashBalance));
01213 childSetText("currency_reason", childGetText("have_enough_lindens"));
01214 }
01215 else
01216 {
01217 childSetTextArg("not_enough_lindens", "[AMOUNT]", llformat("%d", mAgentCashBalance));
01218 childSetTextArg("not_enough_lindens", "[AMOUNT2]", llformat("%d", mParcelPrice - mAgentCashBalance));
01219
01220 childSetText("currency_reason", childGetText("not_enough_lindens"));
01221
01222 childSetTextArg("currency_est", "[AMOUNT2]", llformat("%#.2f", mCurrency.getEstimate() / 100.0));
01223
01224 }
01225
01226 if (willHaveEnough)
01227 {
01228
01229 childSetTextArg("balance_left", "[AMOUNT]", llformat("%d", finalBalance));
01230
01231 childSetText("currency_balance", childGetText("balance_left"));
01232
01233 }
01234 else
01235 {
01236
01237 childSetTextArg("balance_needed", "[AMOUNT]", llformat("%d", mParcelPrice - mAgentCashBalance));
01238
01239 childSetText("currency_balance", childGetText("balance_needed"));
01240
01241 }
01242
01243 childSetValue("remove_contribution", LLSD(groupContributionEnough));
01244 childSetEnabled("remove_contribution", groupContributionEnough);
01245 bool showRemoveContribution = mParcelIsGroupLand
01246 && (mParcelGroupContribution > 0);
01247 childSetLabelArg("remove_contribution", "[AMOUNT]",
01248 llformat("%d", minContribution));
01249 childSetVisible("remove_contribution", showRemoveContribution);
01250
01251 childShow("step_3");
01252 childShow("purchase_action");
01253 childShow("currency_reason");
01254 childShow("currency_balance");
01255 }
01256 else
01257 {
01258 childHide("step_3");
01259 childHide("purchase_action");
01260 childHide("currency_reason");
01261 childHide("currency_balance");
01262 childHide("remove_group_donation");
01263 }
01264
01265
01266 bool agrees_to_covenant = false;
01267 LLCheckBoxCtrl* check = (LLCheckBoxCtrl*)getChildByName("agree_covenant");
01268 if (check)
01269 {
01270 agrees_to_covenant = check->get();
01271 }
01272
01273 childSetEnabled("buy_btn",
01274 mCanBuy && mSiteValid && willHaveEnough && !mTransaction && agrees_to_covenant);
01275 }
01276
01277 void LLFloaterBuyLandUI::startBuyPreConfirm()
01278 {
01279 std::string action;
01280
01281 if (mSiteMembershipUpgrade)
01282 {
01283 action += mSiteMembershipAction;
01284 action += "\n";
01285
01286 LLComboBox* levels = LLUICtrlFactory::getComboBoxByName(this, "account_level");
01287 if (levels)
01288 {
01289 action += " * ";
01290 action += mSiteMembershipPlanNames[levels->getCurrentIndex()];
01291 action += "\n";
01292 }
01293 }
01294 if (mSiteLandUseUpgrade)
01295 {
01296 action += mSiteLandUseAction;
01297 action += "\n";
01298 }
01299 if (mCurrency.getAmount() > 0)
01300 {
01301
01302 childSetTextArg("buy_for_US", "[AMOUNT]", llformat("%d", mCurrency.getAmount()));
01303 childSetTextArg("buy_for_US", "[AMOUNT2]", llformat("%#.2f", mCurrency.getEstimate() / 100.0));
01304
01305 action += childGetText("buy_for_US");
01306 }
01307
01308 childSetTextArg("pay_to_for_land", "[AMOUNT]", llformat("%d", mParcelPrice));
01309 childSetTextArg("pay_to_for_land", "[SELLER]", mParcelSellerName);
01310
01311 action += childGetText("pay_to_for_land");
01312
01313
01314 LLConfirmationManager::confirm(mSiteConfirm,
01315 action,
01316 *this,
01317 &LLFloaterBuyLandUI::startBuyPostConfirm);
01318 }
01319
01320 void LLFloaterBuyLandUI::startBuyPostConfirm(const std::string& password)
01321 {
01322 runWebSitePrep(password);
01323
01324 mCanBuy = false;
01325 mCannotBuyReason = childGetText("processing");
01326 refreshUI();
01327 }
01328
01329
01330
01331 void LLFloaterBuyLandUI::onClickBuy(void* data)
01332 {
01333 LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data;
01334 self->startBuyPreConfirm();
01335 }
01336
01337
01338 void LLFloaterBuyLandUI::onClickCancel(void* data)
01339 {
01340 LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data;
01341 self->close();
01342 }
01343
01344
01345 void LLFloaterBuyLandUI::onClickErrorWeb(void* data)
01346 {
01347 LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data;
01348 LLWeb::loadURLExternal(self->mCannotBuyURI);
01349 self->close();
01350 }
01351
01352