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 "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 // 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         
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 // static
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();     /*Flawfinder: ignore*/
00223 }
00224 
00225 // static
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 // static
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 // static
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 // static
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 // static
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 // static
00277 LLFloaterBuyLandUI* LLFloaterBuyLandUI::sInstance = NULL;
00278 
00279 // static
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 // passing 'this' during construction generates a warning. The callee
00317 // only uses the pointer to hold a reference to 'this' which is
00318 // already valid, so this call does the correct thing. Disable the
00319 // warning so that we can compile without generating a warning.
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         // *TODO: This is an approximation, we should send this value down
00368         // to the viewer. See SL-10728 for details.
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         // Can't have more than region max tasks, regardless of parcel 
00432         // object bonus factor. 
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         // checks that we can buy the land
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                         // Policy: Must not have someone else's land selected
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         // send EstateCovenantInfo message
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 // static
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                                 // remove the line stating that you must agree
00609                                 box->setVisible(FALSE);
00610                         }
00611                         else
00612                         {
00613                                 check->setEnabled(true);
00614 
00615                                 // remove the line stating that you must agree
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         // enable this code if you want the details to blank while we're talking
00657         // to the web site... it's kind of jarring
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];  /*Flawfinder: ignore*/
00823                 
00824                 gCacheName->getGroupName(parcelp->getGroupID(), &groupName[0]);
00825                 mParcelSellerName = groupName;
00826         }
00827         else
00828         {
00829                 char firstName[DB_LAST_NAME_BUF_SIZE];          /*Flawfinder: ignore*/
00830                 char lastName[DB_LAST_NAME_BUF_SIZE];           /*Flawfinder: ignore*/
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         // Select a URI and method appropriate for the transaction type.
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 /* don't use gzip */
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 // virtual
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                 // the user is buying, don't change the selection
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         // section zero: title area
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")//"Buying land for group:"
01035                                                 : childGetText("buying_will")//"Buying this land will:"
01036                                 : 
01037                                         mCannotBuyIsError
01038                                                 ? childGetText("cannot_buy_now")//"Cannot buy now:"
01039                                                 : childGetText("not_for_sale")//"Not for sale:"
01040 
01041                         );
01042         }
01043         
01044         bool showingError = !mCanBuy || !mSiteValid;
01045         
01046         // error section
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         // section one: account
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         // section two: land use fees
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         // section three: purchase & currency
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 // static
01331 void LLFloaterBuyLandUI::onClickBuy(void* data)
01332 {
01333         LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data;
01334         self->startBuyPreConfirm();
01335 }
01336 
01337 // static
01338 void LLFloaterBuyLandUI::onClickCancel(void* data)
01339 {
01340         LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data;
01341         self->close();
01342 }
01343 
01344 // static
01345 void LLFloaterBuyLandUI::onClickErrorWeb(void* data)
01346 {
01347         LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data;
01348         LLWeb::loadURLExternal(self->mCannotBuyURI);
01349         self->close();
01350 }
01351 
01352 

Generated on Thu Jul 1 06:08:32 2010 for Second Life Viewer by  doxygen 1.4.7