llfloaterbuyland.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llfloaterbuyland.h"
00035 
00036 // viewer includes
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 // NOTE: This is duplicated in lldatamoney.cpp ...
00069 const F32 GROUP_LAND_BONUS_FACTOR = 1.1f;
00070 const F64 CURRENCY_ESTIMATE_FREQUENCY = 0.5;
00071         // how long of a pause in typing a currency buy amount before an
00072         // esimate is fetched from the server
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         // information about the agent
00094         S32                             mAgentCommittedTier;
00095         S32                             mAgentCashBalance;
00096         bool                    mAgentHasNeverOwnedLand;
00097         
00098         // information about the parcel
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         // user's choices
00113         S32                             mUserPlanChoice;
00114         
00115         // from website
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         // values in current Preflight transaction... used to avoid extra
00128         // preflights when the parcel manager goes update crazy
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         /*virtual*/ 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 // static
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();     /*Flawfinder: ignore*/
00224 }
00225 
00226 // static
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 // static
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 // static
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 // static
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 // static
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 // static
00278 LLFloaterBuyLandUI* LLFloaterBuyLandUI::sInstance = NULL;
00279 
00280 // static
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 // passing 'this' during construction generates a warning. The callee
00318 // only uses the pointer to hold a reference to 'this' which is
00319 // already valid, so this call does the correct thing. Disable the
00320 // warning so that we can compile without generating a warning.
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         // *TODO: This is an approximation, we should send this value down
00369         // to the viewer. See SL-10728 for details.
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         // Can't have more than region max tasks, regardless of parcel 
00433         // object bonus factor. 
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         // checks that we can buy the land
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                         // Policy: Must not have someone else's land selected
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         // send EstateCovenantInfo message
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 // static
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                                 // remove the line stating that you must agree
00610                                 box->setVisible(FALSE);
00611                         }
00612                         else
00613                         {
00614                                 check->setEnabled(true);
00615 
00616                                 // remove the line stating that you must agree
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         // enable this code if you want the details to blank while we're talking
00658         // to the web site... it's kind of jarring
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         // Select a URI and method appropriate for the transaction type.
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 /* don't use gzip */
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 // virtual
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                 // the user is buying, don't change the selection
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 // virtual
00973 BOOL LLFloaterBuyLandUI::canClose()
00974 {
00975         bool can_close = (mTransaction ? FALSE : TRUE) && mCurrency.canCancel();
00976         if (!can_close)
00977         {
00978                 // explain to user why they can't do this, see DEV-9605
00979                 gViewerWindow->alertXml("CannotCloseFloaterBuyLand");
00980         }
00981         return can_close;
00982 }
00983 
00984 // virtual
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         // section zero: title area
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")//"Buying land for group:"
01045                                                 : getString("buying_will")//"Buying this land will:"
01046                                 : 
01047                                         mCannotBuyIsError
01048                                                 ? getString("cannot_buy_now")//"Cannot buy now:"
01049                                                 : getString("not_for_sale")//"Not for sale:"
01050 
01051                         );
01052         }
01053         
01054         bool showingError = !mCanBuy || !mSiteValid;
01055         
01056         // error section
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         // section one: account
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         // section two: land use fees
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         // section three: purchase & currency
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 // static
01344 void LLFloaterBuyLandUI::onClickBuy(void* data)
01345 {
01346         LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data;
01347         self->startBuyPreConfirm();
01348 }
01349 
01350 // static
01351 void LLFloaterBuyLandUI::onClickCancel(void* data)
01352 {
01353         LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data;
01354         self->close();
01355 }
01356 
01357 // static
01358 void LLFloaterBuyLandUI::onClickErrorWeb(void* data)
01359 {
01360         LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data;
01361         LLWeb::loadURLExternal(self->mCannotBuyURI);
01362         self->close();
01363 }
01364 
01365 

Generated on Fri May 16 08:33:23 2008 for SecondLife by  doxygen 1.5.5