00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "lluictrlfactory.h"
00035 #include "lltextbox.h"
00036 #include "lllineeditor.h"
00037
00038 #include "llcurrencyuimanager.h"
00039
00040
00041 #include "llagent.h"
00042 #include "llconfirmationmanager.h"
00043 #include "llframetimer.h"
00044 #include "lllineeditor.h"
00045 #include "llviewchildren.h"
00046 #include "llxmlrpctransaction.h"
00047 #include "viewer.h"
00048
00049
00050
00051 const F64 CURRENCY_ESTIMATE_FREQUENCY = 2.0;
00052
00053
00054
00055 class LLCurrencyUIManager::Impl
00056 {
00057 public:
00058 Impl(LLPanel& dialog);
00059 virtual ~Impl();
00060
00061 LLPanel& mPanel;
00062
00063 bool mHidden;
00064
00065 bool mError;
00066 std::string mErrorMessage;
00067 std::string mErrorURI;
00068
00069 std::string mZeroMessage;
00070
00071
00072 S32 mUserCurrencyBuy;
00073 bool mUserEnteredCurrencyBuy;
00074
00075
00076 bool mSiteCurrencyEstimated;
00077 S32 mSiteCurrencyEstimatedCost;
00078 std::string mSiteConfirm;
00079
00080 bool mBought;
00081
00082 enum TransactionType
00083 {
00084 TransactionNone,
00085 TransactionCurrency,
00086 TransactionBuy
00087 };
00088
00089 TransactionType mTransactionType;
00090 LLXMLRPCTransaction* mTransaction;
00091
00092 bool mCurrencyChanged;
00093 LLFrameTimer mCurrencyKeyTimer;
00094
00095
00096 void updateCurrencyInfo();
00097 void finishCurrencyInfo();
00098
00099 void startCurrencyBuy(const std::string& password);
00100 void finishCurrencyBuy();
00101
00102 void startTransaction(TransactionType type,
00103 const char* method, LLXMLRPCValue params);
00104 bool checkTransaction();
00105
00106
00107 void setError(const std::string& message, const std::string& uri);
00108 void clearError();
00109
00110 bool considerUpdateCurrency();
00111
00112 void currencyKey(S32);
00113 static void onCurrencyKey(LLLineEditor* caller, void* data);
00114
00115 void prepare();
00116 void updateUI();
00117 };
00118
00119
00120 LLCurrencyUIManager::Impl::Impl(LLPanel& dialog)
00121 : mPanel(dialog),
00122 mHidden(false),
00123 mError(false),
00124 mUserCurrencyBuy(1000), mUserEnteredCurrencyBuy(false),
00125 mSiteCurrencyEstimated(false),
00126 mBought(false),
00127 mTransactionType(TransactionNone), mTransaction(0),
00128 mCurrencyChanged(false)
00129 {
00130 }
00131
00132 LLCurrencyUIManager::Impl::~Impl()
00133 {
00134 delete mTransaction;
00135 }
00136
00137 void LLCurrencyUIManager::Impl::updateCurrencyInfo()
00138 {
00139 mSiteCurrencyEstimated = false;
00140 mSiteCurrencyEstimatedCost = 0;
00141 mBought = false;
00142 mCurrencyChanged = false;
00143
00144 if (mUserCurrencyBuy == 0)
00145 {
00146 mSiteCurrencyEstimated = true;
00147 return;
00148 }
00149
00150 LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
00151 keywordArgs.appendString("agentId", gAgent.getID().asString());
00152 keywordArgs.appendString(
00153 "secureSessionId",
00154 gAgent.getSecureSessionID().asString());
00155 keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy);
00156
00157 LLXMLRPCValue params = LLXMLRPCValue::createArray();
00158 params.append(keywordArgs);
00159
00160 startTransaction(TransactionCurrency, "getCurrencyQuote", params);
00161 }
00162
00163 void LLCurrencyUIManager::Impl::finishCurrencyInfo()
00164 {
00165 LLXMLRPCValue result = mTransaction->responseValue();
00166
00167 bool success = result["success"].asBool();
00168 if (!success)
00169 {
00170 setError(
00171 result["errorMessage"].asString(),
00172 result["errorURI"].asString()
00173 );
00174 return;
00175 }
00176
00177 LLXMLRPCValue currency = result["currency"];
00178 mSiteCurrencyEstimated = true;
00179 mSiteCurrencyEstimatedCost = currency["estimatedCost"].asInt();
00180
00181 S32 newCurrencyBuy = currency["currencyBuy"].asInt();
00182 if (newCurrencyBuy != mUserCurrencyBuy)
00183 {
00184 mUserCurrencyBuy = newCurrencyBuy;
00185 mUserEnteredCurrencyBuy = false;
00186 }
00187
00188 mSiteConfirm = result["confirm"].asString();
00189 }
00190
00191 void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password)
00192 {
00193 mSiteCurrencyEstimated = false;
00194 mSiteCurrencyEstimatedCost = 0;
00195 mCurrencyChanged = false;
00196
00197 LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
00198 keywordArgs.appendString("agentId", gAgent.getID().asString());
00199 keywordArgs.appendString(
00200 "secureSessionId",
00201 gAgent.getSecureSessionID().asString());
00202 keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy);
00203 keywordArgs.appendInt("estimatedCost", mSiteCurrencyEstimatedCost);
00204 keywordArgs.appendString("confirm", mSiteConfirm);
00205 if (!password.empty())
00206 {
00207 keywordArgs.appendString("password", password);
00208 }
00209
00210 LLXMLRPCValue params = LLXMLRPCValue::createArray();
00211 params.append(keywordArgs);
00212
00213 startTransaction(TransactionBuy, "buyCurrency", params);
00214 }
00215
00216 void LLCurrencyUIManager::Impl::finishCurrencyBuy()
00217 {
00218 LLXMLRPCValue result = mTransaction->responseValue();
00219
00220 bool success = result["success"].asBool();
00221 if (!success)
00222 {
00223 setError(
00224 result["errorMessage"].asString(),
00225 result["errorURI"].asString()
00226 );
00227 }
00228 else
00229 {
00230 mUserCurrencyBuy = 0;
00231 mUserEnteredCurrencyBuy = false;
00232 mBought = true;
00233 }
00234 }
00235
00236 void LLCurrencyUIManager::Impl::startTransaction(TransactionType type,
00237 const char* method, LLXMLRPCValue params)
00238 {
00239 static std::string transactionURI;
00240 if (transactionURI.empty())
00241 {
00242 transactionURI = getHelperURI() + "currency.php";
00243 }
00244
00245 delete mTransaction;
00246
00247 mTransactionType = type;
00248 mTransaction = new LLXMLRPCTransaction(
00249 transactionURI,
00250 method,
00251 params,
00252 false
00253 );
00254
00255 clearError();
00256 }
00257
00258 bool LLCurrencyUIManager::Impl::checkTransaction()
00259 {
00260 if (!mTransaction)
00261 {
00262 return false;
00263 }
00264
00265 if (!mTransaction->process())
00266 {
00267 return false;
00268 }
00269
00270 if (mTransaction->status(NULL) != LLXMLRPCTransaction::StatusComplete)
00271 {
00272 setError(mTransaction->statusMessage(), mTransaction->statusURI());
00273 }
00274 else {
00275 switch (mTransactionType)
00276 {
00277 case TransactionCurrency: finishCurrencyInfo(); break;
00278 case TransactionBuy: finishCurrencyBuy(); break;
00279 default: ;
00280 }
00281 }
00282
00283 delete mTransaction;
00284 mTransaction = NULL;
00285 mTransactionType = TransactionNone;
00286
00287 return true;
00288 }
00289
00290 void LLCurrencyUIManager::Impl::setError(
00291 const std::string& message, const std::string& uri)
00292 {
00293 mError = true;
00294 mErrorMessage = message;
00295 mErrorURI = uri;
00296 }
00297
00298 void LLCurrencyUIManager::Impl::clearError()
00299 {
00300 mError = false;
00301 mErrorMessage.clear();
00302 mErrorURI.clear();
00303 }
00304
00305 bool LLCurrencyUIManager::Impl::considerUpdateCurrency()
00306 {
00307 if (mCurrencyChanged
00308 && !mTransaction
00309 && mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY)
00310 {
00311 updateCurrencyInfo();
00312 return true;
00313 }
00314
00315 return false;
00316 }
00317
00318 void LLCurrencyUIManager::Impl::currencyKey(S32 value)
00319 {
00320 mUserEnteredCurrencyBuy = true;
00321 mCurrencyKeyTimer.reset();
00322
00323 if (mUserCurrencyBuy == value)
00324 {
00325 return;
00326 }
00327
00328 mUserCurrencyBuy = value;
00329
00330 if (mSiteCurrencyEstimated) {
00331 mSiteCurrencyEstimated = false;
00332
00333
00334
00335 mPanel.childHide("currency_est");
00336 }
00337
00338 mCurrencyChanged = true;
00339 }
00340
00341
00342 void LLCurrencyUIManager::Impl::onCurrencyKey(
00343 LLLineEditor* caller, void* data)
00344 {
00345 S32 value = atoi(caller->getText().c_str());
00346 LLCurrencyUIManager::Impl* self = (LLCurrencyUIManager::Impl*)data;
00347 self->currencyKey(value);
00348 }
00349
00350 void LLCurrencyUIManager::Impl::prepare()
00351 {
00352 LLLineEditor* lindenAmount = LLUICtrlFactory::getLineEditorByName(&mPanel,"currency_amt");
00353 if (lindenAmount)
00354 {
00355 lindenAmount->setPrevalidate(LLLineEditor::prevalidateNonNegativeS32);
00356 lindenAmount->setKeystrokeCallback(onCurrencyKey);
00357 lindenAmount->setCallbackUserData(this);
00358 }
00359 }
00360
00361 void LLCurrencyUIManager::Impl::updateUI()
00362 {
00363 if (mHidden)
00364 {
00365 mPanel.childHide("currency_action");
00366 mPanel.childHide("currency_amt");
00367 mPanel.childHide("currency_est");
00368 return;
00369 }
00370
00371 mPanel.childShow("currency_action");
00372
00373 LLLineEditor* lindenAmount = LLUICtrlFactory::getLineEditorByName(&mPanel,"currency_amt");
00374 if (lindenAmount)
00375 {
00376 lindenAmount->setVisible(true);
00377 lindenAmount->setLabel(mZeroMessage);
00378
00379 if (!mUserEnteredCurrencyBuy)
00380 {
00381 if (!mZeroMessage.empty() && mUserCurrencyBuy == 0)
00382 {
00383 lindenAmount->setText(LLString::null);
00384 }
00385 else
00386 {
00387 lindenAmount->setText(llformat("%d", mUserCurrencyBuy));
00388 }
00389
00390 lindenAmount->selectAll();
00391 }
00392 }
00393
00394 mPanel.childSetTextArg("currency_est", "[USD]", llformat("%#.2f", mSiteCurrencyEstimatedCost / 100.0));
00395 mPanel.childSetVisible("currency_est", mSiteCurrencyEstimated && mUserCurrencyBuy > 0);
00396 }
00397
00398
00399
00400 LLCurrencyUIManager::LLCurrencyUIManager(LLPanel& dialog)
00401 : impl(* new Impl(dialog))
00402 {
00403 }
00404
00405 LLCurrencyUIManager::~LLCurrencyUIManager()
00406 {
00407 delete &impl;
00408 }
00409
00410 void LLCurrencyUIManager::setAmount(int amount, bool noEstimate)
00411 {
00412 impl.mUserCurrencyBuy = amount;
00413 impl.mUserEnteredCurrencyBuy = false;
00414 impl.updateUI();
00415
00416 impl.mCurrencyChanged = !noEstimate;
00417 }
00418
00419 int LLCurrencyUIManager::getAmount()
00420 {
00421 return impl.mUserCurrencyBuy;
00422 }
00423
00424 void LLCurrencyUIManager::setZeroMessage(const std::string& message)
00425 {
00426 impl.mZeroMessage = message;
00427 }
00428
00429 void LLCurrencyUIManager::setEstimate(int amount)
00430 {
00431 impl.mSiteCurrencyEstimatedCost = amount;
00432 impl.mSiteCurrencyEstimated = true;
00433 impl.updateUI();
00434
00435 impl.mCurrencyChanged = false;
00436 }
00437
00438 int LLCurrencyUIManager::getEstimate()
00439 {
00440 return impl.mSiteCurrencyEstimated ? impl.mSiteCurrencyEstimatedCost : 0;
00441 }
00442
00443 void LLCurrencyUIManager::prepare()
00444 {
00445 impl.prepare();
00446 }
00447
00448 void LLCurrencyUIManager::updateUI(bool show)
00449 {
00450 impl.mHidden = !show;
00451 impl.updateUI();
00452 }
00453
00454 bool LLCurrencyUIManager::process()
00455 {
00456 bool changed = false;
00457 changed |= impl.checkTransaction();
00458 changed |= impl.considerUpdateCurrency();
00459 return changed;
00460 }
00461
00462 void LLCurrencyUIManager::buy(const LLString& buy_msg)
00463 {
00464 if (!canBuy())
00465 {
00466 return;
00467 }
00468
00469 LLUIString msg = buy_msg;
00470 msg.setArg("[LINDENS]", llformat("%d", impl.mUserCurrencyBuy));
00471 msg.setArg("[USD]", llformat("%#.2f", impl.mSiteCurrencyEstimatedCost / 100.0));
00472 LLConfirmationManager::confirm(impl.mSiteConfirm,
00473 msg,
00474 impl,
00475 &LLCurrencyUIManager::Impl::startCurrencyBuy);
00476 }
00477
00478
00479 bool LLCurrencyUIManager::inProcess()
00480 {
00481 return impl.mTransactionType != Impl::TransactionNone;
00482 }
00483
00484 bool LLCurrencyUIManager::canCancel()
00485 {
00486 return impl.mTransactionType != Impl::TransactionBuy;
00487 }
00488
00489 bool LLCurrencyUIManager::canBuy()
00490 {
00491 return impl.mTransactionType == Impl::TransactionNone
00492 && impl.mSiteCurrencyEstimated
00493 && impl.mUserCurrencyBuy > 0;
00494 }
00495
00496 bool LLCurrencyUIManager::buying()
00497 {
00498 return impl.mTransactionType == Impl::TransactionBuy;
00499 }
00500
00501 bool LLCurrencyUIManager::bought()
00502 {
00503 return impl.mBought;
00504 }
00505
00506 bool LLCurrencyUIManager::hasError()
00507 {
00508 return impl.mError;
00509 }
00510
00511 std::string LLCurrencyUIManager::errorMessage()
00512 {
00513 return impl.mErrorMessage;
00514 }
00515
00516 std::string LLCurrencyUIManager::errorURI()
00517 {
00518 return impl.mErrorURI;
00519 }
00520
00521