llcurrencyuimanager.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. /**
  2. * @file llcurrencyuimanager.cpp
  3. * @brief LLCurrencyUIManager class implementation
  4. *
  5. * $LicenseInfo:firstyear=2006&license=viewergpl$
  6. *
  7. * Copyright (c) 2006-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llcurrencyuimanager.h"
  34. #include "llconfirmationmanager.h"
  35. #include "lllineeditor.h"
  36. #include "llpanel.h"
  37. #include "lltextbox.h"
  38. #include "llversionviewer.h"
  39. #include "llxmlrpctransaction.h"
  40. #include "llagent.h"
  41. #include "llgridmanager.h"
  42. #include "llviewercontrol.h"
  43. // How long of a pause in typing a currency buy amount before an esimate is
  44. // fetched from the server:
  45. constexpr F64 CURRENCY_ESTIMATE_FREQUENCY = 2.0;
  46. class LLCurrencyUIManager::Impl
  47. {
  48. public:
  49. Impl(LLPanel& dialog);
  50. ~Impl();
  51. void updateCurrencyInfo();
  52. void finishCurrencyInfo();
  53. void startCurrencyBuy(const std::string& password);
  54. void finishCurrencyBuy();
  55. LL_INLINE void clearEstimate()
  56. {
  57. mUSDCurrencyEstimated = mLocalCurrencyEstimated = false;
  58. mUSDCurrencyEstimatedCost = 0;
  59. mLocalCurrencyEstimatedCost = "0";
  60. }
  61. LL_INLINE bool hasEstimate() const
  62. {
  63. return mUSDCurrencyEstimated || mLocalCurrencyEstimated;
  64. }
  65. std::string getLocalEstimate() const;
  66. enum TransactionType
  67. {
  68. TransactionNone,
  69. TransactionCurrency,
  70. TransactionBuy
  71. };
  72. void startTransaction(TransactionType type, const char* method,
  73. const LLSD& params);
  74. // Returns true if update needed
  75. bool checkTransaction();
  76. void setError(const std::string& message, const std::string& uri);
  77. void clearError();
  78. // Returns true if update needed
  79. bool considerUpdateCurrency();
  80. void currencyKey(S32 value);
  81. static void onCurrencyKey(LLLineEditor* callerp, void* datap);
  82. void prepare();
  83. void updateUI();
  84. public:
  85. LLPanel& mPanel;
  86. LLXMLRPCTransaction* mTransaction;
  87. TransactionType mTransactionType;
  88. LLFrameTimer mCurrencyKeyTimer;
  89. std::string mErrorMessage;
  90. std::string mErrorURI;
  91. std::string mZeroMessage;
  92. std::string mSiteConfirm;
  93. std::string mLocalCurrencyEstimatedCost;
  94. S32 mUSDCurrencyEstimatedCost;
  95. S32 mUserCurrencyBuy;
  96. bool mCurrencyChanged;
  97. bool mUserEnteredCurrencyBuy;
  98. bool mUSDCurrencyEstimated;
  99. bool mLocalCurrencyEstimated;
  100. bool mSupportsInternationalBilling;
  101. bool mBought;
  102. bool mHidden;
  103. bool mError;
  104. };
  105. LLCurrencyUIManager::Impl::Impl(LLPanel& dialog)
  106. : mPanel(dialog),
  107. mTransaction(NULL),
  108. mTransactionType(TransactionNone),
  109. // Note, this is a default, real value set in llfloaterbuycurrency.cpp
  110. mUserCurrencyBuy(2000),
  111. mUserEnteredCurrencyBuy(false),
  112. mSupportsInternationalBilling(false),
  113. mHidden(false),
  114. mError(false),
  115. mBought(false),
  116. mCurrencyChanged(false)
  117. {
  118. clearEstimate();
  119. }
  120. LLCurrencyUIManager::Impl::~Impl()
  121. {
  122. delete mTransaction;
  123. }
  124. static void add_common_params(LLSD& params)
  125. {
  126. params["agentId"] = gAgentID.asString();
  127. params["secureSessionId"] = gAgent.getSecureSessionID().asString();
  128. params["language"] = LLUI::getLanguage();
  129. params["viewerChannel"] = gSavedSettings.getString("VersionChannelName");
  130. params["viewerMajorVersion"] = LL_VERSION_MAJOR;
  131. params["viewerMinorVersion"] = LL_VERSION_MINOR;
  132. params["viewerPatchVersion"] = LL_VERSION_BRANCH;
  133. // Note: to match was LL is doing to fit very large build numbers. HB
  134. params["viewerBuildVersion"] = std::to_string(LL_VERSION_RELEASE);
  135. }
  136. void LLCurrencyUIManager::Impl::updateCurrencyInfo()
  137. {
  138. clearEstimate();
  139. mBought = false;
  140. mCurrencyChanged = false;
  141. if (mUserCurrencyBuy == 0)
  142. {
  143. mLocalCurrencyEstimated = true;
  144. return;
  145. }
  146. LLSD params = LLSD::emptyMap();
  147. add_common_params(params);
  148. params["currencyBuy"] = mUserCurrencyBuy;
  149. startTransaction(TransactionCurrency, "getCurrencyQuote", params);
  150. }
  151. void LLCurrencyUIManager::Impl::finishCurrencyInfo()
  152. {
  153. const LLSD& result = mTransaction->response();
  154. bool success = result["success"].asBoolean();
  155. if (!success)
  156. {
  157. setError(result["errorMessage"].asString(),
  158. result["errorURI"].asString());
  159. return;
  160. }
  161. const LLSD& currency = result["currency"];
  162. // Old XML-RPC server: estimatedCost = value in US$ cents
  163. mUSDCurrencyEstimated = currency.has("estimatedCost");
  164. if (mUSDCurrencyEstimated)
  165. {
  166. mUSDCurrencyEstimatedCost = currency["estimatedCost"].asInteger();
  167. }
  168. // Newer XML-RPC server: estimatedLocalCost = local currency string
  169. mLocalCurrencyEstimated = currency.has("estimatedLocalCost");
  170. if (mLocalCurrencyEstimated)
  171. {
  172. mLocalCurrencyEstimatedCost =
  173. currency["estimatedLocalCost"].asString();
  174. mSupportsInternationalBilling = true;
  175. }
  176. S32 new_currency_buy = currency["currencyBuy"].asInteger();
  177. if (mUserCurrencyBuy != new_currency_buy)
  178. {
  179. mUserCurrencyBuy = new_currency_buy;
  180. mUserEnteredCurrencyBuy = false;
  181. }
  182. mSiteConfirm = result["confirm"].asString();
  183. }
  184. void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password)
  185. {
  186. LLSD params = LLSD::emptyMap();
  187. add_common_params(params);
  188. params["currencyBuy"] = mUserCurrencyBuy;
  189. params["confirm"] = mSiteConfirm;
  190. if (mUSDCurrencyEstimated)
  191. {
  192. params["estimatedCost"] = mUSDCurrencyEstimatedCost;
  193. }
  194. if (mLocalCurrencyEstimated)
  195. {
  196. params["estimatedLocalCost"] = mLocalCurrencyEstimatedCost;
  197. }
  198. if (!password.empty())
  199. {
  200. params["password"] = password;
  201. }
  202. startTransaction(TransactionBuy, "buyCurrency", params);
  203. clearEstimate();
  204. mCurrencyChanged = false;
  205. }
  206. void LLCurrencyUIManager::Impl::finishCurrencyBuy()
  207. {
  208. const LLSD& result = mTransaction->response();
  209. bool success = result["success"].asBoolean();
  210. if (!success)
  211. {
  212. setError(result["errorMessage"].asString(),
  213. result["errorURI"].asString());
  214. }
  215. else
  216. {
  217. mUserCurrencyBuy = 0;
  218. mUserEnteredCurrencyBuy = false;
  219. mBought = true;
  220. }
  221. }
  222. void LLCurrencyUIManager::Impl::startTransaction(TransactionType type,
  223. const char* method,
  224. const LLSD& params)
  225. {
  226. static std::string transaction_uri;
  227. if (transaction_uri.empty())
  228. {
  229. transaction_uri = LLGridManager::getInstance()->getHelperURI() +
  230. "currency.php";
  231. }
  232. delete mTransaction;
  233. mTransactionType = type;
  234. mTransaction = new LLXMLRPCTransaction(transaction_uri, method, params);
  235. clearError();
  236. }
  237. std::string LLCurrencyUIManager::Impl::getLocalEstimate() const
  238. {
  239. if (mLocalCurrencyEstimated)
  240. {
  241. return mLocalCurrencyEstimatedCost;
  242. }
  243. if (mUSDCurrencyEstimated)
  244. {
  245. return llformat("US$ %#.2f", F32(mUSDCurrencyEstimatedCost) * 0.01f);
  246. }
  247. return "";
  248. }
  249. bool LLCurrencyUIManager::Impl::checkTransaction()
  250. {
  251. if (!mTransaction || !mTransaction->process())
  252. {
  253. return false;
  254. }
  255. if (mTransaction->status(NULL) != LLXMLRPCTransaction::StatusComplete)
  256. {
  257. setError(mTransaction->statusMessage(), mTransaction->statusURI());
  258. }
  259. else
  260. {
  261. switch (mTransactionType)
  262. {
  263. case TransactionCurrency:
  264. finishCurrencyInfo();
  265. break;
  266. case TransactionBuy:
  267. finishCurrencyBuy();
  268. break;
  269. default:
  270. break;
  271. }
  272. }
  273. delete mTransaction;
  274. mTransaction = NULL;
  275. mTransactionType = TransactionNone;
  276. return true;
  277. }
  278. void LLCurrencyUIManager::Impl::setError(const std::string& message,
  279. const std::string& uri)
  280. {
  281. mError = true;
  282. mErrorMessage = message;
  283. mErrorURI = uri;
  284. }
  285. void LLCurrencyUIManager::Impl::clearError()
  286. {
  287. mError = false;
  288. mErrorMessage.clear();
  289. mErrorURI.clear();
  290. }
  291. bool LLCurrencyUIManager::Impl::considerUpdateCurrency()
  292. {
  293. if (mCurrencyChanged && !mTransaction &&
  294. mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY)
  295. {
  296. updateCurrencyInfo();
  297. return true;
  298. }
  299. return false;
  300. }
  301. void LLCurrencyUIManager::Impl::currencyKey(S32 value)
  302. {
  303. mUserEnteredCurrencyBuy = true;
  304. mCurrencyKeyTimer.reset();
  305. if (mUserCurrencyBuy == value)
  306. {
  307. return;
  308. }
  309. mUserCurrencyBuy = value;
  310. if (hasEstimate())
  311. {
  312. clearEstimate();
  313. // Cannot just simply refresh the whole UI, as the edit field will get
  314. // reset and the cursor will change...
  315. mPanel.childHide("currency_est");
  316. LLTextBox* textp = mPanel.getChild<LLTextBox>("getting_data", true,
  317. false);
  318. if (textp)
  319. {
  320. textp->setVisible(true);
  321. }
  322. }
  323. mCurrencyChanged = true;
  324. }
  325. //static
  326. void LLCurrencyUIManager::Impl::onCurrencyKey(LLLineEditor* caller, void* data)
  327. {
  328. S32 value = atoi(caller->getText().c_str());
  329. LLCurrencyUIManager::Impl* self = (LLCurrencyUIManager::Impl*)data;
  330. if (self)
  331. {
  332. self->currencyKey(value);
  333. }
  334. }
  335. void LLCurrencyUIManager::Impl::prepare()
  336. {
  337. LLLineEditor* lineeditp = mPanel.getChild<LLLineEditor>("currency_amt");
  338. if (lineeditp)
  339. {
  340. lineeditp->setPrevalidate(LLLineEditor::prevalidateNonNegativeS32);
  341. lineeditp->setKeystrokeCallback(onCurrencyKey);
  342. lineeditp->setCallbackUserData(this);
  343. }
  344. }
  345. void LLCurrencyUIManager::Impl::updateUI()
  346. {
  347. if (mHidden)
  348. {
  349. mPanel.childHide("currency_action");
  350. mPanel.childHide("currency_amt");
  351. mPanel.childHide("currency_est");
  352. return;
  353. }
  354. mPanel.childShow("currency_action");
  355. LLLineEditor* lineeditp = mPanel.getChild<LLLineEditor>("currency_amt");
  356. if (lineeditp)
  357. {
  358. lineeditp->setVisible(true);
  359. lineeditp->setLabel(mZeroMessage);
  360. if (!mUserEnteredCurrencyBuy)
  361. {
  362. if (mUserCurrencyBuy == 0)
  363. {
  364. lineeditp->setText(LLStringUtil::null);
  365. }
  366. else
  367. {
  368. lineeditp->setText(llformat("%d", mUserCurrencyBuy));
  369. }
  370. lineeditp->selectAll();
  371. }
  372. }
  373. std::string estimated = "US$ 0.00";
  374. if (mUserCurrencyBuy)
  375. {
  376. estimated = getLocalEstimate();
  377. }
  378. mPanel.childSetTextArg("currency_est", "[LOCALAMOUNT]", estimated);
  379. mPanel.childSetVisible("currency_est", hasEstimate() || !mUserCurrencyBuy);
  380. LLTextBox* textp = mPanel.getChild<LLTextBox>("getting_data", true, false);
  381. if (textp &&
  382. (mPanel.childIsEnabled("buy_btn") ||
  383. mPanel.childIsVisible("currency_est") ||
  384. mPanel.childIsVisible("error_web")))
  385. {
  386. textp->setVisible(false);
  387. }
  388. }
  389. LLCurrencyUIManager::LLCurrencyUIManager(LLPanel& dialog)
  390. : impl(*new Impl(dialog))
  391. {
  392. }
  393. LLCurrencyUIManager::~LLCurrencyUIManager()
  394. {
  395. delete &impl;
  396. }
  397. void LLCurrencyUIManager::setAmount(S32 amount, bool no_estimate)
  398. {
  399. impl.mUserCurrencyBuy = amount;
  400. impl.mUserEnteredCurrencyBuy = false;
  401. impl.updateUI();
  402. impl.mCurrencyChanged = !no_estimate;
  403. }
  404. S32 LLCurrencyUIManager::getAmount()
  405. {
  406. return impl.mUserCurrencyBuy;
  407. }
  408. void LLCurrencyUIManager::setZeroMessage(const std::string& message)
  409. {
  410. impl.mZeroMessage = message;
  411. }
  412. void LLCurrencyUIManager::setUSDEstimate(S32 amount)
  413. {
  414. impl.mUSDCurrencyEstimatedCost = amount;
  415. impl.mUSDCurrencyEstimated = true;
  416. impl.updateUI();
  417. impl.mCurrencyChanged = false;
  418. }
  419. S32 LLCurrencyUIManager::getUSDEstimate()
  420. {
  421. return impl.mUSDCurrencyEstimated ? impl.mUSDCurrencyEstimatedCost : 0;
  422. }
  423. void LLCurrencyUIManager::setLocalEstimate(const std::string& amount)
  424. {
  425. impl.mLocalCurrencyEstimatedCost = amount;
  426. impl.mLocalCurrencyEstimated = true;
  427. impl.updateUI();
  428. impl.mCurrencyChanged = false;
  429. }
  430. std::string LLCurrencyUIManager::getLocalEstimate() const
  431. {
  432. return impl.getLocalEstimate();
  433. }
  434. void LLCurrencyUIManager::prepare()
  435. {
  436. impl.prepare();
  437. }
  438. void LLCurrencyUIManager::updateUI(bool show)
  439. {
  440. impl.mHidden = !show;
  441. impl.updateUI();
  442. }
  443. bool LLCurrencyUIManager::process()
  444. {
  445. bool changed = false;
  446. changed |= impl.checkTransaction();
  447. changed |= impl.considerUpdateCurrency();
  448. return changed;
  449. }
  450. void LLCurrencyUIManager::buy(const std::string& buy_msg)
  451. {
  452. if (!canBuy())
  453. {
  454. return;
  455. }
  456. LLUIString msg = buy_msg;
  457. msg.setArg("[LINDENS]", llformat("%d", impl.mUserCurrencyBuy));
  458. msg.setArg("[LOCALAMOUNT]", getLocalEstimate());
  459. LLConfirmationManager::confirm(impl.mSiteConfirm, msg, impl,
  460. &LLCurrencyUIManager::Impl::startCurrencyBuy);
  461. }
  462. bool LLCurrencyUIManager::inProcess()
  463. {
  464. return impl.mTransactionType != Impl::TransactionNone;
  465. }
  466. bool LLCurrencyUIManager::canCancel()
  467. {
  468. return !buying();
  469. }
  470. bool LLCurrencyUIManager::canBuy()
  471. {
  472. return !inProcess() && impl.hasEstimate() && impl.mUserCurrencyBuy > 0;
  473. }
  474. bool LLCurrencyUIManager::buying()
  475. {
  476. return impl.mTransactionType == Impl::TransactionBuy;
  477. }
  478. bool LLCurrencyUIManager::bought()
  479. {
  480. return impl.mBought;
  481. }
  482. void LLCurrencyUIManager::clearError()
  483. {
  484. impl.clearError();
  485. }
  486. bool LLCurrencyUIManager::hasError()
  487. {
  488. return impl.mError;
  489. }
  490. std::string LLCurrencyUIManager::errorMessage()
  491. {
  492. return impl.mErrorMessage;
  493. }
  494. std::string LLCurrencyUIManager::errorURI()
  495. {
  496. return impl.mErrorURI;
  497. }