PageRenderTime 90ms CodeModel.GetById 26ms app.highlight 58ms RepoModel.GetById 1ms 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
  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
 26#include "llviewerprecompiledheaders.h"
 27
 28#include "llfloatersellland.h"
 29
 30#include "llavatarnamecache.h"
 31#include "llfloateravatarpicker.h"
 32#include "llfloaterreg.h"
 33#include "llfloaterland.h"
 34#include "lllineeditor.h"
 35#include "llnotifications.h"
 36#include "llnotificationsutil.h"
 37#include "llparcel.h"
 38#include "llselectmgr.h"
 39#include "lltexturectrl.h"
 40#include "llviewercontrol.h"
 41#include "llviewerparcelmgr.h"
 42#include "lluictrlfactory.h"
 43#include "llviewerwindow.h"
 44#include "lltrans.h"
 45
 46class LLAvatarName;
 47
 48// defined in llfloaterland.cpp
 49void send_parcel_select_objects(S32 parcel_local_id, U32 return_type,
 50								uuid_list_t* return_ids = NULL);
 51
 52enum Badge { BADGE_OK, BADGE_NOTE, BADGE_WARN, BADGE_ERROR };
 53
 54class LLFloaterSellLandUI
 55:	public LLFloater
 56{
 57public:
 58	LLFloaterSellLandUI(const LLSD& key);
 59	virtual ~LLFloaterSellLandUI();
 60	/*virtual*/ void onClose(bool app_quitting);
 61	
 62private:
 63	class SelectionObserver : public LLParcelObserver
 64	{
 65	public:
 66		SelectionObserver(LLFloaterSellLandUI* floater) : mFloater(floater) {}
 67		virtual void changed();
 68	private:
 69		LLFloaterSellLandUI* mFloater;
 70	};
 71	
 72private:
 73	LLViewerRegion*	mRegion;
 74	LLParcelSelectionHandle	mParcelSelection;
 75	bool					mParcelIsForSale;
 76	bool					mSellToBuyer;
 77	bool					mChoseSellTo;
 78	S32						mParcelPrice;
 79	S32						mParcelActualArea;
 80	LLUUID					mParcelSnapshot;
 81	LLUUID					mAuthorizedBuyer;
 82	bool					mParcelSoldWithObjects;
 83	SelectionObserver 		mParcelSelectionObserver;
 84	
 85	void updateParcelInfo();
 86	void refreshUI();
 87	void setBadge(const char* id, Badge badge);
 88
 89	static void onChangeValue(LLUICtrl *ctrl, void *userdata);
 90	void doSelectAgent();
 91	static void doCancel(void *userdata);
 92	static void doSellLand(void *userdata);
 93	bool onConfirmSale(const LLSD& notification, const LLSD& response);
 94	static void doShowObjects(void *userdata);
 95
 96	void callbackAvatarPick(const uuid_vec_t& ids, const std::vector<LLAvatarName> names);
 97
 98	void onBuyerNameCache(const LLAvatarName& av_name);
 99
100public:
101	virtual BOOL postBuild();
102	
103	bool setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel);
104	static bool callbackHighlightTransferable(const LLSD& notification, const LLSD& response);
105};
106
107// static
108void LLFloaterSellLand::sellLand(
109	LLViewerRegion* region, LLParcelSelectionHandle parcel)
110{
111	LLFloaterSellLandUI* ui = LLFloaterReg::showTypedInstance<LLFloaterSellLandUI>("sell_land");
112	ui->setParcel(region, parcel);
113}
114
115// static
116LLFloater* LLFloaterSellLand::buildFloater(const LLSD& key)
117{
118	LLFloaterSellLandUI* floater = new LLFloaterSellLandUI(key);
119	return floater;
120}
121
122#if LL_WINDOWS
123// passing 'this' during construction generates a warning. The callee
124// only uses the pointer to hold a reference to 'this' which is
125// already valid, so this call does the correct thing. Disable the
126// warning so that we can compile without generating a warning.
127#pragma warning(disable : 4355)
128#endif 
129LLFloaterSellLandUI::LLFloaterSellLandUI(const LLSD& key)
130:	LLFloater(key),
131	mParcelSelectionObserver(this),
132	mRegion(0)
133{
134	LLViewerParcelMgr::getInstance()->addObserver(&mParcelSelectionObserver);
135}
136
137LLFloaterSellLandUI::~LLFloaterSellLandUI()
138{
139	LLViewerParcelMgr::getInstance()->removeObserver(&mParcelSelectionObserver);
140}
141
142// Because we are single_instance, we are not destroyed on close.
143void LLFloaterSellLandUI::onClose(bool app_quitting)
144{
145	// Must release parcel selection to allow land to deselect, see EXT-803
146	mParcelSelection = NULL;
147}
148
149void LLFloaterSellLandUI::SelectionObserver::changed()
150{
151	if (LLViewerParcelMgr::getInstance()->selectionEmpty())
152	{
153		mFloater->closeFloater();
154	}
155	else if (mFloater->getVisible()) // only update selection if sell land ui in use
156	{
157		mFloater->setParcel(LLViewerParcelMgr::getInstance()->getSelectionRegion(),
158							LLViewerParcelMgr::getInstance()->getParcelSelection());
159	}
160}
161
162BOOL LLFloaterSellLandUI::postBuild()
163{
164	childSetCommitCallback("sell_to", onChangeValue, this);
165	childSetCommitCallback("price", onChangeValue, this);
166	getChild<LLLineEditor>("price")->setPrevalidate(LLTextValidate::validateNonNegativeS32);
167	childSetCommitCallback("sell_objects", onChangeValue, this);
168	childSetAction("sell_to_select_agent", boost::bind( &LLFloaterSellLandUI::doSelectAgent, this));
169	childSetAction("cancel_btn", doCancel, this);
170	childSetAction("sell_btn", doSellLand, this);
171	childSetAction("show_objects", doShowObjects, this);
172	center();
173	getChild<LLUICtrl>("profile_scroll")->setTabStop(true);
174	return TRUE;
175}
176
177bool LLFloaterSellLandUI::setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel)
178{
179	if (!parcel->getParcel())
180	{
181		return false;
182	}
183
184	mRegion = region;
185	mParcelSelection = parcel;
186	mChoseSellTo = false;
187
188
189	updateParcelInfo();
190	refreshUI();
191
192	return true;
193}
194
195void LLFloaterSellLandUI::updateParcelInfo()
196{
197	LLParcel* parcelp = mParcelSelection->getParcel();
198	if (!parcelp) return;
199
200	mParcelActualArea = parcelp->getArea();
201	mParcelIsForSale = parcelp->getForSale();
202	if (mParcelIsForSale)
203	{
204		mChoseSellTo = true;
205	}
206	mParcelPrice = mParcelIsForSale ? parcelp->getSalePrice() : 0;
207	mParcelSoldWithObjects = parcelp->getSellWithObjects();
208	if (mParcelIsForSale)
209	{
210		getChild<LLUICtrl>("price")->setValue(mParcelPrice);
211		if (mParcelSoldWithObjects)
212		{
213			getChild<LLUICtrl>("sell_objects")->setValue("yes");
214		}
215		else
216		{
217			getChild<LLUICtrl>("sell_objects")->setValue("no");
218		}
219	}
220	else
221	{
222		getChild<LLUICtrl>("price")->setValue("");
223		getChild<LLUICtrl>("sell_objects")->setValue("none");
224	}
225
226	mParcelSnapshot = parcelp->getSnapshotID();
227
228	mAuthorizedBuyer = parcelp->getAuthorizedBuyerID();
229	mSellToBuyer = mAuthorizedBuyer.notNull();
230
231	if(mSellToBuyer)
232	{
233		LLAvatarNameCache::get(mAuthorizedBuyer, 
234			boost::bind(&LLFloaterSellLandUI::onBuyerNameCache, this, _2));
235	}
236}
237
238void LLFloaterSellLandUI::onBuyerNameCache(const LLAvatarName& av_name)
239{
240	getChild<LLUICtrl>("sell_to_agent")->setValue(av_name.getCompleteName());
241	getChild<LLUICtrl>("sell_to_agent")->setToolTip(av_name.mUsername);
242}
243
244void LLFloaterSellLandUI::setBadge(const char* id, Badge badge)
245{
246	static std::string badgeOK("badge_ok.j2c");
247	static std::string badgeNote("badge_note.j2c");
248	static std::string badgeWarn("badge_warn.j2c");
249	static std::string badgeError("badge_error.j2c");
250	
251	std::string badgeName;
252	switch (badge)
253	{
254		default:
255		case BADGE_OK:		badgeName = badgeOK;	break;
256		case BADGE_NOTE:	badgeName = badgeNote;	break;
257		case BADGE_WARN:	badgeName = badgeWarn;	break;
258		case BADGE_ERROR:	badgeName = badgeError;	break;
259	}
260	
261	getChild<LLUICtrl>(id)->setValue(badgeName);
262}
263
264void LLFloaterSellLandUI::refreshUI()
265{
266	LLParcel* parcelp = mParcelSelection->getParcel();
267	if (!parcelp) return;
268
269	LLTextureCtrl* snapshot = getChild<LLTextureCtrl>("info_image");
270	snapshot->setImageAssetID(mParcelSnapshot);
271
272	getChild<LLUICtrl>("info_parcel")->setValue(parcelp->getName());
273	getChild<LLUICtrl>("info_size")->setTextArg("[AREA]", llformat("%d", mParcelActualArea));
274
275	std::string price_str = getChild<LLUICtrl>("price")->getValue().asString();
276	bool valid_price = false;
277	valid_price = (price_str != "") && LLTextValidate::validateNonNegativeS32(utf8str_to_wstring(price_str));
278
279	if (valid_price && mParcelActualArea > 0)
280	{
281		F32 per_meter_price = 0;
282		per_meter_price = F32(mParcelPrice) / F32(mParcelActualArea);
283		getChild<LLUICtrl>("price_per_m")->setTextArg("[PER_METER]", llformat("%0.2f", per_meter_price));
284		getChildView("price_per_m")->setVisible(TRUE);
285
286		setBadge("step_price", BADGE_OK);
287	}
288	else
289	{
290		getChildView("price_per_m")->setVisible(FALSE);
291
292		if ("" == price_str)
293		{
294			setBadge("step_price", BADGE_NOTE);
295		}
296		else
297		{
298			setBadge("step_price", BADGE_ERROR);
299		}
300	}
301
302	if (mSellToBuyer)
303	{
304		getChild<LLUICtrl>("sell_to")->setValue("user");
305		getChildView("sell_to_agent")->setVisible(TRUE);
306		getChildView("sell_to_select_agent")->setVisible(TRUE);
307	}
308	else
309	{
310		if (mChoseSellTo)
311		{
312			getChild<LLUICtrl>("sell_to")->setValue("anyone");
313		}
314		else
315		{
316			getChild<LLUICtrl>("sell_to")->setValue("select");
317		}
318		getChildView("sell_to_agent")->setVisible(FALSE);
319		getChildView("sell_to_select_agent")->setVisible(FALSE);
320	}
321
322	// Must select Sell To: Anybody, or User (with a specified username)
323	std::string sell_to = getChild<LLUICtrl>("sell_to")->getValue().asString();
324	bool valid_sell_to = "select" != sell_to &&
325		("user" != sell_to || mAuthorizedBuyer.notNull());
326
327	if (!valid_sell_to)
328	{
329		setBadge("step_sell_to", BADGE_NOTE);
330	}
331	else
332	{
333		setBadge("step_sell_to", BADGE_OK);
334	}
335
336	bool valid_sell_objects = ("none" != getChild<LLUICtrl>("sell_objects")->getValue().asString());
337
338	if (!valid_sell_objects)
339	{
340		setBadge("step_sell_objects", BADGE_NOTE);
341	}
342	else
343	{
344		setBadge("step_sell_objects", BADGE_OK);
345	}
346
347	if (valid_sell_to && valid_price && valid_sell_objects)
348	{
349		getChildView("sell_btn")->setEnabled(TRUE);
350	}
351	else
352	{
353		getChildView("sell_btn")->setEnabled(FALSE);
354	}
355}
356
357// static
358void LLFloaterSellLandUI::onChangeValue(LLUICtrl *ctrl, void *userdata)
359{
360	LLFloaterSellLandUI *self = (LLFloaterSellLandUI *)userdata;
361
362	std::string sell_to = self->getChild<LLUICtrl>("sell_to")->getValue().asString();
363
364	if (sell_to == "user")
365	{
366		self->mChoseSellTo = true;
367		self->mSellToBuyer = true;
368		if (self->mAuthorizedBuyer.isNull())
369		{
370			self->doSelectAgent();
371		}
372	}
373	else if (sell_to == "anyone")
374	{
375		self->mChoseSellTo = true;
376		self->mSellToBuyer = false;
377	}
378
379	self->mParcelPrice = self->getChild<LLUICtrl>("price")->getValue();
380
381	if ("yes" == self->getChild<LLUICtrl>("sell_objects")->getValue().asString())
382	{
383		self->mParcelSoldWithObjects = true;
384	}
385	else
386	{
387		self->mParcelSoldWithObjects = false;
388	}
389
390	self->refreshUI();
391}
392
393void LLFloaterSellLandUI::doSelectAgent()
394{
395	// grandparent is a floater, in order to set up dependency
396	addDependentFloater(LLFloaterAvatarPicker::show(boost::bind(&LLFloaterSellLandUI::callbackAvatarPick, this, _1, _2), FALSE, TRUE));
397}
398
399void LLFloaterSellLandUI::callbackAvatarPick(const uuid_vec_t& ids, const std::vector<LLAvatarName> names)
400{	
401	LLParcel* parcel = mParcelSelection->getParcel();
402
403	if (names.empty() || ids.empty()) return;
404	
405	LLUUID id = ids[0];
406	parcel->setAuthorizedBuyerID(id);
407
408	mAuthorizedBuyer = ids[0];
409
410	getChild<LLUICtrl>("sell_to_agent")->setValue(names[0].getCompleteName());
411
412	refreshUI();
413}
414
415// static
416void LLFloaterSellLandUI::doCancel(void *userdata)
417{
418	LLFloaterSellLandUI* self = (LLFloaterSellLandUI*)userdata;
419	self->closeFloater();
420}
421
422// static
423void LLFloaterSellLandUI::doShowObjects(void *userdata)
424{
425	LLFloaterSellLandUI* self = (LLFloaterSellLandUI*)userdata;
426	LLParcel* parcel = self->mParcelSelection->getParcel();
427	if (!parcel) return;
428
429	send_parcel_select_objects(parcel->getLocalID(), RT_SELL);
430
431	// we shouldn't pass callback functor since it is registered in LLFunctorRegistration
432	LLNotificationsUtil::add("TransferObjectsHighlighted",
433						LLSD(), LLSD());
434}
435
436static LLNotificationFunctorRegistration tr("TransferObjectsHighlighted", &LLFloaterSellLandUI::callbackHighlightTransferable);
437
438// static
439bool LLFloaterSellLandUI::callbackHighlightTransferable(const LLSD& notification, const LLSD& data)
440{
441	LLSelectMgr::getInstance()->unhighlightAll();
442	return false;
443}
444
445// static
446void LLFloaterSellLandUI::doSellLand(void *userdata)
447{
448	LLFloaterSellLandUI* self = (LLFloaterSellLandUI*)userdata;
449
450	LLParcel* parcel = self->mParcelSelection->getParcel();
451
452	// Do a confirmation
453	S32 sale_price = self->getChild<LLUICtrl>("price")->getValue();
454	S32 area = parcel->getArea();
455	std::string authorizedBuyerName = LLTrans::getString("Anyone");
456	bool sell_to_anyone = true;
457	if ("user" == self->getChild<LLUICtrl>("sell_to")->getValue().asString())
458	{
459		authorizedBuyerName = self->getChild<LLUICtrl>("sell_to_agent")->getValue().asString();
460		sell_to_anyone = false;
461	}
462
463	// must sell to someone if indicating sale to anyone
464	if (!parcel->getForSale() 
465		&& (sale_price == 0) 
466		&& sell_to_anyone)
467	{
468		LLNotificationsUtil::add("SalePriceRestriction");
469		return;
470	}
471
472	LLSD args;
473	args["LAND_SIZE"] = llformat("%d",area);
474	args["SALE_PRICE"] = llformat("%d",sale_price);
475	args["NAME"] = authorizedBuyerName;
476
477	LLNotification::Params params("ConfirmLandSaleChange");
478	params.substitutions(args)
479		.functor.function(boost::bind(&LLFloaterSellLandUI::onConfirmSale, self, _1, _2));
480
481	if (sell_to_anyone)
482	{
483		params.name("ConfirmLandSaleToAnyoneChange");
484	}
485	
486	if (parcel->getForSale())
487	{
488		// parcel already for sale, so ignore this question
489		LLNotifications::instance().forceResponse(params, -1);
490	}
491	else
492	{
493		// ask away
494		LLNotifications::instance().add(params);
495	}
496
497}
498
499bool LLFloaterSellLandUI::onConfirmSale(const LLSD& notification, const LLSD& response)
500{
501	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
502	if (option != 0)
503	{
504		return false;
505	}
506	S32  sale_price	= getChild<LLUICtrl>("price")->getValue();
507
508	// Valid extracted data
509	if (sale_price < 0)
510	{
511		// TomY TODO: Throw an error
512		return false;
513	}
514
515	LLParcel* parcel = mParcelSelection->getParcel();
516	if (!parcel) return false;
517
518	// can_agent_modify_parcel deprecated by GROUPS
519// 	if (!can_agent_modify_parcel(parcel))
520// 	{
521// 		close();
522// 		return;
523// 	}
524
525	parcel->setParcelFlag(PF_FOR_SALE, TRUE);
526	parcel->setSalePrice(sale_price);
527	bool sell_with_objects = false;
528	if ("yes" == getChild<LLUICtrl>("sell_objects")->getValue().asString())
529	{
530		sell_with_objects = true;
531	}
532	parcel->setSellWithObjects(sell_with_objects);
533	if ("user" == getChild<LLUICtrl>("sell_to")->getValue().asString())
534	{
535		parcel->setAuthorizedBuyerID(mAuthorizedBuyer);
536	}
537	else
538	{
539		parcel->setAuthorizedBuyerID(LLUUID::null);
540	}
541
542	// Send update to server
543	LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel );
544
545	closeFloater();
546	return false;
547}