llfloatersellland.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /**
  2. * @file llfloatersellland.cpp
  3. *
  4. * $LicenseInfo:firstyear=2006&license=viewergpl$
  5. *
  6. * Copyright (c) 2006-2009, Linden Research, Inc.
  7. *
  8. * Second Life Viewer Source Code
  9. * The source code in this file ("Source Code") is provided by Linden Lab
  10. * to you under the terms of the GNU General Public License, version 2.0
  11. * ("GPL"), unless you have obtained a separate licensing agreement
  12. * ("Other License"), formally executed by you and Linden Lab. Terms of
  13. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  14. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  15. *
  16. * There are special exceptions to the terms and conditions of the GPL as
  17. * it is applied to this Source Code. View the full text of the exception
  18. * in the file doc/FLOSS-exception.txt in this software distribution, or
  19. * online at
  20. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  21. *
  22. * By copying, modifying or distributing this software, you acknowledge
  23. * that you have read and understood your obligations described above,
  24. * and agree to abide by those obligations.
  25. *
  26. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  27. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  28. * COMPLETENESS OR PERFORMANCE.
  29. * $/LicenseInfo$
  30. */
  31. #include "llviewerprecompiledheaders.h"
  32. #include "llfloatersellland.h"
  33. #include "llcachename.h"
  34. #include "lllineeditor.h"
  35. #include "llparcel.h"
  36. #include "lluictrlfactory.h"
  37. #include "llfloateravatarpicker.h"
  38. #include "llfloater.h"
  39. #include "llfloaterland.h"
  40. #include "llselectmgr.h"
  41. #include "lltexturectrl.h"
  42. #include "llviewercontrol.h"
  43. #include "llviewerparcelmgr.h"
  44. //static
  45. LLParcelSelectionObserver* LLFloaterSellLand::sParcelObserver = NULL;
  46. void LLFloaterSellLand::SelectionObserver::changed()
  47. {
  48. LLFloaterSellLand* self = LLFloaterSellLand::findInstance();
  49. if (self)
  50. {
  51. if (gViewerParcelMgr.selectionEmpty())
  52. {
  53. self->close();
  54. }
  55. else
  56. {
  57. self->setParcel(gViewerParcelMgr.getSelectionRegion(),
  58. gViewerParcelMgr.getParcelSelection());
  59. }
  60. }
  61. }
  62. ///////////////////////////////////////////////////////////////////////////////
  63. // Public (and static) interface method
  64. ///////////////////////////////////////////////////////////////////////////////
  65. //static
  66. void LLFloaterSellLand::sellLand(LLViewerRegion* region,
  67. LLParcelSelectionHandle parcel)
  68. {
  69. LLFloaterSellLand* self = getInstance();
  70. if (self && self->setParcel(region, parcel))
  71. {
  72. self->open();
  73. }
  74. }
  75. ///////////////////////////////////////////////////////////////////////////////
  76. // LLFloaterSellLand proper
  77. ///////////////////////////////////////////////////////////////////////////////
  78. LLFloaterSellLand::LLFloaterSellLand(const LLSD&)
  79. : mRegion(NULL)
  80. {
  81. LLUICtrlFactory::getInstance()->buildFloater(this, "floater_sell_land.xml",
  82. NULL, false);
  83. }
  84. LLFloaterSellLand::~LLFloaterSellLand()
  85. {
  86. if (sParcelObserver)
  87. {
  88. gViewerParcelMgr.removeSelectionObserver(sParcelObserver);
  89. delete sParcelObserver;
  90. sParcelObserver = NULL;
  91. }
  92. // Release the selection handle
  93. mParcelSelection = NULL;
  94. }
  95. //virtual
  96. bool LLFloaterSellLand::postBuild()
  97. {
  98. childSetCommitCallback("sell_to", onChangeValue, this);
  99. childSetCommitCallback("price", onChangeValue, this);
  100. childSetPrevalidate("price", LLLineEditor::prevalidateNonNegativeS32);
  101. childSetCommitCallback("sell_objects", onChangeValue, this);
  102. childSetAction("sell_to_select_agent", doSelectAgent, this);
  103. childSetAction("cancel_btn", doCancel, this);
  104. childSetAction("sell_btn", doSellLand, this);
  105. childSetAction("show_objects", doShowObjects, this);
  106. if (!sParcelObserver)
  107. {
  108. sParcelObserver = new SelectionObserver;
  109. gViewerParcelMgr.addSelectionObserver(sParcelObserver);
  110. }
  111. center();
  112. return true;
  113. }
  114. bool LLFloaterSellLand::setParcel(LLViewerRegion* region,
  115. LLParcelSelectionHandle parcel)
  116. {
  117. if (parcel && parcel->getParcel())
  118. {
  119. mRegion = region;
  120. mParcelSelection = parcel;
  121. mChoseSellTo = false;
  122. updateParcelInfo();
  123. refreshUI();
  124. return true;
  125. }
  126. else
  127. {
  128. return false;
  129. }
  130. }
  131. void LLFloaterSellLand::updateParcelInfo()
  132. {
  133. LLParcel* parcelp = mParcelSelection->getParcel();
  134. if (!parcelp) return;
  135. mParcelActualArea = parcelp->getArea();
  136. mParcelIsForSale = parcelp->getForSale();
  137. if (mParcelIsForSale)
  138. {
  139. mChoseSellTo = true;
  140. }
  141. mParcelPrice = mParcelIsForSale ? parcelp->getSalePrice() : 0;
  142. mParcelSoldWithObjects = parcelp->getSellWithObjects();
  143. if (mParcelIsForSale)
  144. {
  145. childSetValue("price", mParcelPrice);
  146. if (mParcelSoldWithObjects)
  147. {
  148. childSetValue("sell_objects", "yes");
  149. }
  150. else
  151. {
  152. childSetValue("sell_objects", "no");
  153. }
  154. }
  155. else
  156. {
  157. childSetValue("price", "");
  158. childSetValue("sell_objects", "none");
  159. }
  160. mParcelSnapshot = parcelp->getSnapshotID();
  161. mAuthorizedBuyer = parcelp->getAuthorizedBuyerID();
  162. mSellToBuyer = mAuthorizedBuyer.notNull();
  163. if (mSellToBuyer && gCacheNamep)
  164. {
  165. std::string name;
  166. gCacheNamep->getFullName(mAuthorizedBuyer, name);
  167. childSetText("sell_to_agent", name);
  168. }
  169. }
  170. void LLFloaterSellLand::setBadge(const char* id, Badge badge)
  171. {
  172. static std::string badgeOK("badge_ok.j2c");
  173. static std::string badgeNote("badge_note.j2c");
  174. static std::string badgeWarn("badge_warn.j2c");
  175. static std::string badgeError("badge_error.j2c");
  176. std::string badge_name;
  177. switch (badge)
  178. {
  179. default:
  180. case BADGE_OK: badge_name = badgeOK; break;
  181. case BADGE_NOTE: badge_name = badgeNote; break;
  182. case BADGE_WARN: badge_name = badgeWarn; break;
  183. case BADGE_ERROR: badge_name = badgeError;
  184. }
  185. childSetValue(id, badge_name);
  186. }
  187. void LLFloaterSellLand::refreshUI()
  188. {
  189. LLParcel* parcelp = mParcelSelection->getParcel();
  190. if (!parcelp) return;
  191. LLTextureCtrl* snapshot = getChild<LLTextureCtrl>("info_image");
  192. if (snapshot)
  193. {
  194. snapshot->setImageAssetID(mParcelSnapshot);
  195. }
  196. childSetText("info_parcel", parcelp->getName());
  197. childSetTextArg("info_size", "[AREA]", llformat("%d", mParcelActualArea));
  198. std::string price_str = childGetValue("price").asString();
  199. bool valid_price = !price_str.empty() &&
  200. LLLineEditor::prevalidateNonNegativeS32(utf8str_to_wstring(price_str));
  201. if (valid_price && mParcelActualArea > 0)
  202. {
  203. F32 per_meter_price = 0;
  204. per_meter_price = F32(mParcelPrice) / F32(mParcelActualArea);
  205. childSetTextArg("price_per_m", "[PER_METER]",
  206. llformat("%0.2f", per_meter_price));
  207. childShow("price_per_m");
  208. setBadge("step_price", BADGE_OK);
  209. }
  210. else
  211. {
  212. childHide("price_per_m");
  213. if ("" == price_str)
  214. {
  215. setBadge("step_price", BADGE_NOTE);
  216. }
  217. else
  218. {
  219. setBadge("step_price", BADGE_ERROR);
  220. }
  221. }
  222. if (mSellToBuyer)
  223. {
  224. childSetValue("sell_to", "user");
  225. childShow("sell_to_agent");
  226. childShow("sell_to_select_agent");
  227. }
  228. else
  229. {
  230. if (mChoseSellTo)
  231. {
  232. childSetValue("sell_to", "anyone");
  233. }
  234. else
  235. {
  236. childSetValue("sell_to", "select");
  237. }
  238. childHide("sell_to_agent");
  239. childHide("sell_to_select_agent");
  240. }
  241. // Must select Sell To: Anybody, or User (with a specified username)
  242. std::string sell_to = childGetValue("sell_to").asString();
  243. bool valid_sell_to = "select" != sell_to &&
  244. ("user" != sell_to || mAuthorizedBuyer.notNull());
  245. if (!valid_sell_to)
  246. {
  247. setBadge("step_sell_to", BADGE_NOTE);
  248. }
  249. else
  250. {
  251. setBadge("step_sell_to", BADGE_OK);
  252. }
  253. bool valid_sell_objects = childGetValue("sell_objects").asString() != "none";
  254. if (!valid_sell_objects)
  255. {
  256. setBadge("step_sell_objects", BADGE_NOTE);
  257. }
  258. else
  259. {
  260. setBadge("step_sell_objects", BADGE_OK);
  261. }
  262. if (valid_sell_to && valid_price && valid_sell_objects)
  263. {
  264. childEnable("sell_btn");
  265. }
  266. else
  267. {
  268. childDisable("sell_btn");
  269. }
  270. }
  271. //static
  272. void LLFloaterSellLand::onChangeValue(LLUICtrl*, void* userdata)
  273. {
  274. LLFloaterSellLand* self = (LLFloaterSellLand*)userdata;
  275. if (!self) return;
  276. std::string sell_to = self->childGetValue("sell_to").asString();
  277. if (sell_to == "user")
  278. {
  279. self->mChoseSellTo = true;
  280. self->mSellToBuyer = true;
  281. if (self->mAuthorizedBuyer.isNull())
  282. {
  283. doSelectAgent(self);
  284. }
  285. }
  286. else if (sell_to == "anyone")
  287. {
  288. self->mChoseSellTo = true;
  289. self->mSellToBuyer = false;
  290. }
  291. self->mParcelPrice = self->childGetValue("price");
  292. if ("yes" == self->childGetValue("sell_objects").asString())
  293. {
  294. self->mParcelSoldWithObjects = true;
  295. }
  296. else
  297. {
  298. self->mParcelSoldWithObjects = false;
  299. }
  300. self->refreshUI();
  301. }
  302. //static
  303. void LLFloaterSellLand::doSelectAgent(void* userdata)
  304. {
  305. LLFloaterSellLand* self = (LLFloaterSellLand*)userdata;
  306. if (!self) return;
  307. // grandparent is a floater, in order to set up dependency
  308. self->addDependentFloater(LLFloaterAvatarPicker::show(callbackAvatarPick,
  309. self, false, true));
  310. }
  311. //static
  312. void LLFloaterSellLand::callbackAvatarPick(const std::vector<std::string>& names,
  313. const std::vector<LLUUID>& ids,
  314. void* data)
  315. {
  316. LLFloaterSellLand* self = (LLFloaterSellLand*)data;
  317. if (!self || names.empty() || ids.empty()) return;
  318. LLParcel* parcel = self->mParcelSelection->getParcel();
  319. if (parcel)
  320. {
  321. const LLUUID& id = ids[0];
  322. parcel->setAuthorizedBuyerID(id);
  323. self->mAuthorizedBuyer = id;
  324. self->childSetText("sell_to_agent", names[0]);
  325. self->refreshUI();
  326. }
  327. }
  328. //static
  329. void LLFloaterSellLand::doCancel(void* userdata)
  330. {
  331. LLFloaterSellLand* self = (LLFloaterSellLand*)userdata;
  332. if (self)
  333. {
  334. self->close();
  335. }
  336. }
  337. //static
  338. void LLFloaterSellLand::doShowObjects(void* userdata)
  339. {
  340. LLFloaterSellLand* self = (LLFloaterSellLand*)userdata;
  341. if (!self) return;
  342. LLParcel* parcel = self->mParcelSelection->getParcel();
  343. if (!parcel) return;
  344. send_parcel_select_objects(parcel->getLocalID(), RT_SELL);
  345. gNotifications.add("TransferObjectsHighlighted", LLSD(), LLSD(),
  346. callbackHighlightTransferable);
  347. }
  348. //static
  349. bool LLFloaterSellLand::callbackHighlightTransferable(const LLSD& notification,
  350. const LLSD& data)
  351. {
  352. gSelectMgr.unhighlightAll();
  353. return false;
  354. }
  355. //static
  356. void LLFloaterSellLand::doSellLand(void* userdata)
  357. {
  358. LLFloaterSellLand* self = (LLFloaterSellLand*)userdata;
  359. if (!self) return;
  360. LLParcel* parcel = self->mParcelSelection->getParcel();
  361. if (!parcel) return;
  362. // Do a confirmation
  363. S32 sale_price = self->childGetValue("price");
  364. S32 area = parcel->getArea();
  365. std::string authorizedBuyerName = "Anyone";
  366. bool sell_to_anyone = true;
  367. if ("user" == self->childGetValue("sell_to").asString())
  368. {
  369. authorizedBuyerName = self->childGetText("sell_to_agent");
  370. sell_to_anyone = false;
  371. }
  372. // must sell to someone if indicating sale to anyone
  373. if (!parcel->getForSale() && sale_price == 0 && sell_to_anyone)
  374. {
  375. gNotifications.add("SalePriceRestriction");
  376. return;
  377. }
  378. LLSD args;
  379. args["LAND_SIZE"] = llformat("%d", area);
  380. args["SALE_PRICE"] = llformat("%d", sale_price);
  381. args["NAME"] = authorizedBuyerName;
  382. LLNotification::Params params("ConfirmLandSaleChange");
  383. params.substitutions(args).functor(boost::bind(&LLFloaterSellLand::onConfirmSale,
  384. self, _1, _2));
  385. if (sell_to_anyone)
  386. {
  387. params.name("ConfirmLandSaleToAnyoneChange");
  388. }
  389. if (parcel->getForSale())
  390. {
  391. // parcel already for sale, so ignore this question
  392. gNotifications.forceResponse(params, -1);
  393. }
  394. else
  395. {
  396. // ask away
  397. gNotifications.add(params);
  398. }
  399. }
  400. bool LLFloaterSellLand::onConfirmSale(const LLSD& notification,
  401. const LLSD& response)
  402. {
  403. S32 option = LLNotification::getSelectedOption(notification, response);
  404. if (option != 0)
  405. {
  406. return false;
  407. }
  408. S32 sale_price = childGetValue("price");
  409. // Valid extracted data
  410. if (sale_price < 0)
  411. {
  412. // TomY TODO: Throw an error
  413. return false;
  414. }
  415. LLParcel* parcel = mParcelSelection->getParcel();
  416. if (!parcel) return false;
  417. #if 0 // can_agent_modify_parcel deprecated by GROUPS
  418. if (!can_agent_modify_parcel(parcel))
  419. {
  420. close();
  421. return;
  422. }
  423. #endif
  424. parcel->setParcelFlag(PF_FOR_SALE, true);
  425. parcel->setSalePrice(sale_price);
  426. bool sell_with_objects = false;
  427. if ("yes" == childGetValue("sell_objects").asString())
  428. {
  429. sell_with_objects = true;
  430. }
  431. parcel->setSellWithObjects(sell_with_objects);
  432. if ("user" == childGetValue("sell_to").asString())
  433. {
  434. parcel->setAuthorizedBuyerID(mAuthorizedBuyer);
  435. }
  436. else
  437. {
  438. parcel->setAuthorizedBuyerID(LLUUID::null);
  439. }
  440. // Send update to server
  441. gViewerParcelMgr.sendParcelPropertiesUpdate(parcel);
  442. close();
  443. return false;
  444. }