/indra/newview/llfloaterbuycontents.cpp
C++ | 297 lines | 182 code | 55 blank | 60 comment | 26 complexity | e3d27db4bcd9a84b009292d4b62b3f0f MD5 | raw file
Possible License(s): LGPL-2.1
1/**
2 * @file llfloaterbuycontents.cpp
3 * @author James Cook
4 * @brief LLFloaterBuyContents class implementation
5 *
6 * $LicenseInfo:firstyear=2004&license=viewerlgpl$
7 * Second Life Viewer Source Code
8 * Copyright (C) 2010, Linden Research, Inc.
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation;
13 * version 2.1 of the License only.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 *
24 * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
25 * $/LicenseInfo$
26 */
27
28/**
29 * Shows the contents of an object and their permissions when you
30 * click "Buy..." on an object with "Sell Contents" checked.
31 */
32
33#include "llviewerprecompiledheaders.h"
34
35#include "llfloaterbuycontents.h"
36
37#include "llcachename.h"
38
39#include "llagent.h" // for agent id
40#include "llcheckboxctrl.h"
41#include "llinventorydefines.h"
42#include "llinventoryfunctions.h"
43#include "llinventorymodel.h" // for gInventory
44#include "llfirstuse.h"
45#include "llfloaterreg.h"
46#include "llfloaterinventory.h" // for LLInventoryIcon::getIcon
47#include "llnotificationsutil.h"
48#include "llselectmgr.h"
49#include "llscrolllistctrl.h"
50#include "llviewerobject.h"
51#include "llviewerregion.h"
52#include "lluictrlfactory.h"
53#include "llviewerwindow.h"
54
55LLFloaterBuyContents::LLFloaterBuyContents(const LLSD& key)
56: LLFloater(key)
57{
58}
59
60BOOL LLFloaterBuyContents::postBuild()
61{
62
63 getChild<LLUICtrl>("cancel_btn")->setCommitCallback( boost::bind(&LLFloaterBuyContents::onClickCancel, this));
64 getChild<LLUICtrl>("buy_btn")->setCommitCallback( boost::bind(&LLFloaterBuyContents::onClickBuy, this));
65
66 getChildView("item_list")->setEnabled(FALSE);
67 getChildView("buy_btn")->setEnabled(FALSE);
68 getChildView("wear_check")->setEnabled(FALSE);
69
70 setDefaultBtn("cancel_btn"); // to avoid accidental buy (SL-43130)
71
72 // Always center the dialog. User can change the size,
73 // but purchases are important and should be center screen.
74 // This also avoids problems where the user resizes the application window
75 // mid-session and the saved rect is off-center.
76 center();
77
78 return TRUE;
79}
80
81LLFloaterBuyContents::~LLFloaterBuyContents()
82{
83}
84
85
86// static
87void LLFloaterBuyContents::show(const LLSaleInfo& sale_info)
88{
89 LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
90
91 if (selection->getRootObjectCount() != 1)
92 {
93 LLNotificationsUtil::add("BuyContentsOneOnly");
94 return;
95 }
96
97 LLFloaterBuyContents* floater = LLFloaterReg::showTypedInstance<LLFloaterBuyContents>("buy_object_contents");
98 if (!floater)
99 return;
100
101 LLScrollListCtrl* list = floater->getChild<LLScrollListCtrl>("item_list");
102 if (list)
103 list->deleteAllItems();
104
105 floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
106
107 LLUUID owner_id;
108 std::string owner_name;
109 BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name);
110 if (!owners_identical)
111 {
112 LLNotificationsUtil::add("BuyContentsOneOwner");
113 return;
114 }
115
116 floater->mSaleInfo = sale_info;
117
118 // Update the display
119 LLSelectNode* node = selection->getFirstRootNode();
120 if (!node) return;
121 if(node->mPermissions->isGroupOwned())
122 {
123 gCacheName->getGroupName(owner_id, owner_name);
124 }
125
126 floater->getChild<LLUICtrl>("contains_text")->setTextArg("[NAME]", node->mName);
127 floater->getChild<LLUICtrl>("buy_text")->setTextArg("[AMOUNT]", llformat("%d", sale_info.getSalePrice()));
128 floater->getChild<LLUICtrl>("buy_text")->setTextArg("[NAME]", owner_name);
129
130 // Must do this after the floater is created, because
131 // sometimes the inventory is already there and
132 // the callback is called immediately.
133 LLViewerObject* obj = selection->getFirstRootObject();
134 floater->registerVOInventoryListener(obj,NULL);
135 floater->requestVOInventory();
136}
137
138
139void LLFloaterBuyContents::inventoryChanged(LLViewerObject* obj,
140 LLInventoryObject::object_list_t* inv,
141 S32 serial_num,
142 void* data)
143{
144 if (!obj)
145 {
146 llwarns << "No object in LLFloaterBuyContents::inventoryChanged" << llendl;
147 return;
148 }
149
150 if (!inv)
151 {
152 llwarns << "No inventory in LLFloaterBuyContents::inventoryChanged"
153 << llendl;
154 removeVOInventoryListener();
155 return;
156 }
157
158 LLCtrlListInterface *item_list = childGetListInterface("item_list");
159 if (!item_list)
160 {
161 removeVOInventoryListener();
162 return;
163 }
164
165 // default to turning off the buy button.
166 getChildView("buy_btn")->setEnabled(FALSE);
167
168 LLUUID owner_id;
169 BOOL is_group_owned;
170 LLAssetType::EType asset_type;
171 LLInventoryType::EType inv_type;
172 S32 wearable_count = 0;
173
174 LLInventoryObject::object_list_t::const_iterator it = inv->begin();
175 LLInventoryObject::object_list_t::const_iterator end = inv->end();
176
177 for ( ; it != end; ++it )
178 {
179 asset_type = (*it)->getType();
180
181 // Skip folders, so we know we have inventory items only
182 if (asset_type == LLAssetType::AT_CATEGORY)
183 continue;
184
185 LLInventoryItem* inv_item = (LLInventoryItem*)((LLInventoryObject*)(*it));
186 inv_type = inv_item->getInventoryType();
187
188 // Count clothing items for later
189 if (LLInventoryType::IT_WEARABLE == inv_type)
190 {
191 wearable_count++;
192 }
193
194 // Skip items the object's owner can't copy (and hence can't sell)
195 if (!inv_item->getPermissions().getOwnership(owner_id, is_group_owned))
196 continue;
197
198 if (!inv_item->getPermissions().allowCopyBy(owner_id, owner_id))
199 continue;
200
201 // Skip items we can't transfer
202 if (!inv_item->getPermissions().allowTransferTo(gAgent.getID()))
203 continue;
204
205 // There will be at least one item shown in the display, so go
206 // ahead and enable the buy button.
207 getChildView("buy_btn")->setEnabled(TRUE);
208
209 // Create the line in the list
210 LLSD row;
211
212 BOOL item_is_multi = FALSE;
213 if ( inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_LANDMARK_VISITED )
214 {
215 item_is_multi = TRUE;
216 }
217
218 std::string icon_name = LLInventoryIcon::getIconName(inv_item->getType(),
219 inv_item->getInventoryType(),
220 inv_item->getFlags(),
221 item_is_multi);
222 row["columns"][0]["column"] = "icon";
223 row["columns"][0]["type"] = "icon";
224 row["columns"][0]["value"] = icon_name;
225
226 // Append the permissions that you will acquire (not the current
227 // permissions).
228 U32 next_owner_mask = inv_item->getPermissions().getMaskNextOwner();
229 std::string text = (*it)->getName();
230
231 if (!(next_owner_mask & PERM_COPY))
232 {
233 text.append(getString("no_copy_text"));
234 }
235 if (!(next_owner_mask & PERM_MODIFY))
236 {
237 text.append(getString("no_modify_text"));
238 }
239 if (!(next_owner_mask & PERM_TRANSFER))
240 {
241 text.append(getString("no_transfer_text"));
242 }
243
244 row["columns"][1]["column"] = "text";
245 row["columns"][1]["value"] = text;
246 row["columns"][1]["font"] = "SANSSERIF";
247
248 item_list->addElement(row);
249 }
250
251 if (wearable_count > 0)
252 {
253 getChildView("wear_check")->setEnabled(TRUE);
254 getChild<LLUICtrl>("wear_check")->setValue(LLSD(false) );
255 }
256
257 removeVOInventoryListener();
258}
259
260
261void LLFloaterBuyContents::onClickBuy()
262{
263 // Make sure this wasn't selected through other mechanisms
264 // (ie, being the default button and pressing enter.
265 if(!getChildView("buy_btn")->getEnabled())
266 {
267 // We shouldn't be enabled. Just close.
268 closeFloater();
269 return;
270 }
271
272 // We may want to wear this item
273 if (getChild<LLUICtrl>("wear_check")->getValue())
274 {
275 LLInventoryState::sWearNewClothing = TRUE;
276 }
277
278 // Put the items where we put new folders.
279 LLUUID category_id;
280 category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_ROOT_INVENTORY);
281
282 // *NOTE: doesn't work for multiple object buy, which UI does not
283 // currently support sale info is used for verification only, if
284 // it doesn't match region info then sale is canceled.
285 LLSelectMgr::getInstance()->sendBuy(gAgent.getID(), category_id, mSaleInfo);
286
287 // NOTE: do this here instead of on receipt of object, since contents are transfered
288 // via a generic BulkUpdateInventory message with no way of distinguishing it from
289 // other inventory operations
290 LLFirstUse::newInventory();
291 closeFloater();
292}
293
294void LLFloaterBuyContents::onClickCancel()
295{
296 closeFloater();
297}