aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llinventoryview.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llinventoryview.cpp
parentREADME.txt (diff)
downloadmeta-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.cpp1602
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
80LLDynamicArray<LLInventoryView*> LLInventoryView::sActiveViews;
81
82//BOOL LLInventoryView::sOpenNextNewItem = FALSE;
83BOOL LLInventoryView::sWearNewClothing = FALSE;
84LLUUID LLInventoryView::sWearNewClothingTransactionID;
85
86///----------------------------------------------------------------------------
87/// Local function declarations, constants, enums, and typedefs
88///----------------------------------------------------------------------------
89
90const S32 INV_MIN_WIDTH = 240;
91const S32 INV_MIN_HEIGHT = 150;
92const S32 INV_FINDER_WIDTH = 160;
93const S32 INV_FINDER_HEIGHT = 408;
94
95///----------------------------------------------------------------------------
96/// LLInventoryViewFinder
97///----------------------------------------------------------------------------
98
99LLInventoryViewFinder::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
125void 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
133void LLInventoryViewFinder::changeFilter(LLInventoryFilter* filter)
134{
135 mFilter = filter;
136 updateElementsFromFilter();
137}
138
139void 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
170void 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
277void 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
292BOOL LLInventoryViewFinder::getCheckShowEmpty()
293{
294 return childGetValue("check_show_empty");
295}
296
297BOOL LLInventoryViewFinder::getCheckSinceLogoff()
298{
299 return childGetValue("check_since_logoff");
300}
301
302void LLInventoryViewFinder::onCloseBtn(void* user_data)
303{
304 LLInventoryViewFinder* finderp = (LLInventoryViewFinder*)user_data;
305 finderp->close();
306}
307
308// static
309void 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
340void 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///----------------------------------------------------------------------------
376class LLSaveFolderState : public LLFolderViewFunctor
377{
378public:
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(); }
385protected:
386 std::set<LLUUID> mOpenFolders;
387 BOOL mApply;
388};
389
390void 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
424LLInventoryView::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
435LLInventoryView::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
448void 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
497BOOL 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
506LLInventoryView::~LLInventoryView( void )
507{
508 sActiveViews.removeObj(this);
509 gInventory.removeObserver(this);
510 delete mSavedFolderState;
511}
512
513void 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
544void LLOpenFilteredFolders::doItem(LLFolderViewItem *item)
545{
546 if (item->getFiltered())
547 {
548 item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
549 }
550}
551
552void 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
565void 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
579void 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
593class LLOpenFoldersWithSelection : public LLFolderViewFunctor
594{
595public:
596 LLOpenFoldersWithSelection() {}
597 virtual ~LLOpenFoldersWithSelection() {}
598 virtual void doFolder(LLFolderViewFolder* folder);
599 virtual void doItem(LLFolderViewItem* item);
600};
601
602void LLOpenFoldersWithSelection::doItem(LLFolderViewItem *item)
603{
604 if (item->getParentFolder() && item->isSelected())
605 {
606 item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
607 }
608}
609
610void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder)
611{
612 if (folder->getParentFolder() && folder->isSelected())
613 {
614 folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
615 }
616}
617
618void 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
628void 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.
635void 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
660BOOL 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
683void 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
700LLInventoryView* 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
742LLInventoryView* 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
767void 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
798void 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
807void 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
833BOOL 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
842void 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
871void 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
908BOOL 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
943void 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
968LLUUID 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
1082LLViewerImage* 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
1092const LLString LLInventoryPanel::DEFAULT_SORT_ORDER = LLString("InventorySortOrder");
1093const LLString LLInventoryPanel::RECENTITEMS_SORT_ORDER = LLString("RecentItemsSortOrder");
1094const LLString LLInventoryPanel::INHERIT_SORT_ORDER = LLString("");
1095
1096LLInventoryPanel::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
1115BOOL 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
1159LLInventoryPanel::~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
1175LLXMLNodePtr 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
1184LLView* 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
1211void LLInventoryPanel::setFilterTypes(U32 filter_types)
1212{
1213 mFolders->getFilter()->setFilterTypes(filter_types);
1214}
1215
1216void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask)
1217{
1218 mFolders->getFilter()->setFilterPermissions(filter_perm_mask);
1219}
1220
1221void LLInventoryPanel::setFilterSubString(const LLString& string)
1222{
1223 mFolders->getFilter()->setFilterSubString(string);
1224}
1225
1226void 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
1237void LLInventoryPanel::setSinceLogoff(BOOL sl)
1238{
1239 mFolders->getFilter()->setDateRangeLastLogoff(sl);
1240}
1241
1242void LLInventoryPanel::setHoursAgo(U32 hours)
1243{
1244 mFolders->getFilter()->setHoursAgo(hours);
1245}
1246
1247void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show)
1248{
1249 mFolders->getFilter()->setShowFolderState(show);
1250}
1251
1252LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState()
1253{
1254 return mFolders->getFilter()->getShowFolderState();
1255}
1256
1257void 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
1359void 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
1373void 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
1468struct LLConfirmPurgeData
1469{
1470 LLUUID mID;
1471 LLInventoryModel* mModel;
1472};
1473
1474class LLIsNotWorn : public LLInventoryCollectFunctor
1475{
1476public:
1477 LLIsNotWorn() {}
1478 virtual ~LLIsNotWorn() {}
1479 virtual bool operator()(LLInventoryCategory* cat,
1480 LLInventoryItem* item)
1481 {
1482 return !gAgent.isWearingItem(item->getUUID());
1483 }
1484};
1485
1486class LLOpenFolderByID : public LLFolderViewFunctor
1487{
1488public:
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) {}
1496protected:
1497 const LLUUID& mID;
1498};
1499
1500
1501void 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
1510BOOL 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
1529BOOL 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
1546void LLInventoryPanel::openAllFolders()
1547{
1548 mFolders->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN);
1549 mFolders->arrangeAll();
1550}
1551
1552void LLInventoryPanel::closeAllFolders()
1553{
1554 mFolders->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN);
1555 mFolders->arrangeAll();
1556}
1557
1558void LLInventoryPanel::openDefaultFolderForType(LLAssetType::EType type)
1559{
1560 LLUUID category_id = mInventory->findCategoryUUIDForType(type);
1561 LLOpenFolderByID opener(category_id);
1562 mFolders->applyFunctorRecursively(opener);
1563}
1564
1565void 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
1576void LLInventoryPanel::clearSelection()
1577{
1578 mFolders->clearSelection();
1579}
1580
1581void 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:
1598void LLInventoryPanel::dumpSelectionInformation(void* user_data)
1599{
1600 LLInventoryPanel* iv = (LLInventoryPanel*)user_data;
1601 iv->mFolders->dumpSelectionInformation();
1602}