diff options
author | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
---|---|---|
committer | Jacek Antonelli | 2008-08-15 23:44:46 -0500 |
commit | 38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch) | |
tree | adca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llinventoryview.cpp | |
parent | README.txt (diff) | |
download | meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2 meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz |
Second Life viewer sources 1.13.2.12
Diffstat (limited to 'linden/indra/newview/llinventoryview.cpp')
-rw-r--r-- | linden/indra/newview/llinventoryview.cpp | 1602 |
1 files changed, 1602 insertions, 0 deletions
diff --git a/linden/indra/newview/llinventoryview.cpp b/linden/indra/newview/llinventoryview.cpp new file mode 100644 index 0000000..9eb33ee --- /dev/null +++ b/linden/indra/newview/llinventoryview.cpp | |||
@@ -0,0 +1,1602 @@ | |||
1 | /** | ||
2 | * @file llinventoryview.cpp | ||
3 | * @brief Implementation of the inventory view and associated stuff. | ||
4 | * | ||
5 | * Copyright (c) 2001-2007, Linden Research, Inc. | ||
6 | * | ||
7 | * The source code in this file ("Source Code") is provided by Linden Lab | ||
8 | * to you under the terms of the GNU General Public License, version 2.0 | ||
9 | * ("GPL"), unless you have obtained a separate licensing agreement | ||
10 | * ("Other License"), formally executed by you and Linden Lab. Terms of | ||
11 | * the GPL can be found in doc/GPL-license.txt in this distribution, or | ||
12 | * online at http://secondlife.com/developers/opensource/gplv2 | ||
13 | * | ||
14 | * There are special exceptions to the terms and conditions of the GPL as | ||
15 | * it is applied to this Source Code. View the full text of the exception | ||
16 | * in the file doc/FLOSS-exception.txt in this software distribution, or | ||
17 | * online at http://secondlife.com/developers/opensource/flossexception | ||
18 | * | ||
19 | * By copying, modifying or distributing this software, you acknowledge | ||
20 | * that you have read and understood your obligations described above, | ||
21 | * and agree to abide by those obligations. | ||
22 | * | ||
23 | * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO | ||
24 | * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, | ||
25 | * COMPLETENESS OR PERFORMANCE. | ||
26 | */ | ||
27 | |||
28 | #include "llviewerprecompiledheaders.h" | ||
29 | |||
30 | #include <utility> // for std::pair<> | ||
31 | |||
32 | #include "llinventoryview.h" | ||
33 | #include "llinventorybridge.h" | ||
34 | |||
35 | #include "message.h" | ||
36 | |||
37 | #include "llagent.h" | ||
38 | #include "llcallingcard.h" | ||
39 | #include "llcheckboxctrl.h" // for radio buttons | ||
40 | #include "llradiogroup.h" | ||
41 | #include "llspinctrl.h" | ||
42 | #include "lltextbox.h" | ||
43 | #include "llui.h" | ||
44 | |||
45 | #include "llfirstuse.h" | ||
46 | #include "llfloateravatarinfo.h" | ||
47 | #include "llfloaterchat.h" | ||
48 | #include "llfloatercustomize.h" | ||
49 | #include "llfocusmgr.h" | ||
50 | #include "llfolderview.h" | ||
51 | #include "llgesturemgr.h" | ||
52 | #include "lliconctrl.h" | ||
53 | #include "llinventorymodel.h" | ||
54 | #include "llinventoryclipboard.h" | ||
55 | #include "lllineeditor.h" | ||
56 | #include "llmenugl.h" | ||
57 | #include "llpreviewanim.h" | ||
58 | #include "llpreviewgesture.h" | ||
59 | #include "llpreviewlandmark.h" | ||
60 | #include "llpreviewnotecard.h" | ||
61 | #include "llpreviewscript.h" | ||
62 | #include "llpreviewsound.h" | ||
63 | #include "llpreviewtexture.h" | ||
64 | #include "llresmgr.h" | ||
65 | #include "llscrollcontainer.h" | ||
66 | #include "llimview.h" | ||
67 | #include "lltooldraganddrop.h" | ||
68 | #include "llviewerimagelist.h" | ||
69 | #include "llviewerinventory.h" | ||
70 | #include "llviewerobjectlist.h" | ||
71 | #include "llviewerwindow.h" | ||
72 | #include "llwearablelist.h" | ||
73 | #include "viewer.h" | ||
74 | #include "llviewermessage.h" | ||
75 | #include "llviewerregion.h" | ||
76 | #include "lltabcontainer.h" | ||
77 | #include "llvieweruictrlfactory.h" | ||
78 | #include "llselectmgr.h" | ||
79 | |||
80 | LLDynamicArray<LLInventoryView*> LLInventoryView::sActiveViews; | ||
81 | |||
82 | //BOOL LLInventoryView::sOpenNextNewItem = FALSE; | ||
83 | BOOL LLInventoryView::sWearNewClothing = FALSE; | ||
84 | LLUUID LLInventoryView::sWearNewClothingTransactionID; | ||
85 | |||
86 | ///---------------------------------------------------------------------------- | ||
87 | /// Local function declarations, constants, enums, and typedefs | ||
88 | ///---------------------------------------------------------------------------- | ||
89 | |||
90 | const S32 INV_MIN_WIDTH = 240; | ||
91 | const S32 INV_MIN_HEIGHT = 150; | ||
92 | const S32 INV_FINDER_WIDTH = 160; | ||
93 | const S32 INV_FINDER_HEIGHT = 408; | ||
94 | |||
95 | ///---------------------------------------------------------------------------- | ||
96 | /// LLInventoryViewFinder | ||
97 | ///---------------------------------------------------------------------------- | ||
98 | |||
99 | LLInventoryViewFinder::LLInventoryViewFinder(const LLString& name, | ||
100 | const LLRect& rect, | ||
101 | LLInventoryView* inventory_view) : | ||
102 | LLFloater(name, rect, "Filters", RESIZE_NO, | ||
103 | INV_FINDER_WIDTH, INV_FINDER_HEIGHT, DRAG_ON_TOP, | ||
104 | MINIMIZE_NO, CLOSE_YES), | ||
105 | mInventoryView(inventory_view), | ||
106 | mFilter(inventory_view->mActivePanel->getFilter()) | ||
107 | { | ||
108 | |||
109 | gUICtrlFactory->buildFloater(this, "floater_inventory_view_finder.xml"); | ||
110 | |||
111 | childSetAction("All", selectAllTypes, this); | ||
112 | childSetAction("None", selectNoTypes, this); | ||
113 | |||
114 | mSpinSinceHours = LLUICtrlFactory::getSpinnerByName(this, "spin_hours_ago"); | ||
115 | childSetCommitCallback("spin_hours_ago", onTimeAgo, this); | ||
116 | |||
117 | mSpinSinceDays = LLUICtrlFactory::getSpinnerByName(this, "spin_days_ago"); | ||
118 | childSetCommitCallback("spin_days_ago", onTimeAgo, this); | ||
119 | |||
120 | childSetAction("Close", onCloseBtn, this); | ||
121 | |||
122 | updateElementsFromFilter(); | ||
123 | } | ||
124 | |||
125 | void LLInventoryViewFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data) | ||
126 | { | ||
127 | LLInventoryViewFinder *self = (LLInventoryViewFinder *)user_data; | ||
128 | if (!self) return; | ||
129 | |||
130 | self->childSetValue("check_since_logoff", FALSE); | ||
131 | } | ||
132 | |||
133 | void LLInventoryViewFinder::changeFilter(LLInventoryFilter* filter) | ||
134 | { | ||
135 | mFilter = filter; | ||
136 | updateElementsFromFilter(); | ||
137 | } | ||
138 | |||
139 | void LLInventoryViewFinder::updateElementsFromFilter() | ||
140 | { | ||
141 | if (!mFilter) | ||
142 | return; | ||
143 | |||
144 | // Get data needed for filter display | ||
145 | U32 filter_types = mFilter->getFilterTypes(); | ||
146 | LLString filter_string = mFilter->getFilterSubString(); | ||
147 | LLInventoryFilter::EFolderShow show_folders = mFilter->getShowFolderState(); | ||
148 | U32 hours = mFilter->getHoursAgo(); | ||
149 | |||
150 | // update the ui elements | ||
151 | LLFloater::setTitle(mFilter->getName()); | ||
152 | childSetValue("check_animation", (S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION)); | ||
153 | |||
154 | childSetValue("check_calling_card", (S32) (filter_types & 0x1 << LLInventoryType::IT_CALLINGCARD)); | ||
155 | childSetValue("check_clothing", (S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE)); | ||
156 | childSetValue("check_gesture", (S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE)); | ||
157 | childSetValue("check_landmark", (S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK)); | ||
158 | childSetValue("check_notecard", (S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD)); | ||
159 | childSetValue("check_object", (S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT)); | ||
160 | childSetValue("check_script", (S32) (filter_types & 0x1 << LLInventoryType::IT_LSL)); | ||
161 | childSetValue("check_sound", (S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND)); | ||
162 | childSetValue("check_texture", (S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE)); | ||
163 | childSetValue("check_snapshot", (S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT)); | ||
164 | childSetValue("check_show_empty", show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS); | ||
165 | childSetValue("check_since_logoff", mFilter->isSinceLogoff()); | ||
166 | mSpinSinceHours->set((F32)(hours % 24)); | ||
167 | mSpinSinceDays->set((F32)(hours / 24)); | ||
168 | } | ||
169 | |||
170 | void LLInventoryViewFinder::draw() | ||
171 | { | ||
172 | U32 filter = 0xffffffff; | ||
173 | BOOL filtered_by_all_types = TRUE; | ||
174 | |||
175 | if (!childGetValue("check_animation")) | ||
176 | { | ||
177 | filter &= ~(0x1 << LLInventoryType::IT_ANIMATION); | ||
178 | filtered_by_all_types = FALSE; | ||
179 | } | ||
180 | |||
181 | |||
182 | if (!childGetValue("check_calling_card")) | ||
183 | { | ||
184 | filter &= ~(0x1 << LLInventoryType::IT_CALLINGCARD); | ||
185 | filtered_by_all_types = FALSE; | ||
186 | } | ||
187 | |||
188 | if (!childGetValue("check_clothing")) | ||
189 | { | ||
190 | filter &= ~(0x1 << LLInventoryType::IT_WEARABLE); | ||
191 | filtered_by_all_types = FALSE; | ||
192 | } | ||
193 | |||
194 | if (!childGetValue("check_gesture")) | ||
195 | { | ||
196 | filter &= ~(0x1 << LLInventoryType::IT_GESTURE); | ||
197 | filtered_by_all_types = FALSE; | ||
198 | } | ||
199 | |||
200 | if (!childGetValue("check_landmark")) | ||
201 | |||
202 | |||
203 | { | ||
204 | filter &= ~(0x1 << LLInventoryType::IT_LANDMARK); | ||
205 | filtered_by_all_types = FALSE; | ||
206 | } | ||
207 | |||
208 | if (!childGetValue("check_notecard")) | ||
209 | { | ||
210 | filter &= ~(0x1 << LLInventoryType::IT_NOTECARD); | ||
211 | filtered_by_all_types = FALSE; | ||
212 | } | ||
213 | |||
214 | if (!childGetValue("check_object")) | ||
215 | { | ||
216 | filter &= ~(0x1 << LLInventoryType::IT_OBJECT); | ||
217 | filter &= ~(0x1 << LLInventoryType::IT_ATTACHMENT); | ||
218 | filtered_by_all_types = FALSE; | ||
219 | } | ||
220 | |||
221 | if (!childGetValue("check_script")) | ||
222 | { | ||
223 | filter &= ~(0x1 << LLInventoryType::IT_LSL); | ||
224 | filtered_by_all_types = FALSE; | ||
225 | } | ||
226 | |||
227 | if (!childGetValue("check_sound")) | ||
228 | { | ||
229 | filter &= ~(0x1 << LLInventoryType::IT_SOUND); | ||
230 | filtered_by_all_types = FALSE; | ||
231 | } | ||
232 | |||
233 | if (!childGetValue("check_texture")) | ||
234 | { | ||
235 | filter &= ~(0x1 << LLInventoryType::IT_TEXTURE); | ||
236 | filtered_by_all_types = FALSE; | ||
237 | } | ||
238 | |||
239 | if (!childGetValue("check_snapshot")) | ||
240 | { | ||
241 | filter &= ~(0x1 << LLInventoryType::IT_SNAPSHOT); | ||
242 | filtered_by_all_types = FALSE; | ||
243 | } | ||
244 | |||
245 | if (!filtered_by_all_types) | ||
246 | { | ||
247 | // don't include folders in filter, unless I've selected everything | ||
248 | filter &= ~(0x1 << LLInventoryType::IT_CATEGORY); | ||
249 | } | ||
250 | |||
251 | // update the panel, panel will update the filter | ||
252 | mInventoryView->mActivePanel->setShowFolderState(getCheckShowEmpty() ? | ||
253 | LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); | ||
254 | mInventoryView->mActivePanel->setFilterTypes(filter); | ||
255 | if (getCheckSinceLogoff()) | ||
256 | { | ||
257 | mSpinSinceDays->set(0); | ||
258 | mSpinSinceHours->set(0); | ||
259 | } | ||
260 | U32 days = (U32)mSpinSinceDays->get(); | ||
261 | U32 hours = (U32)mSpinSinceHours->get(); | ||
262 | if (hours > 24) | ||
263 | { | ||
264 | days += hours / 24; | ||
265 | hours = (U32)hours % 24; | ||
266 | mSpinSinceDays->set((F32)days); | ||
267 | mSpinSinceHours->set((F32)hours); | ||
268 | } | ||
269 | hours += days * 24; | ||
270 | mInventoryView->mActivePanel->setHoursAgo(hours); | ||
271 | mInventoryView->mActivePanel->setSinceLogoff(getCheckSinceLogoff()); | ||
272 | mInventoryView->setFilterTextFromFilter(); | ||
273 | |||
274 | LLFloater::draw(); | ||
275 | } | ||
276 | |||
277 | void LLInventoryViewFinder::onClose(bool app_quitting) | ||
278 | { | ||
279 | if (mInventoryView) mInventoryView->getControl("Inventory.ShowFilters")->setValue(FALSE); | ||
280 | // If you want to reset the filter on close, do it here. This functionality was | ||
281 | // hotly debated - Paulm | ||
282 | #if 0 | ||
283 | if (mInventoryView) | ||
284 | { | ||
285 | LLInventoryView::onResetFilter((void *)mInventoryView); | ||
286 | } | ||
287 | #endif | ||
288 | destroy(); | ||
289 | } | ||
290 | |||
291 | |||
292 | BOOL LLInventoryViewFinder::getCheckShowEmpty() | ||
293 | { | ||
294 | return childGetValue("check_show_empty"); | ||
295 | } | ||
296 | |||
297 | BOOL LLInventoryViewFinder::getCheckSinceLogoff() | ||
298 | { | ||
299 | return childGetValue("check_since_logoff"); | ||
300 | } | ||
301 | |||
302 | void LLInventoryViewFinder::onCloseBtn(void* user_data) | ||
303 | { | ||
304 | LLInventoryViewFinder* finderp = (LLInventoryViewFinder*)user_data; | ||
305 | finderp->close(); | ||
306 | } | ||
307 | |||
308 | // static | ||
309 | void LLInventoryViewFinder::selectAllTypes(void* user_data) | ||
310 | { | ||
311 | LLInventoryViewFinder* self = (LLInventoryViewFinder*)user_data; | ||
312 | if(!self) return; | ||
313 | |||
314 | self->childSetValue("check_animation", TRUE); | ||
315 | self->childSetValue("check_calling_card", TRUE); | ||
316 | self->childSetValue("check_clothing", TRUE); | ||
317 | self->childSetValue("check_gesture", TRUE); | ||
318 | self->childSetValue("check_landmark", TRUE); | ||
319 | self->childSetValue("check_notecard", TRUE); | ||
320 | self->childSetValue("check_object", TRUE); | ||
321 | self->childSetValue("check_script", TRUE); | ||
322 | self->childSetValue("check_sound", TRUE); | ||
323 | self->childSetValue("check_texture", TRUE); | ||
324 | self->childSetValue("check_snapshot", TRUE); | ||
325 | |||
326 | /* | ||
327 | self->mCheckCallingCard->set(TRUE); | ||
328 | self->mCheckClothing->set(TRUE); | ||
329 | self->mCheckGesture->set(TRUE); | ||
330 | self->mCheckLandmark->set(TRUE); | ||
331 | self->mCheckNotecard->set(TRUE); | ||
332 | self->mCheckObject->set(TRUE); | ||
333 | self->mCheckScript->set(TRUE); | ||
334 | self->mCheckSound->set(TRUE); | ||
335 | self->mCheckTexture->set(TRUE); | ||
336 | self->mCheckSnapshot->set(TRUE);*/ | ||
337 | } | ||
338 | |||
339 | //static | ||
340 | void LLInventoryViewFinder::selectNoTypes(void* user_data) | ||
341 | { | ||
342 | LLInventoryViewFinder* self = (LLInventoryViewFinder*)user_data; | ||
343 | if(!self) return; | ||
344 | |||
345 | /* | ||
346 | self->childSetValue("check_animation", FALSE); | ||
347 | self->mCheckCallingCard->set(FALSE); | ||
348 | self->mCheckClothing->set(FALSE); | ||
349 | self->mCheckGesture->set(FALSE); | ||
350 | self->mCheckLandmark->set(FALSE); | ||
351 | self->mCheckNotecard->set(FALSE); | ||
352 | self->mCheckObject->set(FALSE); | ||
353 | self->mCheckScript->set(FALSE); | ||
354 | self->mCheckSound->set(FALSE); | ||
355 | self->mCheckTexture->set(FALSE); | ||
356 | self->mCheckSnapshot->set(FALSE);*/ | ||
357 | |||
358 | |||
359 | self->childSetValue("check_animation", FALSE); | ||
360 | self->childSetValue("check_calling_card", FALSE); | ||
361 | self->childSetValue("check_clothing", FALSE); | ||
362 | self->childSetValue("check_gesture", FALSE); | ||
363 | self->childSetValue("check_landmark", FALSE); | ||
364 | self->childSetValue("check_notecard", FALSE); | ||
365 | self->childSetValue("check_object", FALSE); | ||
366 | self->childSetValue("check_script", FALSE); | ||
367 | self->childSetValue("check_sound", FALSE); | ||
368 | self->childSetValue("check_texture", FALSE); | ||
369 | self->childSetValue("check_snapshot", FALSE); | ||
370 | } | ||
371 | |||
372 | |||
373 | ///---------------------------------------------------------------------------- | ||
374 | /// LLInventoryView | ||
375 | ///---------------------------------------------------------------------------- | ||
376 | class LLSaveFolderState : public LLFolderViewFunctor | ||
377 | { | ||
378 | public: | ||
379 | LLSaveFolderState() : mApply(FALSE) {} | ||
380 | virtual ~LLSaveFolderState() {} | ||
381 | virtual void doFolder(LLFolderViewFolder* folder); | ||
382 | virtual void doItem(LLFolderViewItem* item) {} | ||
383 | void setApply(BOOL apply) { mApply = apply; } | ||
384 | void clearOpenFolders() { mOpenFolders.clear(); } | ||
385 | protected: | ||
386 | std::set<LLUUID> mOpenFolders; | ||
387 | BOOL mApply; | ||
388 | }; | ||
389 | |||
390 | void LLSaveFolderState::doFolder(LLFolderViewFolder* folder) | ||
391 | { | ||
392 | if(mApply) | ||
393 | { | ||
394 | // we're applying the open state | ||
395 | LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); | ||
396 | if(!bridge) return; | ||
397 | LLUUID id(bridge->getUUID()); | ||
398 | if(mOpenFolders.find(id) != mOpenFolders.end()) | ||
399 | { | ||
400 | folder->setOpen(TRUE); | ||
401 | } | ||
402 | else | ||
403 | { | ||
404 | // keep selected filter in its current state, this is less jarring to user | ||
405 | if (!folder->isSelected()) | ||
406 | { | ||
407 | folder->setOpen(FALSE); | ||
408 | } | ||
409 | } | ||
410 | } | ||
411 | else | ||
412 | { | ||
413 | // we're recording state at this point | ||
414 | if(folder->isOpen()) | ||
415 | { | ||
416 | LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); | ||
417 | if(!bridge) return; | ||
418 | mOpenFolders.insert(bridge->getUUID()); | ||
419 | } | ||
420 | } | ||
421 | } | ||
422 | |||
423 | // Default constructor | ||
424 | LLInventoryView::LLInventoryView(const LLString& name, | ||
425 | const LLString& rect, | ||
426 | LLInventoryModel* inventory) : | ||
427 | LLFloater(name, rect, "Inventory", RESIZE_YES, | ||
428 | INV_MIN_WIDTH, INV_MIN_HEIGHT, DRAG_ON_TOP, | ||
429 | MINIMIZE_NO, CLOSE_YES) | ||
430 | //LLViewHandle mFinderHandle takes care of its own initialization | ||
431 | { | ||
432 | init(inventory); | ||
433 | } | ||
434 | |||
435 | LLInventoryView::LLInventoryView(const LLString& name, | ||
436 | const LLRect& rect, | ||
437 | LLInventoryModel* inventory) : | ||
438 | LLFloater(name, rect, "Inventory", RESIZE_YES, | ||
439 | INV_MIN_WIDTH, INV_MIN_HEIGHT, DRAG_ON_TOP, | ||
440 | MINIMIZE_NO, CLOSE_YES) | ||
441 | //LLViewHandle mFinderHandle takes care of its own initialization | ||
442 | { | ||
443 | init(inventory); | ||
444 | setRect(rect); // override XML | ||
445 | } | ||
446 | |||
447 | |||
448 | void LLInventoryView::init(LLInventoryModel* inventory) | ||
449 | { | ||
450 | // Callbacks | ||
451 | init_inventory_actions(this); | ||
452 | |||
453 | // Controls | ||
454 | U32 sort_order = gSavedSettings.getU32("InventorySortOrder"); | ||
455 | BOOL sort_by_name = ! ( sort_order & LLInventoryFilter::SO_DATE ); | ||
456 | BOOL sort_folders_by_name = ( sort_order & LLInventoryFilter::SO_FOLDERS_BY_NAME ); | ||
457 | |||
458 | addBoolControl("Inventory.ShowFilters", FALSE); | ||
459 | addBoolControl("Inventory.SortByName", sort_by_name ); | ||
460 | addBoolControl("Inventory.SortByDate", ! sort_by_name ); | ||
461 | addBoolControl("Inventory.FoldersAlwaysByName", sort_folders_by_name ); | ||
462 | |||
463 | mSavedFolderState = new LLSaveFolderState(); | ||
464 | mSavedFolderState->setApply(FALSE); | ||
465 | |||
466 | gUICtrlFactory->buildFloater(this, "floater_inventory.xml", NULL); | ||
467 | |||
468 | mActivePanel = (LLInventoryPanel*)getCtrlByNameAndType("All Items", WIDGET_TYPE_INVENTORY_PANEL); | ||
469 | if (mActivePanel) | ||
470 | { | ||
471 | // "All Items" is the previous only view, so it gets the InventorySortOrder | ||
472 | mActivePanel->setSortOrder(gSavedSettings.getU32("InventorySortOrder")); | ||
473 | mActivePanel->getFilter()->markDefault(); | ||
474 | mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); | ||
475 | } | ||
476 | LLInventoryPanel* recent_items_panel = (LLInventoryPanel*)getCtrlByNameAndType("Recent Items", WIDGET_TYPE_INVENTORY_PANEL); | ||
477 | if (recent_items_panel) | ||
478 | { | ||
479 | recent_items_panel->setSinceLogoff(TRUE); | ||
480 | recent_items_panel->setSortOrder(LLInventoryFilter::SO_DATE); | ||
481 | recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); | ||
482 | recent_items_panel->getFilter()->markDefault(); | ||
483 | } | ||
484 | |||
485 | mSearchEditor = (LLSearchEditor*)getCtrlByNameAndType("inventory search editor", WIDGET_TYPE_SEARCH_EDITOR); | ||
486 | if (mSearchEditor) | ||
487 | { | ||
488 | mSearchEditor->setSearchCallback(onSearchEdit, this); | ||
489 | } | ||
490 | |||
491 | moveResizeHandleToFront(); | ||
492 | sActiveViews.put(this); | ||
493 | |||
494 | gInventory.addObserver(this); | ||
495 | } | ||
496 | |||
497 | BOOL LLInventoryView::postBuild() | ||
498 | { | ||
499 | childSetTabChangeCallback("inventory filter tabs", "All Items", onFilterSelected, this); | ||
500 | childSetTabChangeCallback("inventory filter tabs", "Recent Items", onFilterSelected, this); | ||
501 | //panel->getFilter()->markDefault(); | ||
502 | return TRUE; | ||
503 | } | ||
504 | |||
505 | // Destroys the object | ||
506 | LLInventoryView::~LLInventoryView( void ) | ||
507 | { | ||
508 | sActiveViews.removeObj(this); | ||
509 | gInventory.removeObserver(this); | ||
510 | delete mSavedFolderState; | ||
511 | } | ||
512 | |||
513 | void LLInventoryView::draw() | ||
514 | { | ||
515 | if (mActivePanel && mActivePanel->getNeedsAutoSelect()) | ||
516 | { | ||
517 | LLOpenFilteredFolders opener; | ||
518 | mActivePanel->getRootFolder()->applyFunctorRecursively(opener); | ||
519 | // select first filtered item | ||
520 | LLSelectFirstFilteredItem filter; | ||
521 | mActivePanel->getRootFolder()->applyFunctorRecursively(filter); | ||
522 | mActivePanel->getRootFolder()->scrollToShowSelection(); | ||
523 | mActivePanel->setNeedsAutoSelect(FALSE); | ||
524 | } | ||
525 | |||
526 | if (LLInventoryModel::isEverythingFetched()) | ||
527 | { | ||
528 | LLLocale locale(LLLocale::USER_LOCALE); | ||
529 | std::ostringstream title; | ||
530 | title << "Inventory"; | ||
531 | LLString item_count_string; | ||
532 | gResMgr->getIntegerString(item_count_string, gInventory.getItemCount()); | ||
533 | title << " (" << item_count_string << " items)"; | ||
534 | title << mFilterText; | ||
535 | setTitle(title.str()); | ||
536 | } | ||
537 | if (mActivePanel && mSearchEditor) | ||
538 | { | ||
539 | mSearchEditor->setText(mActivePanel->getFilterSubString()); | ||
540 | } | ||
541 | LLFloater::draw(); | ||
542 | } | ||
543 | |||
544 | void LLOpenFilteredFolders::doItem(LLFolderViewItem *item) | ||
545 | { | ||
546 | if (item->getFiltered()) | ||
547 | { | ||
548 | item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); | ||
549 | } | ||
550 | } | ||
551 | |||
552 | void LLOpenFilteredFolders::doFolder(LLFolderViewFolder* folder) | ||
553 | { | ||
554 | if (folder->getFiltered() && folder->getParentFolder()) | ||
555 | { | ||
556 | folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); | ||
557 | } | ||
558 | // if this folder didn't pass the filter, and none of its descendants did | ||
559 | else if (!folder->getFiltered() && !folder->hasFilteredDescendants()) | ||
560 | { | ||
561 | folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO); | ||
562 | } | ||
563 | } | ||
564 | |||
565 | void LLSelectFirstFilteredItem::doItem(LLFolderViewItem *item) | ||
566 | { | ||
567 | if (item->getFiltered() && !mItemSelected) | ||
568 | { | ||
569 | item->getRoot()->setSelection(item, FALSE, FALSE); | ||
570 | if (item->getParentFolder()) | ||
571 | { | ||
572 | item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); | ||
573 | } | ||
574 | item->getRoot()->scrollToShowSelection(); | ||
575 | mItemSelected = TRUE; | ||
576 | } | ||
577 | } | ||
578 | |||
579 | void LLSelectFirstFilteredItem::doFolder(LLFolderViewFolder* folder) | ||
580 | { | ||
581 | if (folder->getFiltered() && !mItemSelected) | ||
582 | { | ||
583 | folder->getRoot()->setSelection(folder, FALSE, FALSE); | ||
584 | if (folder->getParentFolder()) | ||
585 | { | ||
586 | folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); | ||
587 | } | ||
588 | folder->getRoot()->scrollToShowSelection(); | ||
589 | mItemSelected = TRUE; | ||
590 | } | ||
591 | } | ||
592 | |||
593 | class LLOpenFoldersWithSelection : public LLFolderViewFunctor | ||
594 | { | ||
595 | public: | ||
596 | LLOpenFoldersWithSelection() {} | ||
597 | virtual ~LLOpenFoldersWithSelection() {} | ||
598 | virtual void doFolder(LLFolderViewFolder* folder); | ||
599 | virtual void doItem(LLFolderViewItem* item); | ||
600 | }; | ||
601 | |||
602 | void LLOpenFoldersWithSelection::doItem(LLFolderViewItem *item) | ||
603 | { | ||
604 | if (item->getParentFolder() && item->isSelected()) | ||
605 | { | ||
606 | item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); | ||
607 | } | ||
608 | } | ||
609 | |||
610 | void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder) | ||
611 | { | ||
612 | if (folder->getParentFolder() && folder->isSelected()) | ||
613 | { | ||
614 | folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); | ||
615 | } | ||
616 | } | ||
617 | |||
618 | void LLInventoryView::startSearch() | ||
619 | { | ||
620 | // this forces focus to line editor portion of search editor | ||
621 | if (mSearchEditor) | ||
622 | { | ||
623 | mSearchEditor->focusFirstItem(TRUE); | ||
624 | } | ||
625 | } | ||
626 | |||
627 | // virtual, from LLView | ||
628 | void LLInventoryView::setVisible( BOOL visible ) | ||
629 | { | ||
630 | gSavedSettings.setBOOL("ShowInventory", visible); | ||
631 | LLFloater::setVisible(visible); | ||
632 | } | ||
633 | |||
634 | // Destroy all but the last floater, which is made invisible. | ||
635 | void LLInventoryView::onClose(bool app_quitting) | ||
636 | { | ||
637 | S32 count = sActiveViews.count(); | ||
638 | if (count > 1) | ||
639 | { | ||
640 | destroy(); | ||
641 | } | ||
642 | else | ||
643 | { | ||
644 | if (!app_quitting) | ||
645 | { | ||
646 | gSavedSettings.setBOOL("ShowInventory", FALSE); | ||
647 | } | ||
648 | // clear filters, but save user's folder state first | ||
649 | if (!mActivePanel->getRootFolder()->isFilterActive()) | ||
650 | { | ||
651 | mSavedFolderState->setApply(FALSE); | ||
652 | mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); | ||
653 | } | ||
654 | onClearSearch(this); | ||
655 | // pass up | ||
656 | LLFloater::setVisible(FALSE); | ||
657 | } | ||
658 | } | ||
659 | |||
660 | BOOL LLInventoryView::handleKeyHere(KEY key, MASK mask, BOOL called_from_parent) | ||
661 | { | ||
662 | LLFolderView* root_folder = mActivePanel ? mActivePanel->getRootFolder() : NULL; | ||
663 | // first check for user accepting current search results | ||
664 | if (!called_from_parent && root_folder&& | ||
665 | mSearchEditor && mSearchEditor->hasFocus() && | ||
666 | (key == KEY_RETURN || key == KEY_DOWN) && mask == MASK_NONE) | ||
667 | { | ||
668 | // move focus to inventory proper | ||
669 | root_folder->setFocus(TRUE); | ||
670 | root_folder->scrollToShowSelection(); | ||
671 | return TRUE; | ||
672 | } | ||
673 | |||
674 | if (root_folder->hasFocus() && key == KEY_UP) | ||
675 | { | ||
676 | startSearch(); | ||
677 | } | ||
678 | |||
679 | return LLFloater::handleKeyHere(key, mask, called_from_parent); | ||
680 | |||
681 | } | ||
682 | |||
683 | void LLInventoryView::changed(U32 mask) | ||
684 | { | ||
685 | std::ostringstream title; | ||
686 | title << "Inventory"; | ||
687 | if (LLInventoryModel::backgroundFetchActive()) | ||
688 | { | ||
689 | LLLocale locale(LLLocale::USER_LOCALE); | ||
690 | LLString item_count_string; | ||
691 | gResMgr->getIntegerString(item_count_string, gInventory.getItemCount()); | ||
692 | title << " (Fetched " << item_count_string << " items...)"; | ||
693 | } | ||
694 | title << mFilterText; | ||
695 | setTitle(title.str()); | ||
696 | } | ||
697 | |||
698 | // static | ||
699 | // *TODO: remove take_keyboard_focus param | ||
700 | LLInventoryView* LLInventoryView::showAgentInventory(BOOL take_keyboard_focus) | ||
701 | { | ||
702 | if (gDisconnected || gNoRender) | ||
703 | { | ||
704 | return NULL; | ||
705 | } | ||
706 | |||
707 | LLInventoryView* iv = LLInventoryView::getActiveInventory(); | ||
708 | #if 0 && !LL_RELEASE_FOR_DOWNLOAD | ||
709 | if (sActiveViews.count() == 1) | ||
710 | { | ||
711 | delete iv; | ||
712 | iv = NULL; | ||
713 | } | ||
714 | #endif | ||
715 | if(!iv && !gAgent.cameraMouselook()) | ||
716 | { | ||
717 | // create one. | ||
718 | iv = new LLInventoryView("Inventory", | ||
719 | "FloaterInventoryRect", | ||
720 | &gInventory); | ||
721 | iv->open(); | ||
722 | // keep onscreen | ||
723 | gFloaterView->adjustToFitScreen(iv, FALSE); | ||
724 | |||
725 | gSavedSettings.setBOOL("ShowInventory", TRUE); | ||
726 | } | ||
727 | if(iv) | ||
728 | { | ||
729 | // Make sure it's in front and it makes a noise | ||
730 | iv->setTitle("Inventory"); | ||
731 | iv->open(); | ||
732 | } | ||
733 | //if (take_keyboard_focus) | ||
734 | //{ | ||
735 | // iv->startSearch(); | ||
736 | // gFocusMgr.triggerFocusFlash(); | ||
737 | //} | ||
738 | return iv; | ||
739 | } | ||
740 | |||
741 | // static | ||
742 | LLInventoryView* LLInventoryView::getActiveInventory() | ||
743 | { | ||
744 | LLInventoryView* iv = NULL; | ||
745 | S32 count = sActiveViews.count(); | ||
746 | if(count > 0) | ||
747 | { | ||
748 | iv = sActiveViews.get(0); | ||
749 | S32 z_order = gFloaterView->getZOrder(iv); | ||
750 | S32 z_next = 0; | ||
751 | LLInventoryView* next_iv = NULL; | ||
752 | for(S32 i = 1; i < count; ++i) | ||
753 | { | ||
754 | next_iv = sActiveViews.get(i); | ||
755 | z_next = gFloaterView->getZOrder(next_iv); | ||
756 | if(z_next < z_order) | ||
757 | { | ||
758 | iv = next_iv; | ||
759 | z_order = z_next; | ||
760 | } | ||
761 | } | ||
762 | } | ||
763 | return iv; | ||
764 | } | ||
765 | |||
766 | // static | ||
767 | void LLInventoryView::toggleVisibility() | ||
768 | { | ||
769 | S32 count = sActiveViews.count(); | ||
770 | if (0 == count) | ||
771 | { | ||
772 | showAgentInventory(TRUE); | ||
773 | } | ||
774 | else if (1 == count) | ||
775 | { | ||
776 | if (sActiveViews.get(0)->getVisible()) | ||
777 | { | ||
778 | sActiveViews.get(0)->close(); | ||
779 | gSavedSettings.setBOOL("ShowInventory", FALSE); | ||
780 | } | ||
781 | else | ||
782 | { | ||
783 | showAgentInventory(TRUE); | ||
784 | } | ||
785 | } | ||
786 | else | ||
787 | { | ||
788 | // With more than one open, we know at least one | ||
789 | // is visible. | ||
790 | |||
791 | // Close all the last one spawned. | ||
792 | S32 last_index = sActiveViews.count() - 1; | ||
793 | sActiveViews.get(last_index)->close(); | ||
794 | } | ||
795 | } | ||
796 | |||
797 | // static | ||
798 | void LLInventoryView::cleanup() | ||
799 | { | ||
800 | S32 count = sActiveViews.count(); | ||
801 | for (S32 i = 0; i < count; i++) | ||
802 | { | ||
803 | sActiveViews.get(i)->destroy(); | ||
804 | } | ||
805 | } | ||
806 | |||
807 | void LLInventoryView::toggleFindOptions() | ||
808 | { | ||
809 | LLFloater *floater = getFinder(); | ||
810 | if (!floater) | ||
811 | { | ||
812 | LLInventoryViewFinder * finder = new LLInventoryViewFinder("Inventory Finder", | ||
813 | LLRect(mRect.mLeft - INV_FINDER_WIDTH, mRect.mTop, mRect.mLeft, mRect.mTop - INV_FINDER_HEIGHT), | ||
814 | this); | ||
815 | mFinderHandle = finder->getHandle(); | ||
816 | finder->open(); | ||
817 | addDependentFloater(mFinderHandle); | ||
818 | |||
819 | // start background fetch of folders | ||
820 | gInventory.startBackgroundFetch(); | ||
821 | |||
822 | mFloaterControls["Inventory.ShowFilters"]->setValue(TRUE); | ||
823 | } | ||
824 | else | ||
825 | { | ||
826 | floater->close(); | ||
827 | |||
828 | mFloaterControls["Inventory.ShowFilters"]->setValue(FALSE); | ||
829 | } | ||
830 | } | ||
831 | |||
832 | // static | ||
833 | BOOL LLInventoryView::filtersVisible(void* user_data) | ||
834 | { | ||
835 | LLInventoryView* self = (LLInventoryView*)user_data; | ||
836 | if(!self) return FALSE; | ||
837 | |||
838 | return self->getFinder() != NULL; | ||
839 | } | ||
840 | |||
841 | // static | ||
842 | void LLInventoryView::onClearSearch(void* user_data) | ||
843 | { | ||
844 | LLInventoryView* self = (LLInventoryView*)user_data; | ||
845 | if(!self) return; | ||
846 | |||
847 | LLFloater *finder = self->getFinder(); | ||
848 | if (self->mActivePanel) | ||
849 | { | ||
850 | self->mActivePanel->setFilterSubString(""); | ||
851 | self->mActivePanel->setFilterTypes(0xffffffff); | ||
852 | } | ||
853 | |||
854 | if (finder) | ||
855 | { | ||
856 | LLInventoryViewFinder::selectAllTypes(finder); | ||
857 | } | ||
858 | |||
859 | // re-open folders that were initially open | ||
860 | if (self->mActivePanel) | ||
861 | { | ||
862 | self->mSavedFolderState->setApply(TRUE); | ||
863 | self->mActivePanel->getRootFolder()->applyFunctorRecursively(*self->mSavedFolderState); | ||
864 | LLOpenFoldersWithSelection opener; | ||
865 | self->mActivePanel->getRootFolder()->applyFunctorRecursively(opener); | ||
866 | self->mActivePanel->getRootFolder()->scrollToShowSelection(); | ||
867 | } | ||
868 | } | ||
869 | |||
870 | //static | ||
871 | void LLInventoryView::onSearchEdit(const LLString& search_string, void* user_data ) | ||
872 | { | ||
873 | if (search_string == "") | ||
874 | { | ||
875 | onClearSearch(user_data); | ||
876 | } | ||
877 | LLInventoryView* self = (LLInventoryView*)user_data; | ||
878 | if (!self->mActivePanel) | ||
879 | { | ||
880 | return; | ||
881 | } | ||
882 | |||
883 | gInventory.startBackgroundFetch(); | ||
884 | |||
885 | LLString filter_text = search_string; | ||
886 | LLString uppercase_search_string = filter_text; | ||
887 | LLString::toUpper(uppercase_search_string); | ||
888 | if (self->mActivePanel->getFilterSubString().empty() && uppercase_search_string.empty()) | ||
889 | { | ||
890 | // current filter and new filter empty, do nothing | ||
891 | return; | ||
892 | } | ||
893 | |||
894 | // save current folder open state if no filter currently applied | ||
895 | if (!self->mActivePanel->getRootFolder()->isFilterActive()) | ||
896 | { | ||
897 | self->mSavedFolderState->clearOpenFolders(); | ||
898 | self->mSavedFolderState->setApply(FALSE); | ||
899 | self->mActivePanel->getRootFolder()->applyFunctorRecursively(*self->mSavedFolderState); | ||
900 | } | ||
901 | |||
902 | // set new filter string | ||
903 | self->mActivePanel->setFilterSubString(uppercase_search_string); | ||
904 | } | ||
905 | |||
906 | |||
907 | // static | ||
908 | BOOL LLInventoryView::incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward) | ||
909 | { | ||
910 | LLInventoryView* active_view = NULL; | ||
911 | |||
912 | for (S32 i = 0; i < sActiveViews.count(); i++) | ||
913 | { | ||
914 | if (gFocusMgr.childHasKeyboardFocus(sActiveViews[i])) | ||
915 | { | ||
916 | active_view = sActiveViews[i]; | ||
917 | break; | ||
918 | } | ||
919 | } | ||
920 | |||
921 | if (!active_view) | ||
922 | { | ||
923 | return FALSE; | ||
924 | } | ||
925 | |||
926 | LLString search_string(find_text); | ||
927 | |||
928 | if (search_string.empty()) | ||
929 | { | ||
930 | return FALSE; | ||
931 | } | ||
932 | |||
933 | if (active_view->mActivePanel && | ||
934 | active_view->mActivePanel->getRootFolder()->search(first_item, search_string, backward)) | ||
935 | { | ||
936 | return TRUE; | ||
937 | } | ||
938 | |||
939 | return FALSE; | ||
940 | } | ||
941 | |||
942 | //static | ||
943 | void LLInventoryView::onFilterSelected(void* userdata, bool from_click) | ||
944 | { | ||
945 | LLInventoryView* self = (LLInventoryView*) userdata; | ||
946 | LLInventoryFilter* filter; | ||
947 | |||
948 | LLInventoryViewFinder *finder = self->getFinder(); | ||
949 | // Find my index | ||
950 | self->mActivePanel = (LLInventoryPanel*)self->childGetVisibleTab("inventory filter tabs"); | ||
951 | if (!self->mActivePanel) | ||
952 | { | ||
953 | return; | ||
954 | } | ||
955 | filter = self->mActivePanel->getFilter(); | ||
956 | if (finder) | ||
957 | { | ||
958 | finder->changeFilter(filter); | ||
959 | } | ||
960 | if (filter->isActive()) | ||
961 | { | ||
962 | // If our filter is active we may be the first thing requiring a fetch so we better start it here. | ||
963 | gInventory.startBackgroundFetch(); | ||
964 | } | ||
965 | self->setFilterTextFromFilter(); | ||
966 | } | ||
967 | |||
968 | LLUUID get_item_icon_uuid(LLAssetType::EType asset_type, | ||
969 | LLInventoryType::EType inventory_type, | ||
970 | U32 flags) | ||
971 | { | ||
972 | EInventoryIcon idx = OBJECT_ICON_NAME; | ||
973 | switch(asset_type) | ||
974 | { | ||
975 | case LLAssetType::AT_TEXTURE: | ||
976 | if(LLInventoryType::IT_SNAPSHOT == inventory_type) | ||
977 | { | ||
978 | idx = SNAPSHOT_ICON_NAME; | ||
979 | } | ||
980 | else | ||
981 | { | ||
982 | idx = TEXTURE_ICON_NAME; | ||
983 | } | ||
984 | break; | ||
985 | case LLAssetType::AT_SOUND: | ||
986 | idx = SOUND_ICON_NAME; | ||
987 | break; | ||
988 | case LLAssetType::AT_CALLINGCARD: | ||
989 | if(flags != 0) | ||
990 | { | ||
991 | idx = CALLINGCARD_ONLINE_ICON_NAME; | ||
992 | } | ||
993 | else | ||
994 | { | ||
995 | idx = CALLINGCARD_OFFLINE_ICON_NAME; | ||
996 | } | ||
997 | break; | ||
998 | case LLAssetType::AT_LANDMARK: | ||
999 | if(flags != 0) | ||
1000 | { | ||
1001 | idx = LANDMARK_VISITED_ICON_NAME; | ||
1002 | } | ||
1003 | else | ||
1004 | { | ||
1005 | idx = LANDMARK_ICON_NAME; | ||
1006 | } | ||
1007 | break; | ||
1008 | case LLAssetType::AT_SCRIPT: | ||
1009 | case LLAssetType::AT_LSL_TEXT: | ||
1010 | case LLAssetType::AT_LSL_BYTECODE: | ||
1011 | idx = SCRIPT_ICON_NAME; | ||
1012 | break; | ||
1013 | case LLAssetType::AT_CLOTHING: | ||
1014 | idx = CLOTHING_ICON_NAME; | ||
1015 | case LLAssetType::AT_BODYPART : | ||
1016 | if(LLAssetType::AT_BODYPART == asset_type) | ||
1017 | { | ||
1018 | idx = BODYPART_ICON_NAME; | ||
1019 | } | ||
1020 | switch(flags) | ||
1021 | { | ||
1022 | case WT_SHAPE: | ||
1023 | idx = BODYPART_SHAPE_ICON_NAME; | ||
1024 | break; | ||
1025 | case WT_SKIN: | ||
1026 | idx = BODYPART_SKIN_ICON_NAME; | ||
1027 | break; | ||
1028 | case WT_HAIR: | ||
1029 | idx = BODYPART_HAIR_ICON_NAME; | ||
1030 | break; | ||
1031 | case WT_EYES: | ||
1032 | idx = BODYPART_EYES_ICON_NAME; | ||
1033 | break; | ||
1034 | case WT_SHIRT: | ||
1035 | idx = CLOTHING_SHIRT_ICON_NAME; | ||
1036 | break; | ||
1037 | case WT_PANTS: | ||
1038 | idx = CLOTHING_PANTS_ICON_NAME; | ||
1039 | break; | ||
1040 | case WT_SHOES: | ||
1041 | idx = CLOTHING_SHOES_ICON_NAME; | ||
1042 | break; | ||
1043 | case WT_SOCKS: | ||
1044 | idx = CLOTHING_SOCKS_ICON_NAME; | ||
1045 | break; | ||
1046 | case WT_JACKET: | ||
1047 | idx = CLOTHING_JACKET_ICON_NAME; | ||
1048 | break; | ||
1049 | case WT_GLOVES: | ||
1050 | idx = CLOTHING_GLOVES_ICON_NAME; | ||
1051 | break; | ||
1052 | case WT_UNDERSHIRT: | ||
1053 | idx = CLOTHING_UNDERSHIRT_ICON_NAME; | ||
1054 | break; | ||
1055 | case WT_UNDERPANTS: | ||
1056 | idx = CLOTHING_UNDERPANTS_ICON_NAME; | ||
1057 | break; | ||
1058 | case WT_SKIRT: | ||
1059 | idx = CLOTHING_SKIRT_ICON_NAME; | ||
1060 | break; | ||
1061 | default: | ||
1062 | // no-op, go with choice above | ||
1063 | break; | ||
1064 | } | ||
1065 | break; | ||
1066 | case LLAssetType::AT_NOTECARD: | ||
1067 | idx = NOTECARD_ICON_NAME; | ||
1068 | break; | ||
1069 | case LLAssetType::AT_ANIMATION: | ||
1070 | idx = ANIMATION_ICON_NAME; | ||
1071 | break; | ||
1072 | case LLAssetType::AT_GESTURE: | ||
1073 | idx = GESTURE_ICON_NAME; | ||
1074 | break; | ||
1075 | default: | ||
1076 | break; | ||
1077 | } | ||
1078 | LLString uuid_string = gViewerArt.getString(ICON_NAME[idx]); | ||
1079 | return LLUUID(uuid_string); | ||
1080 | } | ||
1081 | |||
1082 | LLViewerImage* get_item_icon(LLAssetType::EType asset_type, | ||
1083 | LLInventoryType::EType inventory_type, | ||
1084 | U32 flags) | ||
1085 | { | ||
1086 | LLUUID icon_uuid = get_item_icon_uuid(asset_type, inventory_type, flags); | ||
1087 | LLViewerImage* imagep = gImageList.getImage(icon_uuid, MIPMAP_FALSE, TRUE); | ||
1088 | imagep->setClamp(TRUE, TRUE); | ||
1089 | return imagep; | ||
1090 | } | ||
1091 | |||
1092 | const LLString LLInventoryPanel::DEFAULT_SORT_ORDER = LLString("InventorySortOrder"); | ||
1093 | const LLString LLInventoryPanel::RECENTITEMS_SORT_ORDER = LLString("RecentItemsSortOrder"); | ||
1094 | const LLString LLInventoryPanel::INHERIT_SORT_ORDER = LLString(""); | ||
1095 | |||
1096 | LLInventoryPanel::LLInventoryPanel(const LLString& name, | ||
1097 | const LLString& sort_order_setting, | ||
1098 | const LLRect& rect, | ||
1099 | LLInventoryModel* inventory, | ||
1100 | LLFolderSearchFunction search, | ||
1101 | BOOL allow_multi_select, | ||
1102 | LLView *parent_view) : | ||
1103 | LLPanel(name, rect, TRUE), | ||
1104 | mInventory(inventory), | ||
1105 | mInventoryObserver(NULL), | ||
1106 | mFolders(NULL), | ||
1107 | mScroller(NULL), | ||
1108 | mAllowMultiSelect(allow_multi_select), | ||
1109 | mSortOrderSetting(sort_order_setting), | ||
1110 | mSearchFunction(search), | ||
1111 | mNeedsAutoSelect(FALSE) | ||
1112 | { | ||
1113 | } | ||
1114 | |||
1115 | BOOL LLInventoryPanel::postBuild() | ||
1116 | { | ||
1117 | init_inventory_panel_actions(this); | ||
1118 | |||
1119 | LLRect folder_rect(0, | ||
1120 | 0, | ||
1121 | mRect.getWidth(), | ||
1122 | 0); | ||
1123 | mFolders = new LLFolderView(mName, NULL, folder_rect, LLUUID::null, this); | ||
1124 | mFolders->setAllowMultiSelect(mAllowMultiSelect); | ||
1125 | |||
1126 | // scroller | ||
1127 | LLRect scroller_view_rect = mRect; | ||
1128 | scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); | ||
1129 | mScroller = new LLScrollableContainerView("Inventory Scroller", | ||
1130 | scroller_view_rect, | ||
1131 | mFolders); | ||
1132 | mScroller->setFollowsAll(); | ||
1133 | mScroller->setReserveScrollCorner(TRUE); | ||
1134 | addChild(mScroller); | ||
1135 | mFolders->setScrollContainer(mScroller); | ||
1136 | |||
1137 | // set up the callbacks from the inventory we're viewing, and then | ||
1138 | // build everything. | ||
1139 | mInventoryObserver = new LLInventoryPanelObserver(this); | ||
1140 | mInventory->addObserver(mInventoryObserver); | ||
1141 | rebuildViewsFor(LLUUID::null, LLInventoryObserver::ADD); | ||
1142 | |||
1143 | // bit of a hack to make sure the inventory is open. | ||
1144 | mFolders->openFolder("My Inventory"); | ||
1145 | |||
1146 | if (mSortOrderSetting != INHERIT_SORT_ORDER) | ||
1147 | { | ||
1148 | setSortOrder(gSavedSettings.getU32(mSortOrderSetting)); | ||
1149 | } | ||
1150 | else | ||
1151 | { | ||
1152 | setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER)); | ||
1153 | } | ||
1154 | mFolders->setSortOrder(mFolders->getFilter()->getSortOrder()); | ||
1155 | |||
1156 | return TRUE; | ||
1157 | } | ||
1158 | |||
1159 | LLInventoryPanel::~LLInventoryPanel() | ||
1160 | { | ||
1161 | // should this be a global setting? | ||
1162 | U32 sort_order = mFolders->getSortOrder(); | ||
1163 | if (mSortOrderSetting != INHERIT_SORT_ORDER) | ||
1164 | { | ||
1165 | gSavedSettings.setU32(mSortOrderSetting, sort_order); | ||
1166 | } | ||
1167 | |||
1168 | // LLView destructor will take care of the sub-views. | ||
1169 | mInventory->removeObserver(mInventoryObserver); | ||
1170 | delete mInventoryObserver; | ||
1171 | mScroller = NULL; | ||
1172 | } | ||
1173 | |||
1174 | // virtual | ||
1175 | LLXMLNodePtr LLInventoryPanel::getXML(bool save_children) const | ||
1176 | { | ||
1177 | LLXMLNodePtr node = LLPanel::getXML(false); // Do not print out children | ||
1178 | |||
1179 | node->createChild("allow_multi_select", TRUE)->setBoolValue(mFolders->getAllowMultiSelect()); | ||
1180 | |||
1181 | return node; | ||
1182 | } | ||
1183 | |||
1184 | LLView* LLInventoryPanel::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) | ||
1185 | { | ||
1186 | LLInventoryPanel* panel; | ||
1187 | |||
1188 | LLString name("inventory_panel"); | ||
1189 | node->getAttributeString("name", name); | ||
1190 | |||
1191 | BOOL allow_multi_select = TRUE; | ||
1192 | node->getAttributeBOOL("allow_multi_select", allow_multi_select); | ||
1193 | |||
1194 | LLRect rect; | ||
1195 | createRect(node, rect, parent, LLRect()); | ||
1196 | |||
1197 | LLString sort_order(INHERIT_SORT_ORDER); | ||
1198 | node->getAttributeString("sort_order", sort_order); | ||
1199 | |||
1200 | panel = new LLInventoryPanel(name, sort_order, | ||
1201 | rect, &gInventory, | ||
1202 | LLInventoryView::incrementalFind, allow_multi_select, parent); | ||
1203 | |||
1204 | panel->initFromXML(node, parent); | ||
1205 | |||
1206 | panel->postBuild(); | ||
1207 | |||
1208 | return panel; | ||
1209 | } | ||
1210 | |||
1211 | void LLInventoryPanel::setFilterTypes(U32 filter_types) | ||
1212 | { | ||
1213 | mFolders->getFilter()->setFilterTypes(filter_types); | ||
1214 | } | ||
1215 | |||
1216 | void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) | ||
1217 | { | ||
1218 | mFolders->getFilter()->setFilterPermissions(filter_perm_mask); | ||
1219 | } | ||
1220 | |||
1221 | void LLInventoryPanel::setFilterSubString(const LLString& string) | ||
1222 | { | ||
1223 | mFolders->getFilter()->setFilterSubString(string); | ||
1224 | } | ||
1225 | |||
1226 | void LLInventoryPanel::setSortOrder(U32 order) | ||
1227 | { | ||
1228 | mFolders->getFilter()->setSortOrder(order); | ||
1229 | if (mFolders->getFilter()->isModified()) | ||
1230 | { | ||
1231 | mFolders->setSortOrder(order); | ||
1232 | // try to keep selection onscreen, even if it wasn't to start with | ||
1233 | mFolders->scrollToShowSelection(); | ||
1234 | } | ||
1235 | } | ||
1236 | |||
1237 | void LLInventoryPanel::setSinceLogoff(BOOL sl) | ||
1238 | { | ||
1239 | mFolders->getFilter()->setDateRangeLastLogoff(sl); | ||
1240 | } | ||
1241 | |||
1242 | void LLInventoryPanel::setHoursAgo(U32 hours) | ||
1243 | { | ||
1244 | mFolders->getFilter()->setHoursAgo(hours); | ||
1245 | } | ||
1246 | |||
1247 | void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show) | ||
1248 | { | ||
1249 | mFolders->getFilter()->setShowFolderState(show); | ||
1250 | } | ||
1251 | |||
1252 | LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState() | ||
1253 | { | ||
1254 | return mFolders->getFilter()->getShowFolderState(); | ||
1255 | } | ||
1256 | |||
1257 | void LLInventoryPanel::modelChanged(U32 mask) | ||
1258 | { | ||
1259 | LLFastTimer t2(LLFastTimer::FTM_REFRESH); | ||
1260 | |||
1261 | if(mask & LLInventoryObserver::LABEL) | ||
1262 | { | ||
1263 | // label change - empty out the display name for each object | ||
1264 | // in this change set. | ||
1265 | const std::set<LLUUID>& changed_items = gInventory.getChangedIDs(); | ||
1266 | std::set<LLUUID>::const_iterator id_it = changed_items.begin(); | ||
1267 | std::set<LLUUID>::const_iterator id_end = changed_items.end(); | ||
1268 | LLFolderViewItem* view = NULL; | ||
1269 | LLInvFVBridge* bridge = NULL; | ||
1270 | for (;id_it != id_end; ++id_it) | ||
1271 | { | ||
1272 | view = mFolders->getItemByID(*id_it); | ||
1273 | if(view) | ||
1274 | { | ||
1275 | // request refresh on this item (also flags for filtering) | ||
1276 | view->refresh(); | ||
1277 | bridge = (LLInvFVBridge*)view->getListener(); | ||
1278 | if(bridge) | ||
1279 | { | ||
1280 | bridge->clearDisplayName(); | ||
1281 | } | ||
1282 | } | ||
1283 | } | ||
1284 | } | ||
1285 | else if((mask & (LLInventoryObserver::STRUCTURE | ||
1286 | | LLInventoryObserver::ADD | ||
1287 | | LLInventoryObserver::REMOVE)) != 0) | ||
1288 | { | ||
1289 | |||
1290 | // Record which folders are open by uuid. | ||
1291 | LLInventoryModel* model = getModel(); | ||
1292 | if (model) | ||
1293 | { | ||
1294 | const std::set<LLUUID>& changed_items = gInventory.getChangedIDs(); | ||
1295 | |||
1296 | std::set<LLUUID>::const_iterator id_it = changed_items.begin(); | ||
1297 | std::set<LLUUID>::const_iterator id_end = changed_items.end(); | ||
1298 | for (;id_it != id_end; ++id_it) | ||
1299 | { | ||
1300 | // sync view with model | ||
1301 | LLInventoryObject* model_item = model->getObject(*id_it); | ||
1302 | LLFolderViewItem* view_item = mFolders->getItemByID(*id_it); | ||
1303 | |||
1304 | if (model_item) | ||
1305 | { | ||
1306 | if (!view_item) | ||
1307 | { | ||
1308 | // this object was just created, need to build a view for it | ||
1309 | if ((mask & LLInventoryObserver::ADD) != LLInventoryObserver::ADD) | ||
1310 | { | ||
1311 | llwarns << *id_it << " is in model but not in view, but ADD flag not set" << llendl; | ||
1312 | } | ||
1313 | buildNewViews(*id_it); | ||
1314 | } | ||
1315 | else | ||
1316 | { | ||
1317 | // this object was probably moved, check its parent | ||
1318 | if ((mask & LLInventoryObserver::STRUCTURE) != LLInventoryObserver::STRUCTURE) | ||
1319 | { | ||
1320 | llwarns << *id_it << " is in model and in view, but STRUCTURE flag not set" << llendl; | ||
1321 | } | ||
1322 | |||
1323 | LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolders->getItemByID(model_item->getParentUUID()); | ||
1324 | if (view_item->getParentFolder() != new_parent) | ||
1325 | { | ||
1326 | view_item->getParentFolder()->extractItem(view_item); | ||
1327 | view_item->addToFolder(new_parent, mFolders); | ||
1328 | } | ||
1329 | } | ||
1330 | } | ||
1331 | else | ||
1332 | { | ||
1333 | if (view_item) | ||
1334 | { | ||
1335 | if ((mask & LLInventoryObserver::REMOVE) != LLInventoryObserver::REMOVE) | ||
1336 | { | ||
1337 | llwarns << *id_it << " is not in model but in view, but REMOVE flag not set" << llendl; | ||
1338 | } | ||
1339 | // item in view but not model, need to delete view | ||
1340 | view_item->destroyView(); | ||
1341 | } | ||
1342 | else | ||
1343 | { | ||
1344 | llwarns << *id_it << "Item does not exist in either view or model, but notification triggered" << llendl; | ||
1345 | } | ||
1346 | } | ||
1347 | } | ||
1348 | } | ||
1349 | } | ||
1350 | else | ||
1351 | { | ||
1352 | // it's a small change that only requires a refresh. | ||
1353 | // *TODO: figure out a more efficient way to do the refresh | ||
1354 | // since it is expensive on large inventories | ||
1355 | mFolders->refresh(); | ||
1356 | } | ||
1357 | } | ||
1358 | |||
1359 | void LLInventoryPanel::rebuildViewsFor(const LLUUID& id, U32 mask) | ||
1360 | { | ||
1361 | LLFolderViewItem* old_view = NULL; | ||
1362 | |||
1363 | // get old LLFolderViewItem | ||
1364 | old_view = mFolders->getItemByID(id); | ||
1365 | if (old_view && id.notNull()) | ||
1366 | { | ||
1367 | old_view->destroyView(); | ||
1368 | } | ||
1369 | |||
1370 | buildNewViews(id); | ||
1371 | } | ||
1372 | |||
1373 | void LLInventoryPanel::buildNewViews(const LLUUID& id) | ||
1374 | { | ||
1375 | LLFolderViewItem* itemp = NULL; | ||
1376 | LLInventoryObject* objectp = gInventory.getObject(id); | ||
1377 | S32 i; | ||
1378 | S32 count; | ||
1379 | |||
1380 | if (objectp) | ||
1381 | { | ||
1382 | if (objectp->getType() == LLAssetType::AT_NONE) | ||
1383 | { | ||
1384 | llwarns << "LLInventoryPanel::buildNewViews called with objectp->mType == AT_NONE (shouldn't happen)" << llendl; | ||
1385 | itemp = NULL; | ||
1386 | } | ||
1387 | else if (objectp->getType() == LLAssetType::AT_CATEGORY) // build new view for category | ||
1388 | { | ||
1389 | LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(), | ||
1390 | LLInventoryType::IT_CATEGORY, | ||
1391 | this, | ||
1392 | objectp->getUUID()); | ||
1393 | |||
1394 | LLFolderViewFolder* folderp = new LLFolderViewFolder(new_listener->getDisplayName(), | ||
1395 | new_listener->getIcon(), | ||
1396 | mFolders, | ||
1397 | new_listener); | ||
1398 | if (!(mFolders->getSortOrder() & LLInventoryFilter::SO_DATE)) | ||
1399 | { | ||
1400 | folderp->setItemSortFunction(sort_item_name); | ||
1401 | } | ||
1402 | else | ||
1403 | { | ||
1404 | folderp->setItemSortFunction(sort_item_date); | ||
1405 | } | ||
1406 | itemp = folderp; | ||
1407 | } | ||
1408 | else // build new view for item | ||
1409 | { | ||
1410 | LLInventoryItem* item = (LLInventoryItem*)objectp; | ||
1411 | LLInvFVBridge* new_listener = LLInvFVBridge::createBridge( | ||
1412 | item->getType(), | ||
1413 | item->getInventoryType(), | ||
1414 | this, | ||
1415 | item->getUUID(), | ||
1416 | item->getFlags()); | ||
1417 | itemp = new LLFolderViewItem(new_listener->getDisplayName(), | ||
1418 | new_listener->getIcon(), | ||
1419 | new_listener->getCreationDate(), | ||
1420 | mFolders, | ||
1421 | new_listener); | ||
1422 | } | ||
1423 | |||
1424 | LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolders->getItemByID(objectp->getParentUUID()); | ||
1425 | |||
1426 | if (itemp) | ||
1427 | { | ||
1428 | if (parent_folder) | ||
1429 | { | ||
1430 | itemp->addToFolder(parent_folder, mFolders); | ||
1431 | } | ||
1432 | else | ||
1433 | { | ||
1434 | llwarns << "Couldn't find parent folder for child " << itemp->getLabel() << llendl; | ||
1435 | delete itemp; | ||
1436 | } | ||
1437 | } | ||
1438 | } | ||
1439 | |||
1440 | if ((id.isNull() || | ||
1441 | (objectp && objectp->getType() == LLAssetType::AT_CATEGORY))) | ||
1442 | { | ||
1443 | LLViewerInventoryCategory::cat_array_t* categories; | ||
1444 | LLViewerInventoryItem::item_array_t* items; | ||
1445 | |||
1446 | mInventory->getDirectDescendentsOf(id, categories, items); | ||
1447 | if(categories) | ||
1448 | { | ||
1449 | count = categories->count(); | ||
1450 | for(i = 0; i < count; ++i) | ||
1451 | { | ||
1452 | LLInventoryCategory* cat = categories->get(i); | ||
1453 | buildNewViews(cat->getUUID()); | ||
1454 | } | ||
1455 | } | ||
1456 | if(items) | ||
1457 | { | ||
1458 | count = items->count(); | ||
1459 | for(i = 0; i < count; ++i) | ||
1460 | { | ||
1461 | LLInventoryItem* item = items->get(i); | ||
1462 | buildNewViews(item->getUUID()); | ||
1463 | } | ||
1464 | } | ||
1465 | } | ||
1466 | } | ||
1467 | |||
1468 | struct LLConfirmPurgeData | ||
1469 | { | ||
1470 | LLUUID mID; | ||
1471 | LLInventoryModel* mModel; | ||
1472 | }; | ||
1473 | |||
1474 | class LLIsNotWorn : public LLInventoryCollectFunctor | ||
1475 | { | ||
1476 | public: | ||
1477 | LLIsNotWorn() {} | ||
1478 | virtual ~LLIsNotWorn() {} | ||
1479 | virtual bool operator()(LLInventoryCategory* cat, | ||
1480 | LLInventoryItem* item) | ||
1481 | { | ||
1482 | return !gAgent.isWearingItem(item->getUUID()); | ||
1483 | } | ||
1484 | }; | ||
1485 | |||
1486 | class LLOpenFolderByID : public LLFolderViewFunctor | ||
1487 | { | ||
1488 | public: | ||
1489 | LLOpenFolderByID(const LLUUID& id) : mID(id) {} | ||
1490 | virtual ~LLOpenFolderByID() {} | ||
1491 | virtual void doFolder(LLFolderViewFolder* folder) | ||
1492 | { | ||
1493 | if (folder->getListener() && folder->getListener()->getUUID() == mID) folder->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); | ||
1494 | } | ||
1495 | virtual void doItem(LLFolderViewItem* item) {} | ||
1496 | protected: | ||
1497 | const LLUUID& mID; | ||
1498 | }; | ||
1499 | |||
1500 | |||
1501 | void LLInventoryPanel::openSelected() | ||
1502 | { | ||
1503 | LLFolderViewItem* folder_item = mFolders->getCurSelectedItem(); | ||
1504 | if(!folder_item) return; | ||
1505 | LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener(); | ||
1506 | if(!bridge) return; | ||
1507 | bridge->openItem(); | ||
1508 | } | ||
1509 | |||
1510 | BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask) | ||
1511 | { | ||
1512 | BOOL handled = LLView::handleHover(x, y, mask); | ||
1513 | if(handled) | ||
1514 | { | ||
1515 | ECursorType cursor = getWindow()->getCursor(); | ||
1516 | if (LLInventoryModel::backgroundFetchActive() && cursor == UI_CURSOR_ARROW) | ||
1517 | { | ||
1518 | // replace arrow cursor with arrow and hourglass cursor | ||
1519 | getWindow()->setCursor(UI_CURSOR_WORKING); | ||
1520 | } | ||
1521 | } | ||
1522 | else | ||
1523 | { | ||
1524 | getWindow()->setCursor(UI_CURSOR_ARROW); | ||
1525 | } | ||
1526 | return TRUE; | ||
1527 | } | ||
1528 | |||
1529 | BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, | ||
1530 | EDragAndDropType cargo_type, | ||
1531 | void* cargo_data, | ||
1532 | EAcceptance* accept, | ||
1533 | LLString& tooltip_msg) | ||
1534 | { | ||
1535 | BOOL handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); | ||
1536 | |||
1537 | if (handled) | ||
1538 | { | ||
1539 | mFolders->setDragAndDropThisFrame(); | ||
1540 | } | ||
1541 | |||
1542 | return handled; | ||
1543 | } | ||
1544 | |||
1545 | |||
1546 | void LLInventoryPanel::openAllFolders() | ||
1547 | { | ||
1548 | mFolders->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); | ||
1549 | mFolders->arrangeAll(); | ||
1550 | } | ||
1551 | |||
1552 | void LLInventoryPanel::closeAllFolders() | ||
1553 | { | ||
1554 | mFolders->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); | ||
1555 | mFolders->arrangeAll(); | ||
1556 | } | ||
1557 | |||
1558 | void LLInventoryPanel::openDefaultFolderForType(LLAssetType::EType type) | ||
1559 | { | ||
1560 | LLUUID category_id = mInventory->findCategoryUUIDForType(type); | ||
1561 | LLOpenFolderByID opener(category_id); | ||
1562 | mFolders->applyFunctorRecursively(opener); | ||
1563 | } | ||
1564 | |||
1565 | void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus) | ||
1566 | { | ||
1567 | LLFolderViewItem* itemp = mFolders->getItemByID(obj_id); | ||
1568 | if(itemp && itemp->getListener()) | ||
1569 | { | ||
1570 | itemp->getListener()->arrangeAndSet(itemp, | ||
1571 | TRUE, | ||
1572 | take_keyboard_focus); | ||
1573 | } | ||
1574 | } | ||
1575 | |||
1576 | void LLInventoryPanel::clearSelection() | ||
1577 | { | ||
1578 | mFolders->clearSelection(); | ||
1579 | } | ||
1580 | |||
1581 | void LLInventoryPanel::createNewItem(const char* name, | ||
1582 | const LLUUID& parent_id, | ||
1583 | LLAssetType::EType asset_type, | ||
1584 | LLInventoryType::EType inv_type, | ||
1585 | U32 next_owner_perm) | ||
1586 | { | ||
1587 | LLString desc; | ||
1588 | LLAssetType::generateDescriptionFor(asset_type, desc); | ||
1589 | next_owner_perm = (next_owner_perm) ? next_owner_perm : PERM_MOVE | PERM_TRANSFER; | ||
1590 | |||
1591 | LLPointer<LLInventoryCallback> cb = NULL; | ||
1592 | create_inventory_item(gAgent.getID(), gAgent.getSessionID(), | ||
1593 | parent_id, LLTransactionID::tnull, name, desc, asset_type, inv_type, | ||
1594 | NOT_WEARABLE, next_owner_perm, cb); | ||
1595 | } | ||
1596 | |||
1597 | // static DEBUG ONLY: | ||
1598 | void LLInventoryPanel::dumpSelectionInformation(void* user_data) | ||
1599 | { | ||
1600 | LLInventoryPanel* iv = (LLInventoryPanel*)user_data; | ||
1601 | iv->mFolders->dumpSelectionInformation(); | ||
1602 | } | ||