llfloaterpay.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:16k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llfloaterpay.cpp
  3.  * @author Aaron Brashears, Kelly Washington, James Cook
  4.  * @brief Implementation of the LLFloaterPay class.
  5.  *
  6.  * $LicenseInfo:firstyear=2002&license=viewergpl$
  7.  * 
  8.  * Copyright (c) 2002-2010, Linden Research, Inc.
  9.  * 
  10.  * Second Life Viewer Source Code
  11.  * The source code in this file ("Source Code") is provided by Linden Lab
  12.  * to you under the terms of the GNU General Public License, version 2.0
  13.  * ("GPL"), unless you have obtained a separate licensing agreement
  14.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  15.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  16.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  17.  * 
  18.  * There are special exceptions to the terms and conditions of the GPL as
  19.  * it is applied to this Source Code. View the full text of the exception
  20.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  21.  * online at
  22.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  23.  * 
  24.  * By copying, modifying or distributing this software, you acknowledge
  25.  * that you have read and understood your obligations described above,
  26.  * and agree to abide by those obligations.
  27.  * 
  28.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  29.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  30.  * COMPLETENESS OR PERFORMANCE.
  31.  * $/LicenseInfo$
  32.  */
  33. #include "llviewerprecompiledheaders.h"
  34. #include "llfloaterpay.h"
  35. #include "message.h"
  36. #include "llfloater.h"
  37. #include "lllslconstants.h" // MAX_PAY_BUTTONS
  38. #include "lluuid.h"
  39. #include "llagent.h"
  40. #include "llfloaterreg.h"
  41. #include "llresmgr.h"
  42. #include "lltextbox.h"
  43. #include "lllineeditor.h"
  44. #include "llmutelist.h"
  45. #include "llfloaterreporter.h"
  46. #include "llviewerobject.h"
  47. #include "llviewerobjectlist.h"
  48. #include "llviewerregion.h"
  49. #include "llviewerwindow.h"
  50. #include "llbutton.h"
  51. #include "llselectmgr.h"
  52. #include "lltransactiontypes.h"
  53. #include "lluictrlfactory.h"
  54. ///----------------------------------------------------------------------------
  55. /// Local function declarations, constants, enums, and typedefs
  56. ///----------------------------------------------------------------------------
  57. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  58. // Class LLGiveMoneyInfo
  59. //
  60. // A small class used to track callback information
  61. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  62. class LLFloaterPay;
  63. struct LLGiveMoneyInfo
  64. {
  65. LLFloaterPay* mFloater;
  66. S32 mAmount;
  67. LLGiveMoneyInfo(LLFloaterPay* floater, S32 amount) :
  68. mFloater(floater), mAmount(amount){}
  69. };
  70. ///----------------------------------------------------------------------------
  71. /// Class LLFloaterPay
  72. ///----------------------------------------------------------------------------
  73. class LLFloaterPay : public LLFloater
  74. {
  75. public:
  76. LLFloaterPay(const LLSD& key);
  77. virtual ~LLFloaterPay();
  78. /*virtual*/ BOOL postBuild();
  79. /*virtual*/ void onClose(bool app_quitting);
  80. void setCallback(money_callback callback) { mCallback = callback; }
  81. static void payViaObject(money_callback callback, LLSafeHandle<LLObjectSelection> selection);
  82. static void payDirectly(money_callback callback,
  83. const LLUUID& target_id,
  84. bool is_group);
  85. private:
  86. static void onCancel(void* data);
  87. static void onKeystroke(LLLineEditor* editor, void* data);
  88. static void onGive(void* data);
  89. void give(S32 amount);
  90. static void processPayPriceReply(LLMessageSystem* msg, void **userdata);
  91. void onCacheOwnerName(const LLUUID& owner_id,
  92.   const std::string& firstname,
  93.   const std::string& lastname,
  94.   BOOL is_group);
  95. void finishPayUI(const LLUUID& target_id, BOOL is_group);
  96. protected:
  97. std::vector<LLGiveMoneyInfo*> mCallbackData;
  98. money_callback mCallback;
  99. LLTextBox* mObjectNameText;
  100. LLUUID mTargetUUID;
  101. BOOL mTargetIsGroup;
  102. BOOL mHaveName;
  103. LLButton* mQuickPayButton[MAX_PAY_BUTTONS];
  104. LLGiveMoneyInfo* mQuickPayInfo[MAX_PAY_BUTTONS];
  105. LLSafeHandle<LLObjectSelection> mObjectSelection;
  106. static S32 sLastAmount;
  107. };
  108. S32 LLFloaterPay::sLastAmount = 0;
  109. const S32 MAX_AMOUNT_LENGTH = 10;
  110. const S32 FASTPAY_BUTTON_WIDTH = 80;
  111. LLFloaterPay::LLFloaterPay(const LLSD& key)
  112. : LLFloater(key),
  113.   mCallbackData(),
  114.   mCallback(NULL),
  115.   mObjectNameText(NULL),
  116.   mTargetUUID(key.asUUID()),
  117.   mTargetIsGroup(FALSE),
  118.   mHaveName(FALSE)
  119. {
  120. }
  121. // Destroys the object
  122. LLFloaterPay::~LLFloaterPay()
  123. {
  124. std::for_each(mCallbackData.begin(), mCallbackData.end(), DeletePointer());
  125. // Name callbacks will be automatically disconnected since LLFloater is trackable
  126. }
  127. BOOL LLFloaterPay::postBuild()
  128. {
  129. S32 i = 0;
  130. LLGiveMoneyInfo* info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_0);
  131. mCallbackData.push_back(info);
  132. childSetAction("fastpay 1",&LLFloaterPay::onGive,info);
  133. childSetVisible("fastpay 1", FALSE);
  134. mQuickPayButton[i] = getChild<LLButton>("fastpay 1");
  135. mQuickPayInfo[i] = info;
  136. ++i;
  137. info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_1);
  138. mCallbackData.push_back(info);
  139. childSetAction("fastpay 5",&LLFloaterPay::onGive,info);
  140. childSetVisible("fastpay 5", FALSE);
  141. mQuickPayButton[i] = getChild<LLButton>("fastpay 5");
  142. mQuickPayInfo[i] = info;
  143. ++i;
  144. info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_2);
  145. mCallbackData.push_back(info);
  146. childSetAction("fastpay 10",&LLFloaterPay::onGive,info);
  147. childSetVisible("fastpay 10", FALSE);
  148. mQuickPayButton[i] = getChild<LLButton>("fastpay 10");
  149. mQuickPayInfo[i] = info;
  150. ++i;
  151. info = new LLGiveMoneyInfo(this, PAY_BUTTON_DEFAULT_3);
  152. mCallbackData.push_back(info);
  153. childSetAction("fastpay 20",&LLFloaterPay::onGive,info);
  154. childSetVisible("fastpay 20", FALSE);
  155. mQuickPayButton[i] = getChild<LLButton>("fastpay 20");
  156. mQuickPayInfo[i] = info;
  157. ++i;
  158. childSetVisible("amount text", FALSE);
  159. std::string last_amount;
  160. if(sLastAmount > 0)
  161. {
  162. last_amount = llformat("%d", sLastAmount);
  163. }
  164. childSetVisible("amount", FALSE);
  165. getChild<LLLineEditor>("amount")->setKeystrokeCallback(&LLFloaterPay::onKeystroke, this);
  166. childSetText("amount", last_amount);
  167. childSetPrevalidate("amount", LLTextValidate::validateNonNegativeS32);
  168. info = new LLGiveMoneyInfo(this, 0);
  169. mCallbackData.push_back(info);
  170. childSetAction("pay btn",&LLFloaterPay::onGive,info);
  171. setDefaultBtn("pay btn");
  172. childSetVisible("pay btn", FALSE);
  173. childSetEnabled("pay btn", (sLastAmount > 0));
  174. childSetAction("cancel btn",&LLFloaterPay::onCancel,this);
  175. return TRUE;
  176. }
  177. // virtual
  178. void LLFloaterPay::onClose(bool app_quitting)
  179. {
  180. // Deselect the objects
  181. mObjectSelection = NULL;
  182. }
  183. // static
  184. void LLFloaterPay::processPayPriceReply(LLMessageSystem* msg, void **userdata)
  185. {
  186. LLFloaterPay* self = (LLFloaterPay*)userdata;
  187. if (self)
  188. {
  189. S32 price;
  190. LLUUID target;
  191. msg->getUUIDFast(_PREHASH_ObjectData,_PREHASH_ObjectID,target);
  192. if (target != self->mTargetUUID)
  193. {
  194. // This is a message for a different object's pay info
  195. return;
  196. }
  197. msg->getS32Fast(_PREHASH_ObjectData,_PREHASH_DefaultPayPrice,price);
  198. if (PAY_PRICE_HIDE == price)
  199. {
  200. self->childSetVisible("amount", FALSE);
  201. self->childSetVisible("pay btn", FALSE);
  202. self->childSetVisible("amount text", FALSE);
  203. }
  204. else if (PAY_PRICE_DEFAULT == price)
  205. {
  206. self->childSetVisible("amount", TRUE);
  207. self->childSetVisible("pay btn", TRUE);
  208. self->childSetVisible("amount text", TRUE);
  209. }
  210. else
  211. {
  212. // PAY_PRICE_HIDE and PAY_PRICE_DEFAULT are negative values
  213. // So we take the absolute value here after we have checked for those cases
  214. self->childSetVisible("amount", TRUE);
  215. self->childSetVisible("pay btn", TRUE);
  216. self->childSetEnabled("pay btn", TRUE);
  217. self->childSetVisible("amount text", TRUE);
  218. self->childSetText("amount", llformat("%d", llabs(price)));
  219. }
  220. S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_ButtonData);
  221. S32 i = 0;
  222. if (num_blocks > MAX_PAY_BUTTONS) num_blocks = MAX_PAY_BUTTONS;
  223. S32 max_pay_amount = 0;
  224. S32 padding_required = 0;
  225. for (i=0;i<num_blocks;++i)
  226. {
  227. S32 pay_button;
  228. msg->getS32Fast(_PREHASH_ButtonData,_PREHASH_PayButton,pay_button,i);
  229. if (pay_button > 0)
  230. {
  231. std::string button_str = "L$";
  232. button_str += LLResMgr::getInstance()->getMonetaryString( pay_button );
  233. self->mQuickPayButton[i]->setLabelSelected(button_str);
  234. self->mQuickPayButton[i]->setLabelUnselected(button_str);
  235. self->mQuickPayButton[i]->setVisible(TRUE);
  236. self->mQuickPayInfo[i]->mAmount = pay_button;
  237. self->childSetVisible("fastpay text",TRUE);
  238. if ( pay_button > max_pay_amount )
  239. {
  240. max_pay_amount = pay_button;
  241. }
  242. }
  243. else
  244. {
  245. self->mQuickPayButton[i]->setVisible(FALSE);
  246. }
  247. }
  248. // build a string containing the maximum value and calc nerw button width from it.
  249. std::string balance_str = "L$";
  250. balance_str += LLResMgr::getInstance()->getMonetaryString( max_pay_amount );
  251. const LLFontGL* font = LLFontGL::getFontSansSerif();
  252. S32 new_button_width = font->getWidth( std::string(balance_str));
  253. new_button_width += ( 12 + 12 ); // padding
  254. // dialong is sized for 2 digit pay amounts - larger pay values need to be scaled
  255. const S32 threshold = 100000;
  256. if ( max_pay_amount >= threshold )
  257. {
  258. S32 num_digits_threshold = (S32)log10((double)threshold) + 1;
  259. S32 num_digits_max = (S32)log10((double)max_pay_amount) + 1;
  260. // calculate the extra width required by 2 buttons with max amount and some commas
  261. padding_required = ( num_digits_max - num_digits_threshold + ( num_digits_max / 3 ) ) * font->getWidth( std::string("0") );
  262. };
  263. // change in button width
  264. S32 button_delta = new_button_width - FASTPAY_BUTTON_WIDTH;
  265. if ( button_delta < 0 ) 
  266. button_delta = 0;
  267. // now we know the maximum amount, we can resize all the buttons to be 
  268. for (i=0;i<num_blocks;++i)
  269. {
  270. LLRect r;
  271. r = self->mQuickPayButton[i]->getRect();
  272. // RHS button colum needs to move further because LHS changed too
  273. if ( i % 2 )
  274. {
  275. r.setCenterAndSize( r.getCenterX() + ( button_delta * 3 ) / 2 , 
  276. r.getCenterY(), 
  277. r.getWidth() + button_delta, 
  278. r.getHeight() ); 
  279. }
  280. else
  281. {
  282. r.setCenterAndSize( r.getCenterX() + button_delta / 2, 
  283. r.getCenterY(), 
  284. r.getWidth() + button_delta, 
  285. r.getHeight() ); 
  286. }
  287. self->mQuickPayButton[i]->setRect( r );
  288. }
  289. for (i=num_blocks;i<MAX_PAY_BUTTONS;++i)
  290. {
  291. self->mQuickPayButton[i]->setVisible(FALSE);
  292. }
  293. self->reshape( self->getRect().getWidth() + padding_required, self->getRect().getHeight(), FALSE );
  294. }
  295. msg->setHandlerFunc("PayPriceReply",NULL,NULL);
  296. }
  297. // static
  298. void LLFloaterPay::payViaObject(money_callback callback, LLSafeHandle<LLObjectSelection> selection)
  299. {
  300. // Object that lead to the selection, may be child
  301. LLViewerObject* object = selection->getPrimaryObject();
  302. if (!object)
  303. return;
  304. LLFloaterPay *floater = LLFloaterReg::showTypedInstance<LLFloaterPay>("pay_object", LLSD(object->getID()));
  305. if (!floater)
  306. return;
  307. floater->setCallback(callback);
  308. // Hold onto the selection until we close
  309. floater->mObjectSelection = selection;
  310. LLSelectNode* node = selection->getFirstRootNode();
  311. if (!node) 
  312. {
  313. //FIXME: notify user object no longer exists
  314. floater->closeFloater();
  315. return;
  316. }
  317. LLHost target_region = object->getRegion()->getHost();
  318. LLMessageSystem* msg = gMessageSystem;
  319. msg->newMessageFast(_PREHASH_RequestPayPrice);
  320. msg->nextBlockFast(_PREHASH_ObjectData);
  321. msg->addUUIDFast(_PREHASH_ObjectID, object->getID());
  322. msg->sendReliable(target_region);
  323. msg->setHandlerFuncFast(_PREHASH_PayPriceReply, processPayPriceReply,(void **)floater);
  324. LLUUID owner_id;
  325. BOOL is_group = FALSE;
  326. node->mPermissions->getOwnership(owner_id, is_group);
  327. floater->childSetText("object_name_text",node->mName);
  328. floater->finishPayUI(owner_id, is_group);
  329. }
  330. void LLFloaterPay::payDirectly(money_callback callback, 
  331.    const LLUUID& target_id,
  332.    bool is_group)
  333. {
  334. LLFloaterPay *floater = LLFloaterReg::showTypedInstance<LLFloaterPay>("pay_resident", LLSD(target_id));
  335. if (!floater)
  336. return;
  337. floater->setCallback(callback);
  338. floater->mObjectSelection = NULL;
  339. floater->childSetVisible("amount", TRUE);
  340. floater->childSetVisible("pay btn", TRUE);
  341. floater->childSetVisible("amount text", TRUE);
  342. floater->childSetVisible("fastpay text",TRUE);
  343. for(S32 i=0;i<MAX_PAY_BUTTONS;++i)
  344. {
  345. floater->mQuickPayButton[i]->setVisible(TRUE);
  346. }
  347. floater->finishPayUI(target_id, is_group);
  348. }
  349. void LLFloaterPay::finishPayUI(const LLUUID& target_id, BOOL is_group)
  350. {
  351. gCacheName->get(target_id, is_group, boost::bind(&LLFloaterPay::onCacheOwnerName, this, _1, _2, _3, _4));
  352. // Make sure the amount field has focus
  353. childSetFocus("amount", TRUE);
  354. LLLineEditor* amount = getChild<LLLineEditor>("amount");
  355. amount->selectAll();
  356. mTargetIsGroup = is_group;
  357. }
  358. void LLFloaterPay::onCacheOwnerName(const LLUUID& owner_id,
  359. const std::string& firstname,
  360. const std::string& lastname,
  361. BOOL is_group)
  362. {
  363. if (is_group)
  364. {
  365. setTitle(getString("payee_group"));
  366. }
  367. else
  368. {
  369. setTitle(getString("payee_resident"));
  370. }
  371. childSetTextArg("payee_name", "[FIRST]", firstname);
  372. childSetTextArg("payee_name", "[LAST]", lastname);
  373. }
  374. // static
  375. void LLFloaterPay::onCancel(void* data)
  376. {
  377. LLFloaterPay* self = reinterpret_cast<LLFloaterPay*>(data);
  378. if(self)
  379. {
  380. self->closeFloater();
  381. }
  382. }
  383. // static
  384. void LLFloaterPay::onKeystroke(LLLineEditor*, void* data)
  385. {
  386. LLFloaterPay* self = reinterpret_cast<LLFloaterPay*>(data);
  387. if(self)
  388. {
  389. // enable the Pay button when amount is non-empty and positive, disable otherwise
  390. std::string amtstr = self->childGetText("amount");
  391. self->childSetEnabled("pay btn", !amtstr.empty() && atoi(amtstr.c_str()) > 0);
  392. }
  393. }
  394. // static
  395. void LLFloaterPay::onGive(void* data)
  396. {
  397. LLGiveMoneyInfo* info = reinterpret_cast<LLGiveMoneyInfo*>(data);
  398. if(info && info->mFloater)
  399. {
  400. info->mFloater->give(info->mAmount);
  401. info->mFloater->closeFloater();
  402. }
  403. }
  404. void LLFloaterPay::give(S32 amount)
  405. {
  406. if(mCallback)
  407. {
  408. // if the amount is 0, that menas that we should use the
  409. // text field.
  410. if(amount == 0)
  411. {
  412. amount = atoi(childGetText("amount").c_str());
  413. }
  414. sLastAmount = amount;
  415. // Try to pay an object.
  416. if (mObjectSelection.notNull())
  417. {
  418. LLViewerObject* dest_object = gObjectList.findObject(mTargetUUID);
  419. if(dest_object)
  420. {
  421. LLViewerRegion* region = dest_object->getRegion();
  422. if (region)
  423. {
  424. // Find the name of the root object
  425. LLSelectNode* node = mObjectSelection->getFirstRootNode();
  426. std::string object_name;
  427. if (node)
  428. {
  429. object_name = node->mName;
  430. }
  431. S32 tx_type = TRANS_PAY_OBJECT;
  432. if(dest_object->isAvatar()) tx_type = TRANS_GIFT;
  433. mCallback(mTargetUUID, region, amount, FALSE, tx_type, object_name);
  434. mObjectSelection = NULL;
  435. // request the object owner in order to check if the owner needs to be unmuted
  436. LLMessageSystem* msg = gMessageSystem;
  437. msg->newMessageFast(_PREHASH_RequestObjectPropertiesFamily);
  438. msg->nextBlockFast(_PREHASH_AgentData);
  439. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  440. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  441. msg->nextBlockFast(_PREHASH_ObjectData);
  442. msg->addU32Fast(_PREHASH_RequestFlags, OBJECT_PAY_REQUEST );
  443. msg->addUUIDFast(_PREHASH_ObjectID,  mTargetUUID);
  444. msg->sendReliable( region->getHost() );
  445. }
  446. }
  447. }
  448. else
  449. {
  450. // just transfer the L$
  451. mCallback(mTargetUUID, gAgent.getRegion(), amount, mTargetIsGroup, TRANS_GIFT, LLStringUtil::null);
  452. // check if the payee needs to be unmuted
  453. LLMuteList::getInstance()->autoRemove(mTargetUUID, LLMuteList::AR_MONEY);
  454. }
  455. }
  456. }
  457. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  458. // Namespace LLFloaterPayUtil
  459. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  460. void LLFloaterPayUtil::registerFloater()
  461. {
  462. // Sneaky, use same code but different XML for dialogs
  463. LLFloaterReg::add("pay_resident", "floater_pay.xml", 
  464. &LLFloaterReg::build<LLFloaterPay>);
  465. LLFloaterReg::add("pay_object", "floater_pay_object.xml", 
  466. &LLFloaterReg::build<LLFloaterPay>);
  467. }
  468. void LLFloaterPayUtil::payViaObject(money_callback callback,
  469. LLSafeHandle<LLObjectSelection> selection)
  470. {
  471. LLFloaterPay::payViaObject(callback, selection);
  472. }
  473. void LLFloaterPayUtil::payDirectly(money_callback callback,
  474.    const LLUUID& target_id,
  475.    bool is_group)
  476. {
  477. LLFloaterPay::payDirectly(callback, target_id, is_group);
  478. }