PageRenderTime 191ms CodeModel.GetById 131ms app.highlight 54ms RepoModel.GetById 2ms app.codeStats 0ms

/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
  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
 27#include "llviewerprecompiledheaders.h"
 28
 29#include "lluictrlfactory.h"
 30#include "lltextbox.h"
 31#include "lllineeditor.h"
 32#include "llresmgr.h" // for LLLocale
 33#include "lltrans.h"
 34#include "llviewercontrol.h"
 35#include "llversioninfo.h"
 36
 37#include "llcurrencyuimanager.h"
 38
 39// viewer includes
 40#include "llagent.h"
 41#include "llconfirmationmanager.h"
 42#include "llframetimer.h"
 43#include "lllineeditor.h"
 44#include "llviewchildren.h"
 45#include "llxmlrpctransaction.h"
 46#include "llviewernetwork.h"
 47#include "llpanel.h"
 48
 49
 50const F64 CURRENCY_ESTIMATE_FREQUENCY = 2.0;
 51	// how long of a pause in typing a currency buy amount before an
 52	// esimate is fetched from the server
 53
 54class LLCurrencyUIManager::Impl
 55{
 56public:
 57	Impl(LLPanel& dialog);
 58	virtual ~Impl();
 59
 60	LLPanel&		mPanel;
 61
 62	bool			mHidden;
 63	
 64	bool			mError;
 65	std::string		mErrorMessage;
 66	std::string		mErrorURI;
 67	
 68	std::string		mZeroMessage;
 69	
 70	// user's choices
 71	S32				mUserCurrencyBuy;
 72	bool			mUserEnteredCurrencyBuy;
 73	
 74	// from website
 75
 76	// pre-viewer 2.0, the server returned estimates as an
 77	// integer US cents value, e.g., "1000" for $10.00
 78	// post-viewer 2.0, the server may also return estimates
 79	// as a string with currency embedded, e.g., "10.00 Euros"
 80	bool			mUSDCurrencyEstimated;
 81	S32				mUSDCurrencyEstimatedCost;
 82	bool			mLocalCurrencyEstimated;
 83	std::string		mLocalCurrencyEstimatedCost;
 84	bool			mSupportsInternationalBilling;
 85	std::string		mSiteConfirm;
 86	
 87	bool			mBought;
 88	
 89	enum TransactionType
 90	{
 91		TransactionNone,
 92		TransactionCurrency,
 93		TransactionBuy
 94	};
 95
 96	TransactionType		 mTransactionType;
 97	LLXMLRPCTransaction* mTransaction;
 98	
 99	bool		 mCurrencyChanged;
100	LLFrameTimer mCurrencyKeyTimer;
101
102
103	void updateCurrencyInfo();
104	void finishCurrencyInfo();
105	
106	void startCurrencyBuy(const std::string& password);
107	void finishCurrencyBuy();
108
109	void clearEstimate();
110	bool hasEstimate() const;
111	std::string getLocalEstimate() const;
112	
113	void startTransaction(TransactionType type,
114		const char* method, LLXMLRPCValue params);
115	bool checkTransaction();
116		// return true if update needed
117	
118	void setError(const std::string& message, const std::string& uri);
119	void clearError();
120
121	bool considerUpdateCurrency();
122		// return true if update needed
123	void currencyKey(S32);
124	static void onCurrencyKey(LLLineEditor* caller, void* data);	
125
126	void prepare();
127	void updateUI();
128};
129
130// is potentially not fully constructed.
131LLCurrencyUIManager::Impl::Impl(LLPanel& dialog)
132	: mPanel(dialog),
133	mHidden(false),
134	mError(false),
135	mUserCurrencyBuy(2000), // note, this is a default, real value set in llfloaterbuycurrency.cpp
136	mUserEnteredCurrencyBuy(false),
137	mSupportsInternationalBilling(false),
138	mBought(false),
139	mTransactionType(TransactionNone), mTransaction(0),
140	mCurrencyChanged(false)
141{
142	clearEstimate();
143}
144
145LLCurrencyUIManager::Impl::~Impl()
146{
147	delete mTransaction;
148}
149
150void LLCurrencyUIManager::Impl::updateCurrencyInfo()
151{
152	clearEstimate();
153	mBought = false;
154	mCurrencyChanged = false;
155
156	if (mUserCurrencyBuy == 0)
157	{
158		mLocalCurrencyEstimated = true;
159		return;
160	}
161	
162	LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
163	keywordArgs.appendString("agentId", gAgent.getID().asString());
164	keywordArgs.appendString(
165		"secureSessionId",
166		gAgent.getSecureSessionID().asString());
167	keywordArgs.appendString("language", LLUI::getLanguage());
168	keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy);
169	keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel());
170	keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor());
171	keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor());
172	keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch());
173	keywordArgs.appendInt("viewerBuildVersion", LLVersionInfo::getBuild());
174	
175	LLXMLRPCValue params = LLXMLRPCValue::createArray();
176	params.append(keywordArgs);
177
178	startTransaction(TransactionCurrency, "getCurrencyQuote", params);
179}
180
181void LLCurrencyUIManager::Impl::finishCurrencyInfo()
182{
183	LLXMLRPCValue result = mTransaction->responseValue();
184
185	bool success = result["success"].asBool();
186	if (!success)
187	{
188		setError(
189			result["errorMessage"].asString(),
190			result["errorURI"].asString()
191		);
192		return;
193	}
194	
195	LLXMLRPCValue currency = result["currency"];
196
197	// old XML-RPC server: estimatedCost = value in US cents
198	mUSDCurrencyEstimated = currency["estimatedCost"].isValid();
199	if (mUSDCurrencyEstimated)
200	{
201		mUSDCurrencyEstimatedCost = currency["estimatedCost"].asInt();
202	}
203
204	// newer XML-RPC server: estimatedLocalCost = local currency string
205	mLocalCurrencyEstimated = currency["estimatedLocalCost"].isValid();
206	if (mLocalCurrencyEstimated)
207	{
208		mLocalCurrencyEstimatedCost = currency["estimatedLocalCost"].asString();
209		mSupportsInternationalBilling = true;
210	}
211
212	S32 newCurrencyBuy = currency["currencyBuy"].asInt();
213	if (newCurrencyBuy != mUserCurrencyBuy)
214	{
215		mUserCurrencyBuy = newCurrencyBuy;
216		mUserEnteredCurrencyBuy = false;
217	}
218
219	mSiteConfirm = result["confirm"].asString();
220}
221
222void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password)
223{
224	LLXMLRPCValue keywordArgs = LLXMLRPCValue::createStruct();
225	keywordArgs.appendString("agentId", gAgent.getID().asString());
226	keywordArgs.appendString(
227		"secureSessionId",
228		gAgent.getSecureSessionID().asString());
229	keywordArgs.appendString("language", LLUI::getLanguage());
230	keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy);
231	if (mUSDCurrencyEstimated)
232	{
233		keywordArgs.appendInt("estimatedCost", mUSDCurrencyEstimatedCost);
234	}
235	if (mLocalCurrencyEstimated)
236	{
237		keywordArgs.appendString("estimatedLocalCost", mLocalCurrencyEstimatedCost);
238	}
239	keywordArgs.appendString("confirm", mSiteConfirm);
240	if (!password.empty())
241	{
242		keywordArgs.appendString("password", password);
243	}
244	keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel());
245	keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor());
246	keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor());
247	keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch());
248	keywordArgs.appendInt("viewerBuildVersion", LLVersionInfo::getBuild());
249
250	LLXMLRPCValue params = LLXMLRPCValue::createArray();
251	params.append(keywordArgs);
252
253	startTransaction(TransactionBuy, "buyCurrency", params);
254
255	clearEstimate();
256	mCurrencyChanged = false;	
257}
258
259void LLCurrencyUIManager::Impl::finishCurrencyBuy()
260{
261	LLXMLRPCValue result = mTransaction->responseValue();
262
263	bool success = result["success"].asBool();
264	if (!success)
265	{
266		setError(
267			result["errorMessage"].asString(),
268			result["errorURI"].asString()
269		);
270	}
271	else
272	{
273		mUserCurrencyBuy = 0;
274		mUserEnteredCurrencyBuy = false;
275		mBought = true;
276	}
277}
278
279void LLCurrencyUIManager::Impl::startTransaction(TransactionType type,
280		const char* method, LLXMLRPCValue params)
281{
282	static std::string transactionURI;
283	if (transactionURI.empty())
284	{
285		transactionURI = LLGridManager::getInstance()->getHelperURI() + "currency.php";
286	}
287
288	delete mTransaction;
289
290	mTransactionType = type;
291	mTransaction = new LLXMLRPCTransaction(
292		transactionURI,
293		method,
294		params,
295		false /* don't use gzip */
296		);
297
298	clearError();
299}
300
301void LLCurrencyUIManager::Impl::clearEstimate()
302{
303	mUSDCurrencyEstimated = false;
304	mUSDCurrencyEstimatedCost = 0;
305	mLocalCurrencyEstimated = false;
306	mLocalCurrencyEstimatedCost = "0";
307}
308
309bool LLCurrencyUIManager::Impl::hasEstimate() const
310{
311	return (mUSDCurrencyEstimated || mLocalCurrencyEstimated);
312}
313
314std::string LLCurrencyUIManager::Impl::getLocalEstimate() const
315{
316	if (mLocalCurrencyEstimated)
317	{
318		// we have the new-style local currency string
319		return mLocalCurrencyEstimatedCost;
320	}
321	if (mUSDCurrencyEstimated)
322	{
323		// we have the old-style USD-specific value
324		LLStringUtil::format_map_t args;
325		{
326			LLLocale locale_override(LLStringUtil::getLocale());
327			args["[AMOUNT]"] = llformat("%#.2f", mUSDCurrencyEstimatedCost / 100.0);
328		}
329		return LLTrans::getString("LocalEstimateUSD", args);
330	}
331	return "";
332}
333
334bool LLCurrencyUIManager::Impl::checkTransaction()
335{
336	if (!mTransaction)
337	{
338		return false;
339	}
340	
341	if (!mTransaction->process())
342	{
343		return false;
344	}
345
346	if (mTransaction->status(NULL) != LLXMLRPCTransaction::StatusComplete)
347	{
348		setError(mTransaction->statusMessage(), mTransaction->statusURI());
349	}
350	else {
351		switch (mTransactionType)
352		{	
353			case TransactionCurrency:	finishCurrencyInfo();	break;
354			case TransactionBuy:		finishCurrencyBuy();	break;
355			default: ;
356		}
357	}
358	
359	delete mTransaction;
360	mTransaction = NULL;
361	mTransactionType = TransactionNone;
362	
363	return true;
364}
365
366void LLCurrencyUIManager::Impl::setError(
367	const std::string& message, const std::string& uri)
368{
369	mError = true;
370	mErrorMessage = message;
371	mErrorURI = uri;
372}
373
374void LLCurrencyUIManager::Impl::clearError()
375{
376	mError = false;
377	mErrorMessage.clear();
378	mErrorURI.clear();
379}
380
381bool LLCurrencyUIManager::Impl::considerUpdateCurrency()
382{
383	if (mCurrencyChanged
384	&&  !mTransaction 
385	&&  mCurrencyKeyTimer.getElapsedTimeF32() >= CURRENCY_ESTIMATE_FREQUENCY)
386	{
387		updateCurrencyInfo();
388		return true;
389	}
390
391	return false;
392}
393
394void LLCurrencyUIManager::Impl::currencyKey(S32 value)
395{
396	mUserEnteredCurrencyBuy = true;
397	mCurrencyKeyTimer.reset();
398
399	if (mUserCurrencyBuy == value)
400	{
401		return;
402	}
403
404	mUserCurrencyBuy = value;
405	
406	if (hasEstimate()) {
407		clearEstimate();
408		//cannot just simply refresh the whole UI, as the edit field will
409		// get reset and the cursor will change...
410		
411		mPanel.getChildView("currency_est")->setVisible(FALSE);
412		mPanel.getChildView("getting_data")->setVisible(TRUE);
413	}
414	
415	mCurrencyChanged = true;
416}
417
418// static
419void LLCurrencyUIManager::Impl::onCurrencyKey(
420		LLLineEditor* caller, void* data)
421{
422	S32 value = atoi(caller->getText().c_str());
423	LLCurrencyUIManager::Impl* self = (LLCurrencyUIManager::Impl*)data;
424	self->currencyKey(value);
425}
426
427void LLCurrencyUIManager::Impl::prepare()
428{
429	LLLineEditor* lindenAmount = mPanel.getChild<LLLineEditor>("currency_amt");
430	if (lindenAmount)
431	{
432		lindenAmount->setPrevalidate(LLTextValidate::validateNonNegativeS32);
433		lindenAmount->setKeystrokeCallback(onCurrencyKey, this);
434	}
435}
436
437void LLCurrencyUIManager::Impl::updateUI()
438{
439	if (mHidden)
440	{
441		mPanel.getChildView("currency_action")->setVisible(FALSE);
442		mPanel.getChildView("currency_amt")->setVisible(FALSE);
443		mPanel.getChildView("currency_est")->setVisible(FALSE);
444		return;
445	}
446
447	mPanel.getChildView("currency_action")->setVisible(TRUE);
448
449	LLLineEditor* lindenAmount = mPanel.getChild<LLLineEditor>("currency_amt");
450	if (lindenAmount) 
451	{
452		lindenAmount->setVisible(true);
453		lindenAmount->setLabel(mZeroMessage);
454		
455		if (!mUserEnteredCurrencyBuy)
456		{
457			if (!mZeroMessage.empty() && mUserCurrencyBuy == 0)
458			{
459				lindenAmount->setText(LLStringUtil::null);
460			}
461			else
462			{
463				lindenAmount->setText(llformat("%d", mUserCurrencyBuy));
464			}
465
466			lindenAmount->selectAll();
467		}
468	}
469
470	mPanel.getChild<LLUICtrl>("currency_est")->setTextArg("[LOCALAMOUNT]", getLocalEstimate());
471	mPanel.getChildView("currency_est")->setVisible( hasEstimate() && mUserCurrencyBuy > 0);
472
473	mPanel.getChildView("currency_links")->setVisible( mSupportsInternationalBilling);
474	mPanel.getChildView("exchange_rate_note")->setVisible( mSupportsInternationalBilling);
475
476	if (mPanel.getChildView("buy_btn")->getEnabled()
477		||mPanel.getChildView("currency_est")->getVisible()
478		|| mPanel.getChildView("error_web")->getVisible())
479	{
480		mPanel.getChildView("getting_data")->setVisible(FALSE);
481	}
482}
483
484
485
486LLCurrencyUIManager::LLCurrencyUIManager(LLPanel& dialog)
487	: impl(* new Impl(dialog))
488{
489}
490
491LLCurrencyUIManager::~LLCurrencyUIManager()
492{
493	delete &impl;
494}
495
496void LLCurrencyUIManager::setAmount(int amount, bool noEstimate)
497{
498	impl.mUserCurrencyBuy = amount;
499	impl.mUserEnteredCurrencyBuy = false;
500	impl.updateUI();
501	
502	impl.mCurrencyChanged = !noEstimate;
503}
504
505int LLCurrencyUIManager::getAmount()
506{
507	return impl.mUserCurrencyBuy;
508}
509
510void LLCurrencyUIManager::setZeroMessage(const std::string& message)
511{
512	impl.mZeroMessage = message;
513}
514
515void LLCurrencyUIManager::setUSDEstimate(int amount)
516{
517	impl.mUSDCurrencyEstimatedCost = amount;
518	impl.mUSDCurrencyEstimated = true;
519	impl.updateUI();
520	
521	impl.mCurrencyChanged = false;
522}
523
524int LLCurrencyUIManager::getUSDEstimate()
525{
526	return impl.mUSDCurrencyEstimated ? impl.mUSDCurrencyEstimatedCost : 0;
527}
528
529void LLCurrencyUIManager::setLocalEstimate(const std::string &amount)
530{
531	impl.mLocalCurrencyEstimatedCost = amount;
532	impl.mLocalCurrencyEstimated = true;
533	impl.updateUI();
534	
535	impl.mCurrencyChanged = false;
536}
537
538std::string LLCurrencyUIManager::getLocalEstimate() const
539{
540	return impl.getLocalEstimate();
541}
542
543void LLCurrencyUIManager::prepare()
544{
545	impl.prepare();
546}
547
548void LLCurrencyUIManager::updateUI(bool show)
549{
550	impl.mHidden = !show;
551	impl.updateUI();
552}
553
554bool LLCurrencyUIManager::process()
555{
556	bool changed = false;
557	changed |= impl.checkTransaction();
558	changed |= impl.considerUpdateCurrency();
559	return changed;
560}
561
562void LLCurrencyUIManager::buy(const std::string& buy_msg)
563{
564	if (!canBuy())
565	{
566		return;
567	}
568
569	LLUIString msg = buy_msg;
570	msg.setArg("[LINDENS]", llformat("%d", impl.mUserCurrencyBuy));
571	msg.setArg("[LOCALAMOUNT]", getLocalEstimate());
572	LLConfirmationManager::confirm(impl.mSiteConfirm,
573								   msg,
574								   impl,
575								   &LLCurrencyUIManager::Impl::startCurrencyBuy);
576}
577
578
579bool LLCurrencyUIManager::inProcess()
580{
581	return impl.mTransactionType != Impl::TransactionNone;
582}
583
584bool LLCurrencyUIManager::canCancel()
585{
586	return impl.mTransactionType != Impl::TransactionBuy;
587}
588
589bool LLCurrencyUIManager::canBuy()
590{
591	return impl.mTransactionType == Impl::TransactionNone
592		&& impl.hasEstimate()
593		&& impl.mUserCurrencyBuy > 0;
594}
595
596bool LLCurrencyUIManager::buying()
597{
598	return impl.mTransactionType == Impl::TransactionBuy;
599}
600
601bool LLCurrencyUIManager::bought()
602{
603	return impl.mBought;
604}
605
606bool LLCurrencyUIManager::hasError()
607{
608	return impl.mError;
609}
610
611std::string LLCurrencyUIManager::errorMessage()
612{
613	return impl.mErrorMessage;
614}
615
616std::string LLCurrencyUIManager::errorURI()
617{
618	return impl.mErrorURI;
619}
620
621
622