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