PageRenderTime 44ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llfloatersellland.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 547 lines | 409 code | 84 blank | 54 comment | 55 complexity | 7b173a35e19875ebd0bb13c5aca42d5d MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llfloatersellland.cpp
  3. *
  4. * $LicenseInfo:firstyear=2006&license=viewerlgpl$
  5. * Second Life Viewer Source Code
  6. * Copyright (C) 2010, Linden Research, Inc.
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public
  10. * License as published by the Free Software Foundation;
  11. * version 2.1 of the License only.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. * Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with this library; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  23. * $/LicenseInfo$
  24. */
  25. #include "llviewerprecompiledheaders.h"
  26. #include "llfloatersellland.h"
  27. #include "llavatarnamecache.h"
  28. #include "llfloateravatarpicker.h"
  29. #include "llfloaterreg.h"
  30. #include "llfloaterland.h"
  31. #include "lllineeditor.h"
  32. #include "llnotifications.h"
  33. #include "llnotificationsutil.h"
  34. #include "llparcel.h"
  35. #include "llselectmgr.h"
  36. #include "lltexturectrl.h"
  37. #include "llviewercontrol.h"
  38. #include "llviewerparcelmgr.h"
  39. #include "lluictrlfactory.h"
  40. #include "llviewerwindow.h"
  41. #include "lltrans.h"
  42. class LLAvatarName;
  43. // defined in llfloaterland.cpp
  44. void send_parcel_select_objects(S32 parcel_local_id, U32 return_type,
  45. uuid_list_t* return_ids = NULL);
  46. enum Badge { BADGE_OK, BADGE_NOTE, BADGE_WARN, BADGE_ERROR };
  47. class LLFloaterSellLandUI
  48. : public LLFloater
  49. {
  50. public:
  51. LLFloaterSellLandUI(const LLSD& key);
  52. virtual ~LLFloaterSellLandUI();
  53. /*virtual*/ void onClose(bool app_quitting);
  54. private:
  55. class SelectionObserver : public LLParcelObserver
  56. {
  57. public:
  58. SelectionObserver(LLFloaterSellLandUI* floater) : mFloater(floater) {}
  59. virtual void changed();
  60. private:
  61. LLFloaterSellLandUI* mFloater;
  62. };
  63. private:
  64. LLViewerRegion* mRegion;
  65. LLParcelSelectionHandle mParcelSelection;
  66. bool mParcelIsForSale;
  67. bool mSellToBuyer;
  68. bool mChoseSellTo;
  69. S32 mParcelPrice;
  70. S32 mParcelActualArea;
  71. LLUUID mParcelSnapshot;
  72. LLUUID mAuthorizedBuyer;
  73. bool mParcelSoldWithObjects;
  74. SelectionObserver mParcelSelectionObserver;
  75. void updateParcelInfo();
  76. void refreshUI();
  77. void setBadge(const char* id, Badge badge);
  78. static void onChangeValue(LLUICtrl *ctrl, void *userdata);
  79. void doSelectAgent();
  80. static void doCancel(void *userdata);
  81. static void doSellLand(void *userdata);
  82. bool onConfirmSale(const LLSD& notification, const LLSD& response);
  83. static void doShowObjects(void *userdata);
  84. void callbackAvatarPick(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);
  85. void onBuyerNameCache(const LLAvatarName& av_name);
  86. public:
  87. virtual BOOL postBuild();
  88. bool setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel);
  89. static bool callbackHighlightTransferable(const LLSD& notification, const LLSD& response);
  90. };
  91. // static
  92. void LLFloaterSellLand::sellLand(
  93. LLViewerRegion* region, LLParcelSelectionHandle parcel)
  94. {
  95. LLFloaterSellLandUI* ui = LLFloaterReg::showTypedInstance<LLFloaterSellLandUI>("sell_land");
  96. ui->setParcel(region, parcel);
  97. }
  98. // static
  99. LLFloater* LLFloaterSellLand::buildFloater(const LLSD& key)
  100. {
  101. LLFloaterSellLandUI* floater = new LLFloaterSellLandUI(key);
  102. return floater;
  103. }
  104. #if LL_WINDOWS
  105. // passing 'this' during construction generates a warning. The callee
  106. // only uses the pointer to hold a reference to 'this' which is
  107. // already valid, so this call does the correct thing. Disable the
  108. // warning so that we can compile without generating a warning.
  109. #pragma warning(disable : 4355)
  110. #endif
  111. LLFloaterSellLandUI::LLFloaterSellLandUI(const LLSD& key)
  112. : LLFloater(key),
  113. mParcelSelectionObserver(this),
  114. mRegion(0)
  115. {
  116. LLViewerParcelMgr::getInstance()->addObserver(&mParcelSelectionObserver);
  117. }
  118. LLFloaterSellLandUI::~LLFloaterSellLandUI()
  119. {
  120. LLViewerParcelMgr::getInstance()->removeObserver(&mParcelSelectionObserver);
  121. }
  122. // Because we are single_instance, we are not destroyed on close.
  123. void LLFloaterSellLandUI::onClose(bool app_quitting)
  124. {
  125. // Must release parcel selection to allow land to deselect, see EXT-803
  126. mParcelSelection = NULL;
  127. }
  128. void LLFloaterSellLandUI::SelectionObserver::changed()
  129. {
  130. if (LLViewerParcelMgr::getInstance()->selectionEmpty())
  131. {
  132. mFloater->closeFloater();
  133. }
  134. else if (mFloater->getVisible()) // only update selection if sell land ui in use
  135. {
  136. mFloater->setParcel(LLViewerParcelMgr::getInstance()->getSelectionRegion(),
  137. LLViewerParcelMgr::getInstance()->getParcelSelection());
  138. }
  139. }
  140. BOOL LLFloaterSellLandUI::postBuild()
  141. {
  142. childSetCommitCallback("sell_to", onChangeValue, this);
  143. childSetCommitCallback("price", onChangeValue, this);
  144. getChild<LLLineEditor>("price")->setPrevalidate(LLTextValidate::validateNonNegativeS32);
  145. childSetCommitCallback("sell_objects", onChangeValue, this);
  146. childSetAction("sell_to_select_agent", boost::bind( &LLFloaterSellLandUI::doSelectAgent, this));
  147. childSetAction("cancel_btn", doCancel, this);
  148. childSetAction("sell_btn", doSellLand, this);
  149. childSetAction("show_objects", doShowObjects, this);
  150. center();
  151. getChild<LLUICtrl>("profile_scroll")->setTabStop(true);
  152. return TRUE;
  153. }
  154. bool LLFloaterSellLandUI::setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel)
  155. {
  156. if (!parcel->getParcel())
  157. {
  158. return false;
  159. }
  160. mRegion = region;
  161. mParcelSelection = parcel;
  162. mChoseSellTo = false;
  163. updateParcelInfo();
  164. refreshUI();
  165. return true;
  166. }
  167. void LLFloaterSellLandUI::updateParcelInfo()
  168. {
  169. LLParcel* parcelp = mParcelSelection->getParcel();
  170. if (!parcelp) return;
  171. mParcelActualArea = parcelp->getArea();
  172. mParcelIsForSale = parcelp->getForSale();
  173. if (mParcelIsForSale)
  174. {
  175. mChoseSellTo = true;
  176. }
  177. mParcelPrice = mParcelIsForSale ? parcelp->getSalePrice() : 0;
  178. mParcelSoldWithObjects = parcelp->getSellWithObjects();
  179. if (mParcelIsForSale)
  180. {
  181. getChild<LLUICtrl>("price")->setValue(mParcelPrice);
  182. if (mParcelSoldWithObjects)
  183. {
  184. getChild<LLUICtrl>("sell_objects")->setValue("yes");
  185. }
  186. else
  187. {
  188. getChild<LLUICtrl>("sell_objects")->setValue("no");
  189. }
  190. }
  191. else
  192. {
  193. getChild<LLUICtrl>("price")->setValue("");
  194. getChild<LLUICtrl>("sell_objects")->setValue("none");
  195. }
  196. mParcelSnapshot = parcelp->getSnapshotID();
  197. mAuthorizedBuyer = parcelp->getAuthorizedBuyerID();
  198. mSellToBuyer = mAuthorizedBuyer.notNull();
  199. if(mSellToBuyer)
  200. {
  201. LLAvatarNameCache::get(mAuthorizedBuyer,
  202. boost::bind(&LLFloaterSellLandUI::onBuyerNameCache, this, _2));
  203. }
  204. }
  205. void LLFloaterSellLandUI::onBuyerNameCache(const LLAvatarName& av_name)
  206. {
  207. getChild<LLUICtrl>("sell_to_agent")->setValue(av_name.getCompleteName());
  208. getChild<LLUICtrl>("sell_to_agent")->setToolTip(av_name.mUsername);
  209. }
  210. void LLFloaterSellLandUI::setBadge(const char* id, Badge badge)
  211. {
  212. static std::string badgeOK("badge_ok.j2c");
  213. static std::string badgeNote("badge_note.j2c");
  214. static std::string badgeWarn("badge_warn.j2c");
  215. static std::string badgeError("badge_error.j2c");
  216. std::string badgeName;
  217. switch (badge)
  218. {
  219. default:
  220. case BADGE_OK: badgeName = badgeOK; break;
  221. case BADGE_NOTE: badgeName = badgeNote; break;
  222. case BADGE_WARN: badgeName = badgeWarn; break;
  223. case BADGE_ERROR: badgeName = badgeError; break;
  224. }
  225. getChild<LLUICtrl>(id)->setValue(badgeName);
  226. }
  227. void LLFloaterSellLandUI::refreshUI()
  228. {
  229. LLParcel* parcelp = mParcelSelection->getParcel();
  230. if (!parcelp) return;
  231. LLTextureCtrl* snapshot = getChild<LLTextureCtrl>("info_image");
  232. snapshot->setImageAssetID(mParcelSnapshot);
  233. getChild<LLUICtrl>("info_parcel")->setValue(parcelp->getName());
  234. getChild<LLUICtrl>("info_size")->setTextArg("[AREA]", llformat("%d", mParcelActualArea));
  235. std::string price_str = getChild<LLUICtrl>("price")->getValue().asString();
  236. bool valid_price = false;
  237. valid_price = (price_str != "") && LLTextValidate::validateNonNegativeS32(utf8str_to_wstring(price_str));
  238. if (valid_price && mParcelActualArea > 0)
  239. {
  240. F32 per_meter_price = 0;
  241. per_meter_price = F32(mParcelPrice) / F32(mParcelActualArea);
  242. getChild<LLUICtrl>("price_per_m")->setTextArg("[PER_METER]", llformat("%0.2f", per_meter_price));
  243. getChildView("price_per_m")->setVisible(TRUE);
  244. setBadge("step_price", BADGE_OK);
  245. }
  246. else
  247. {
  248. getChildView("price_per_m")->setVisible(FALSE);
  249. if ("" == price_str)
  250. {
  251. setBadge("step_price", BADGE_NOTE);
  252. }
  253. else
  254. {
  255. setBadge("step_price", BADGE_ERROR);
  256. }
  257. }
  258. if (mSellToBuyer)
  259. {
  260. getChild<LLUICtrl>("sell_to")->setValue("user");
  261. getChildView("sell_to_agent")->setVisible(TRUE);
  262. getChildView("sell_to_select_agent")->setVisible(TRUE);
  263. }
  264. else
  265. {
  266. if (mChoseSellTo)
  267. {
  268. getChild<LLUICtrl>("sell_to")->setValue("anyone");
  269. }
  270. else
  271. {
  272. getChild<LLUICtrl>("sell_to")->setValue("select");
  273. }
  274. getChildView("sell_to_agent")->setVisible(FALSE);
  275. getChildView("sell_to_select_agent")->setVisible(FALSE);
  276. }
  277. // Must select Sell To: Anybody, or User (with a specified username)
  278. std::string sell_to = getChild<LLUICtrl>("sell_to")->getValue().asString();
  279. bool valid_sell_to = "select" != sell_to &&
  280. ("user" != sell_to || mAuthorizedBuyer.notNull());
  281. if (!valid_sell_to)
  282. {
  283. setBadge("step_sell_to", BADGE_NOTE);
  284. }
  285. else
  286. {
  287. setBadge("step_sell_to", BADGE_OK);
  288. }
  289. bool valid_sell_objects = ("none" != getChild<LLUICtrl>("sell_objects")->getValue().asString());
  290. if (!valid_sell_objects)
  291. {
  292. setBadge("step_sell_objects", BADGE_NOTE);
  293. }
  294. else
  295. {
  296. setBadge("step_sell_objects", BADGE_OK);
  297. }
  298. if (valid_sell_to && valid_price && valid_sell_objects)
  299. {
  300. getChildView("sell_btn")->setEnabled(TRUE);
  301. }
  302. else
  303. {
  304. getChildView("sell_btn")->setEnabled(FALSE);
  305. }
  306. }
  307. // static
  308. void LLFloaterSellLandUI::onChangeValue(LLUICtrl *ctrl, void *userdata)
  309. {
  310. LLFloaterSellLandUI *self = (LLFloaterSellLandUI *)userdata;
  311. std::string sell_to = self->getChild<LLUICtrl>("sell_to")->getValue().asString();
  312. if (sell_to == "user")
  313. {
  314. self->mChoseSellTo = true;
  315. self->mSellToBuyer = true;
  316. if (self->mAuthorizedBuyer.isNull())
  317. {
  318. self->doSelectAgent();
  319. }
  320. }
  321. else if (sell_to == "anyone")
  322. {
  323. self->mChoseSellTo = true;
  324. self->mSellToBuyer = false;
  325. }
  326. self->mParcelPrice = self->getChild<LLUICtrl>("price")->getValue();
  327. if ("yes" == self->getChild<LLUICtrl>("sell_objects")->getValue().asString())
  328. {
  329. self->mParcelSoldWithObjects = true;
  330. }
  331. else
  332. {
  333. self->mParcelSoldWithObjects = false;
  334. }
  335. self->refreshUI();
  336. }
  337. void LLFloaterSellLandUI::doSelectAgent()
  338. {
  339. // grandparent is a floater, in order to set up dependency
  340. addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLFloaterSellLandUI::callbackAvatarPick, this, _1, _2), FALSE, TRUE));
  341. }
  342. void LLFloaterSellLandUI::callbackAvatarPick(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
  343. {
  344. LLParcel* parcel = mParcelSelection->getParcel();
  345. if (names.empty() || ids.empty()) return;
  346. LLUUID id = ids[0];
  347. parcel->setAuthorizedBuyerID(id);
  348. mAuthorizedBuyer = ids[0];
  349. getChild<LLUICtrl>("sell_to_agent")->setValue(names[0].getCompleteName());
  350. refreshUI();
  351. }
  352. // static
  353. void LLFloaterSellLandUI::doCancel(void *userdata)
  354. {
  355. LLFloaterSellLandUI* self = (LLFloaterSellLandUI*)userdata;
  356. self->closeFloater();
  357. }
  358. // static
  359. void LLFloaterSellLandUI::doShowObjects(void *userdata)
  360. {
  361. LLFloaterSellLandUI* self = (LLFloaterSellLandUI*)userdata;
  362. LLParcel* parcel = self->mParcelSelection->getParcel();
  363. if (!parcel) return;
  364. send_parcel_select_objects(parcel->getLocalID(), RT_SELL);
  365. // we shouldn't pass callback functor since it is registered in LLFunctorRegistration
  366. LLNotificationsUtil::add("TransferObjectsHighlighted",
  367. LLSD(), LLSD());
  368. }
  369. static LLNotificationFunctorRegistration tr("TransferObjectsHighlighted", &LLFloaterSellLandUI::callbackHighlightTransferable);
  370. // static
  371. bool LLFloaterSellLandUI::callbackHighlightTransferable(const LLSD& notification, const LLSD& data)
  372. {
  373. LLSelectMgr::getInstance()->unhighlightAll();
  374. return false;
  375. }
  376. // static
  377. void LLFloaterSellLandUI::doSellLand(void *userdata)
  378. {
  379. LLFloaterSellLandUI* self = (LLFloaterSellLandUI*)userdata;
  380. LLParcel* parcel = self->mParcelSelection->getParcel();
  381. // Do a confirmation
  382. S32 sale_price = self->getChild<LLUICtrl>("price")->getValue();
  383. S32 area = parcel->getArea();
  384. std::string authorizedBuyerName = LLTrans::getString("Anyone");
  385. bool sell_to_anyone = true;
  386. if ("user" == self->getChild<LLUICtrl>("sell_to")->getValue().asString())
  387. {
  388. authorizedBuyerName = self->getChild<LLUICtrl>("sell_to_agent")->getValue().asString();
  389. sell_to_anyone = false;
  390. }
  391. // must sell to someone if indicating sale to anyone
  392. if (!parcel->getForSale()
  393. && (sale_price == 0)
  394. && sell_to_anyone)
  395. {
  396. LLNotificationsUtil::add("SalePriceRestriction");
  397. return;
  398. }
  399. LLSD args;
  400. args["LAND_SIZE"] = llformat("%d",area);
  401. args["SALE_PRICE"] = llformat("%d",sale_price);
  402. args["NAME"] = authorizedBuyerName;
  403. LLNotification::Params params("ConfirmLandSaleChange");
  404. params.substitutions(args)
  405. .functor.function(boost::bind(&LLFloaterSellLandUI::onConfirmSale, self, _1, _2));
  406. if (sell_to_anyone)
  407. {
  408. params.name("ConfirmLandSaleToAnyoneChange");
  409. }
  410. if (parcel->getForSale())
  411. {
  412. // parcel already for sale, so ignore this question
  413. LLNotifications::instance().forceResponse(params, -1);
  414. }
  415. else
  416. {
  417. // ask away
  418. LLNotifications::instance().add(params);
  419. }
  420. }
  421. bool LLFloaterSellLandUI::onConfirmSale(const LLSD& notification, const LLSD& response)
  422. {
  423. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  424. if (option != 0)
  425. {
  426. return false;
  427. }
  428. S32 sale_price = getChild<LLUICtrl>("price")->getValue();
  429. // Valid extracted data
  430. if (sale_price < 0)
  431. {
  432. // TomY TODO: Throw an error
  433. return false;
  434. }
  435. LLParcel* parcel = mParcelSelection->getParcel();
  436. if (!parcel) return false;
  437. // can_agent_modify_parcel deprecated by GROUPS
  438. // if (!can_agent_modify_parcel(parcel))
  439. // {
  440. // close();
  441. // return;
  442. // }
  443. parcel->setParcelFlag(PF_FOR_SALE, TRUE);
  444. parcel->setSalePrice(sale_price);
  445. bool sell_with_objects = false;
  446. if ("yes" == getChild<LLUICtrl>("sell_objects")->getValue().asString())
  447. {
  448. sell_with_objects = true;
  449. }
  450. parcel->setSellWithObjects(sell_with_objects);
  451. if ("user" == getChild<LLUICtrl>("sell_to")->getValue().asString())
  452. {
  453. parcel->setAuthorizedBuyerID(mAuthorizedBuyer);
  454. }
  455. else
  456. {
  457. parcel->setAuthorizedBuyerID(LLUUID::null);
  458. }
  459. // Send update to server
  460. LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel );
  461. closeFloater();
  462. return false;
  463. }