PageRenderTime 92ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/indra/newview/llcurrencyuimanager.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 622 lines | 469 code | 109 blank | 44 comment | 44 complexity | 8bbf5fffdec4e358ccbe85469da8307e MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llcurrencyuimanager.cpp
  3. * @brief LLCurrencyUIManager class implementation
  4. *
  5. * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "lluictrlfactory.h"
  28. #include "lltextbox.h"
  29. #include "lllineeditor.h"
  30. #include "llresmgr.h" // for LLLocale
  31. #include "lltrans.h"
  32. #include "llviewercontrol.h"
  33. #include "llversioninfo.h"
  34. #include "llcurrencyuimanager.h"
  35. // viewer includes
  36. #include "llagent.h"
  37. #include "llconfirmationmanager.h"
  38. #include "llframetimer.h"
  39. #include "lllineeditor.h"
  40. #include "llviewchildren.h"
  41. #include "llxmlrpctransaction.h"
  42. #include "llviewernetwork.h"
  43. #include "llpanel.h"
  44. const F64 CURRENCY_ESTIMATE_FREQUENCY = 2.0;
  45. // how long of a pause in typing a currency buy amount before an
  46. // esimate is fetched from the server
  47. class LLCurrencyUIManager::Impl
  48. {
  49. public:
  50. Impl(LLPanel& dialog);
  51. virtual ~Impl();
  52. LLPanel& mPanel;
  53. bool mHidden;
  54. bool mError;
  55. std::string mErrorMessage;
  56. std::string mErrorURI;
  57. std::string mZeroMessage;
  58. // user's choices
  59. S32 mUserCurrencyBuy;
  60. bool mUserEnteredCurrencyBuy;
  61. // from website
  62. // pre-viewer 2.0, the server returned estimates as an
  63. // integer US cents value, e.g., "1000" for $10.00
  64. // post-viewer 2.0, the server may also return estimates
  65. // as a string with currency embedded, e.g., "10.00 Euros"
  66. bool mUSDCurrencyEstimated;
  67. S32 mUSDCurrencyEstimatedCost;
  68. bool mLocalCurrencyEstimated;
  69. std::string mLocalCurrencyEstimatedCost;
  70. bool mSupportsInternationalBilling;
  71. std::string mSiteConfirm;
  72. bool mBought;
  73. enum TransactionType
  74. {
  75. TransactionNone,
  76. TransactionCurrency,
  77. TransactionBuy
  78. };
  79. TransactionType mTransactionType;
  80. LLXMLRPCTransaction* mTransaction;
  81. bool mCurrencyChanged;
  82. LLFrameTimer mCurrencyKeyTimer;
  83. void updateCurrencyInfo();
  84. void finishCurrencyInfo();
  85. void startCurrencyBuy(const std::string& password);
  86. void finishCurrencyBuy();
  87. void clearEstimate();
  88. bool hasEstimate() const;
  89. std::string getLocalEstimate() const;
  90. void startTransaction(TransactionType type,
  91. const char* method, LLXMLRPCValue params);
  92. bool checkTransaction();
  93. // return true if update needed
  94. void setError(const std::string& message, const std::string& uri);
  95. void clearError();
  96. bool considerUpdateCurrency();
  97. // return true if update needed
  98. void currencyKey(S32);
  99. static void onCurrencyKey(LLLineEditor* caller, void* data);
  100. void prepare();
  101. void updateUI();
  102. };
  103. // is potentially not fully constructed.
  104. LLCurrencyUIManager::Impl::Impl(LLPanel& dialog)
  105. : mPanel(dialog),
  106. mHidden(false),
  107. mError(false),
  108. mUserCurrencyBuy(2000), // note, this is a default, real value set in llfloaterbuycurrency.cpp
  109. mUserEnteredCurrencyBuy(false),
  110. mSupportsInternationalBilling(false),
  111. mBought(false),
  112. mTransactionType(TransactionNone), mTransaction(0),
  113. mCurrencyChanged(false)
  114. {
  115. clearEstimate();
  116. }
  117. LLCurrencyUIManager::Impl::~Impl()
  118. {
  119. delete mTransaction;
  120. }
  121. void LLCurrencyUIManager::Impl::updateCurrencyInfo()
  122. {
  123. clearEstimate();
  124. mBought = false;
  125. mCurrencyChanged = false;
  126. if (mUserCurrencyBuy == 0)
  127. {
  128. mLocalCurrencyEstimated = true;
  129. return;
  130. }
  131. LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
  132. keywordArgs.appendString("agentId", gAgent.getID().asString());
  133. keywordArgs.appendString(
  134. "secureSessionId",
  135. gAgent.getSecureSessionID().asString());
  136. keywordArgs.appendString("language", LLUI::getLanguage());
  137. keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy);
  138. keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel());
  139. keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor());
  140. keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor());
  141. keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch());
  142. keywordArgs.appendInt("viewerBuildVersion", LLVersionInfo::getBuild());
  143. LLXMLRPCValue params = LLXMLRPCValue::createArray();
  144. params.append(keywordArgs);
  145. startTransaction(TransactionCurrency, "getCurrencyQuote", params);
  146. }
  147. void LLCurrencyUIManager::Impl::finishCurrencyInfo()
  148. {
  149. LLXMLRPCValue result = mTransaction->responseValue();
  150. bool success = result["success"].asBool();
  151. if (!success)
  152. {
  153. setError(
  154. result["errorMessage"].asString(),
  155. result["errorURI"].asString()
  156. );
  157. return;
  158. }
  159. LLXMLRPCValue currency = result["currency"];
  160. // old XML-RPC server: estimatedCost = value in US cents
  161. mUSDCurrencyEstimated = currency["estimatedCost"].isValid();
  162. if (mUSDCurrencyEstimated)
  163. {
  164. mUSDCurrencyEstimatedCost = currency["estimatedCost"].asInt();
  165. }
  166. // newer XML-RPC server: estimatedLocalCost = local currency string
  167. mLocalCurrencyEstimated = currency["estimatedLocalCost"].isValid();
  168. if (mLocalCurrencyEstimated)
  169. {
  170. mLocalCurrencyEstimatedCost = currency["estimatedLocalCost"].asString();
  171. mSupportsInternationalBilling = true;
  172. }
  173. S32 newCurrencyBuy = currency["currencyBuy"].asInt();
  174. if (newCurrencyBuy != mUserCurrencyBuy)
  175. {
  176. mUserCurrencyBuy = newCurrencyBuy;
  177. mUserEnteredCurrencyBuy = false;
  178. }
  179. mSiteConfirm = result["confirm"].asString();
  180. }
  181. void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password)
  182. {
  183. LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
  184. keywordArgs.appendString("agentId", gAgent.getID().asString());
  185. keywordArgs.appendString(
  186. "secureSessionId",
  187. gAgent.getSecureSessionID().asString());
  188. keywordArgs.appendString("language", LLUI::getLanguage());
  189. keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy);
  190. if (mUSDCurrencyEstimated)
  191. {
  192. keywordArgs.appendInt("estimatedCost", mUSDCurrencyEstimatedCost);
  193. }
  194. if (mLocalCurrencyEstimated)
  195. {
  196. keywordArgs.appendString("estimatedLocalCost", mLocalCurrencyEstimatedCost);
  197. }
  198. keywordArgs.appendString("confirm", mSiteConfirm);
  199. if (!password.empty())
  200. {
  201. keywordArgs.appendString("password", password);
  202. }
  203. keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel());
  204. keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor());
  205. keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor());
  206. keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch());
  207. keywordArgs.appendInt("viewerBuildVersion", LLVersionInfo::getBuild());
  208. LLXMLRPCValue params = LLXMLRPCValue::createArray();
  209. params.append(keywordArgs);
  210. startTransaction(TransactionBuy, "buyCurrency", params);
  211. clearEstimate();
  212. mCurrencyChanged = false;
  213. }
  214. void LLCurrencyUIManager::Impl::finishCurrencyBuy()
  215. {
  216. LLXMLRPCValue result = mTransaction->responseValue();
  217. bool success = result["success"].asBool();
  218. if (!success)
  219. {
  220. setError(
  221. result["errorMessage"].asString(),
  222. result["errorURI"].asString()
  223. );
  224. }
  225. else
  226. {
  227. mUserCurrencyBuy = 0;
  228. mUserEnteredCurrencyBuy = false;
  229. mBought = true;
  230. }
  231. }
  232. void LLCurrencyUIManager::Impl::startTransaction(TransactionType type,
  233. const char* method, LLXMLRPCValue params)
  234. {
  235. static std::string transactionURI;
  236. if (transactionURI.empty())
  237. {
  238. transactionURI = LLGridManager::getInstance()->getHelperURI() + "currency.php";
  239. }
  240. delete mTransaction;
  241. mTransactionType = type;
  242. mTransaction = new LLXMLRPCTransaction(
  243. transactionURI,
  244. method,
  245. params,
  246. false /* don't use gzip */
  247. );
  248. clearError();
  249. }
  250. void LLCurrencyUIManager::Impl::clearEstimate()
  251. {
  252. mUSDCurrencyEstimated = false;
  253. mUSDCurrencyEstimatedCost = 0;
  254. mLocalCurrencyEstimated = false;
  255. mLocalCurrencyEstimatedCost = "0";
  256. }
  257. bool LLCurrencyUIManager::Impl::hasEstimate() const
  258. {
  259. return (mUSDCurrencyEstimated || mLocalCurrencyEstimated);
  260. }
  261. std::string LLCurrencyUIManager::Impl::getLocalEstimate() const
  262. {
  263. if (mLocalCurrencyEstimated)
  264. {
  265. // we have the new-style local currency string
  266. return mLocalCurrencyEstimatedCost;
  267. }
  268. if (mUSDCurrencyEstimated)
  269. {
  270. // we have the old-style USD-specific value
  271. LLStringUtil::format_map_t args;
  272. {
  273. LLLocale locale_override(LLStringUtil::getLocale());
  274. args["[AMOUNT]"] = llformat("%#.2f", mUSDCurrencyEstimatedCost / 100.0);
  275. }
  276. return LLTrans::getString("LocalEstimateUSD", args);
  277. }
  278. return "";
  279. }
  280. bool LLCurrencyUIManager::Impl::checkTransaction()
  281. {
  282. if (!mTransaction)
  283. {
  284. return false;
  285. }
  286. if (!mTransaction->process())
  287. {
  288. return false;
  289. }
  290. if (mTransaction->status(NULL) != LLXMLRPCTransaction::StatusComplete)
  291. {
  292. setError(mTransaction->statusMessage(), mTransaction->statusURI());
  293. }
  294. else {
  295. switch (mTransactionType)
  296. {
  297. case TransactionCurrency: finishCurrencyInfo(); break;
  298. case TransactionBuy: finishCurrencyBuy(); break;
  299. default: ;
  300. }
  301. }
  302. delete mTransaction;
  303. mTransaction = NULL;
  304. mTransactionType = TransactionNone;
  305. return true;
  306. }
  307. void LLCurrencyUIManager::Impl::setError(
  308. const std::string& message, const std::string& uri)
  309. {
  310. mError = true;
  311. mErrorMessage = message;
  312. mErrorURI = uri;
  313. }
  314. void LLCurrencyUIManager::Impl::clearError()
  315. {
  316. mError = false;
  317. mErrorMessage.clear();
  318. mErrorURI.clear();
  319. }
  320. bool LLCurrencyUIManager::Impl::considerUpdateCurrency()
  321. {
  322. if (mCurrencyChanged
  323. && !mTransaction
  324. && mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY)
  325. {
  326. updateCurrencyInfo();
  327. return true;
  328. }
  329. return false;
  330. }
  331. void LLCurrencyUIManager::Impl::currencyKey(S32 value)
  332. {
  333. mUserEnteredCurrencyBuy = true;
  334. mCurrencyKeyTimer.reset();
  335. if (mUserCurrencyBuy == value)
  336. {
  337. return;
  338. }
  339. mUserCurrencyBuy = value;
  340. if (hasEstimate()) {
  341. clearEstimate();
  342. //cannot just simply refresh the whole UI, as the edit field will
  343. // get reset and the cursor will change...
  344. mPanel.getChildView("currency_est")->setVisible(FALSE);
  345. mPanel.getChildView("getting_data")->setVisible(TRUE);
  346. }
  347. mCurrencyChanged = true;
  348. }
  349. // static
  350. void LLCurrencyUIManager::Impl::onCurrencyKey(
  351. LLLineEditor* caller, void* data)
  352. {
  353. S32 value = atoi(caller->getText().c_str());
  354. LLCurrencyUIManager::Impl* self = (LLCurrencyUIManager::Impl*)data;
  355. self->currencyKey(value);
  356. }
  357. void LLCurrencyUIManager::Impl::prepare()
  358. {
  359. LLLineEditor* lindenAmount = mPanel.getChild<LLLineEditor>("currency_amt");
  360. if (lindenAmount)
  361. {
  362. lindenAmount->setPrevalidate(LLTextValidate::validateNonNegativeS32);
  363. lindenAmount->setKeystrokeCallback(onCurrencyKey, this);
  364. }
  365. }
  366. void LLCurrencyUIManager::Impl::updateUI()
  367. {
  368. if (mHidden)
  369. {
  370. mPanel.getChildView("currency_action")->setVisible(FALSE);
  371. mPanel.getChildView("currency_amt")->setVisible(FALSE);
  372. mPanel.getChildView("currency_est")->setVisible(FALSE);
  373. return;
  374. }
  375. mPanel.getChildView("currency_action")->setVisible(TRUE);
  376. LLLineEditor* lindenAmount = mPanel.getChild<LLLineEditor>("currency_amt");
  377. if (lindenAmount)
  378. {
  379. lindenAmount->setVisible(true);
  380. lindenAmount->setLabel(mZeroMessage);
  381. if (!mUserEnteredCurrencyBuy)
  382. {
  383. if (!mZeroMessage.empty() && mUserCurrencyBuy == 0)
  384. {
  385. lindenAmount->setText(LLStringUtil::null);
  386. }
  387. else
  388. {
  389. lindenAmount->setText(llformat("%d", mUserCurrencyBuy));
  390. }
  391. lindenAmount->selectAll();
  392. }
  393. }
  394. mPanel.getChild<LLUICtrl>("currency_est")->setTextArg("[LOCALAMOUNT]", getLocalEstimate());
  395. mPanel.getChildView("currency_est")->setVisible( hasEstimate() && mUserCurrencyBuy > 0);
  396. mPanel.getChildView("currency_links")->setVisible( mSupportsInternationalBilling);
  397. mPanel.getChildView("exchange_rate_note")->setVisible( mSupportsInternationalBilling);
  398. if (mPanel.getChildView("buy_btn")->getEnabled()
  399. ||mPanel.getChildView("currency_est")->getVisible()
  400. || mPanel.getChildView("error_web")->getVisible())
  401. {
  402. mPanel.getChildView("getting_data")->setVisible(FALSE);
  403. }
  404. }
  405. LLCurrencyUIManager::LLCurrencyUIManager(LLPanel& dialog)
  406. : impl(* new Impl(dialog))
  407. {
  408. }
  409. LLCurrencyUIManager::~LLCurrencyUIManager()
  410. {
  411. delete &impl;
  412. }
  413. void LLCurrencyUIManager::setAmount(int amount, bool noEstimate)
  414. {
  415. impl.mUserCurrencyBuy = amount;
  416. impl.mUserEnteredCurrencyBuy = false;
  417. impl.updateUI();
  418. impl.mCurrencyChanged = !noEstimate;
  419. }
  420. int LLCurrencyUIManager::getAmount()
  421. {
  422. return impl.mUserCurrencyBuy;
  423. }
  424. void LLCurrencyUIManager::setZeroMessage(const std::string& message)
  425. {
  426. impl.mZeroMessage = message;
  427. }
  428. void LLCurrencyUIManager::setUSDEstimate(int amount)
  429. {
  430. impl.mUSDCurrencyEstimatedCost = amount;
  431. impl.mUSDCurrencyEstimated = true;
  432. impl.updateUI();
  433. impl.mCurrencyChanged = false;
  434. }
  435. int LLCurrencyUIManager::getUSDEstimate()
  436. {
  437. return impl.mUSDCurrencyEstimated ? impl.mUSDCurrencyEstimatedCost : 0;
  438. }
  439. void LLCurrencyUIManager::setLocalEstimate(const std::string &amount)
  440. {
  441. impl.mLocalCurrencyEstimatedCost = amount;
  442. impl.mLocalCurrencyEstimated = true;
  443. impl.updateUI();
  444. impl.mCurrencyChanged = false;
  445. }
  446. std::string LLCurrencyUIManager::getLocalEstimate() const
  447. {
  448. return impl.getLocalEstimate();
  449. }
  450. void LLCurrencyUIManager::prepare()
  451. {
  452. impl.prepare();
  453. }
  454. void LLCurrencyUIManager::updateUI(bool show)
  455. {
  456. impl.mHidden = !show;
  457. impl.updateUI();
  458. }
  459. bool LLCurrencyUIManager::process()
  460. {
  461. bool changed = false;
  462. changed |= impl.checkTransaction();
  463. changed |= impl.considerUpdateCurrency();
  464. return changed;
  465. }
  466. void LLCurrencyUIManager::buy(const std::string& buy_msg)
  467. {
  468. if (!canBuy())
  469. {
  470. return;
  471. }
  472. LLUIString msg = buy_msg;
  473. msg.setArg("[LINDENS]", llformat("%d", impl.mUserCurrencyBuy));
  474. msg.setArg("[LOCALAMOUNT]", getLocalEstimate());
  475. LLConfirmationManager::confirm(impl.mSiteConfirm,
  476. msg,
  477. impl,
  478. &LLCurrencyUIManager::Impl::startCurrencyBuy);
  479. }
  480. bool LLCurrencyUIManager::inProcess()
  481. {
  482. return impl.mTransactionType != Impl::TransactionNone;
  483. }
  484. bool LLCurrencyUIManager::canCancel()
  485. {
  486. return impl.mTransactionType != Impl::TransactionBuy;
  487. }
  488. bool LLCurrencyUIManager::canBuy()
  489. {
  490. return impl.mTransactionType == Impl::TransactionNone
  491. && impl.hasEstimate()
  492. && impl.mUserCurrencyBuy > 0;
  493. }
  494. bool LLCurrencyUIManager::buying()
  495. {
  496. return impl.mTransactionType == Impl::TransactionBuy;
  497. }
  498. bool LLCurrencyUIManager::bought()
  499. {
  500. return impl.mBought;
  501. }
  502. bool LLCurrencyUIManager::hasError()
  503. {
  504. return impl.mError;
  505. }
  506. std::string LLCurrencyUIManager::errorMessage()
  507. {
  508. return impl.mErrorMessage;
  509. }
  510. std::string LLCurrencyUIManager::errorURI()
  511. {
  512. return impl.mErrorURI;
  513. }