Files
SingularityViewer/indra/newview/llinventoryview.cpp
Shyotl e756140e1d Innitial commit of experimental v2 texture system port work. Compiles and runs on windows, at least. Fixing bugs as they come.
Need to test:
localassetbrowser
preview related floaters
hgfloatertexteditor
maps
media textures! Currently very hacky
web browser
alpha masks on avatars
bumpmaps
Are all sky components appearing?
LLViewerDynamicTexture (texture baking, browser, animated textures, anim previews, etc)
Snapshot related features
Customize avatar
vfs floater
UI textures in general
Texture priority issues
2011-03-31 03:22:01 -05:00

2125 lines
55 KiB
C++

/**
* @file llinventoryview.cpp
* @brief Implementation of the inventory view and associated stuff.
*
* $LicenseInfo:firstyear=2001&license=viewergpl$
*
* Copyright (c) 2001-2009, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at
* http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include <utility> // for std::pair<>
#include "llinventoryview.h"
#include "llinventorybridge.h"
#include "message.h"
#include "llagent.h"
#include "llcallingcard.h"
#include "llcheckboxctrl.h" // for radio buttons
#include "llradiogroup.h"
#include "llspinctrl.h"
#include "lltextbox.h"
#include "llui.h"
#include "llfirstuse.h"
#include "llfloateravatarinfo.h"
#include "llfloaterchat.h"
#include "llfloatercustomize.h"
#include "llfocusmgr.h"
#include "llfolderview.h"
#include "llgesturemgr.h"
#include "lliconctrl.h"
#include "llinventorymodel.h"
#include "llinventoryclipboard.h"
#include "lllineeditor.h"
#include "llmenugl.h"
#include "llpreviewanim.h"
#include "llpreviewgesture.h"
#include "llpreviewlandmark.h"
#include "llpreviewnotecard.h"
#include "llpreviewscript.h"
#include "llpreviewsound.h"
#include "llpreviewtexture.h"
#include "llresmgr.h"
#include "llscrollcontainer.h"
#include "llscrollbar.h"
#include "llimview.h"
#include "lltooldraganddrop.h"
#include "llviewertexturelist.h"
#include "llviewerinventory.h"
#include "llviewerobjectlist.h"
#include "llviewerwindow.h"
#include "llwearablelist.h"
#include "llappviewer.h"
#include "llviewermessage.h"
#include "llviewerregion.h"
#include "lltabcontainer.h"
#include "lluictrlfactory.h"
#include "llselectmgr.h"
#include "llsdserialize.h"
// [RLVa:KB]
#include "rlvhandler.h"
// [/RLVa:KB]
static LLRegisterWidget<LLInventoryPanel> r("inventory_panel");
LLDynamicArray<LLInventoryView*> LLInventoryView::sActiveViews;
//BOOL LLInventoryView::sOpenNextNewItem = FALSE;
BOOL LLInventoryView::sWearNewClothing = FALSE;
LLUUID LLInventoryView::sWearNewClothingTransactionID;
///----------------------------------------------------------------------------
/// Local function declarations, constants, enums, and typedefs
///----------------------------------------------------------------------------
const S32 INV_MIN_WIDTH = 240;
const S32 INV_MIN_HEIGHT = 150;
const S32 INV_FINDER_WIDTH = 160;
const S32 INV_FINDER_HEIGHT = 408;
///----------------------------------------------------------------------------
/// LLInventoryViewFinder
///----------------------------------------------------------------------------
LLInventoryViewFinder::LLInventoryViewFinder(const std::string& name,
const LLRect& rect,
LLInventoryView* inventory_view) :
LLFloater(name, rect, std::string("Filters"), RESIZE_NO,
INV_FINDER_WIDTH, INV_FINDER_HEIGHT, DRAG_ON_TOP,
MINIMIZE_NO, CLOSE_YES),
mInventoryView(inventory_view),
mFilter(inventory_view->mActivePanel->getFilter())
{
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_view_finder.xml");
childSetAction("All", selectAllTypes, this);
childSetAction("None", selectNoTypes, this);
mSpinSinceHours = getChild<LLSpinCtrl>("spin_hours_ago");
childSetCommitCallback("spin_hours_ago", onTimeAgo, this);
mSpinSinceDays = getChild<LLSpinCtrl>("spin_days_ago");
childSetCommitCallback("spin_days_ago", onTimeAgo, this);
// mCheckSinceLogoff = getChild<LLSpinCtrl>("check_since_logoff");
childSetCommitCallback("check_since_logoff", onCheckSinceLogoff, this);
childSetAction("Close", onCloseBtn, this);
updateElementsFromFilter();
}
void LLInventoryViewFinder::onCheckSinceLogoff(LLUICtrl *ctrl, void *user_data)
{
LLInventoryViewFinder *self = (LLInventoryViewFinder *)user_data;
if (!self) return;
bool since_logoff= self->childGetValue("check_since_logoff");
if (!since_logoff &&
!( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) )
{
self->mSpinSinceHours->set(1.0f);
}
}
void LLInventoryViewFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data)
{
LLInventoryViewFinder *self = (LLInventoryViewFinder *)user_data;
if (!self) return;
bool since_logoff=true;
if ( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() )
{
since_logoff = false;
}
self->childSetValue("check_since_logoff", since_logoff);
}
void LLInventoryViewFinder::changeFilter(LLInventoryFilter* filter)
{
mFilter = filter;
updateElementsFromFilter();
}
void LLInventoryViewFinder::updateElementsFromFilter()
{
if (!mFilter)
return;
// Get data needed for filter display
U32 filter_types = mFilter->getFilterTypes();
std::string filter_string = mFilter->getFilterSubString();
LLInventoryFilter::EFolderShow show_folders = mFilter->getShowFolderState();
U32 hours = mFilter->getHoursAgo();
// update the ui elements
LLFloater::setTitle(mFilter->getName());
childSetValue("check_animation", (S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION));
childSetValue("check_calling_card", (S32) (filter_types & 0x1 << LLInventoryType::IT_CALLINGCARD));
childSetValue("check_clothing", (S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE));
childSetValue("check_gesture", (S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE));
childSetValue("check_landmark", (S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK));
childSetValue("check_notecard", (S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD));
childSetValue("check_object", (S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT));
childSetValue("check_script", (S32) (filter_types & 0x1 << LLInventoryType::IT_LSL));
childSetValue("check_sound", (S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND));
childSetValue("check_texture", (S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE));
childSetValue("check_snapshot", (S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT));
childSetValue("check_show_empty", show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS);
childSetValue("check_since_logoff", mFilter->isSinceLogoff());
mSpinSinceHours->set((F32)(hours % 24));
mSpinSinceDays->set((F32)(hours / 24));
}
void LLInventoryViewFinder::draw()
{
U32 filter = 0xffffffff;
BOOL filtered_by_all_types = TRUE;
if (!childGetValue("check_animation"))
{
filter &= ~(0x1 << LLInventoryType::IT_ANIMATION);
filtered_by_all_types = FALSE;
}
if (!childGetValue("check_calling_card"))
{
filter &= ~(0x1 << LLInventoryType::IT_CALLINGCARD);
filtered_by_all_types = FALSE;
}
if (!childGetValue("check_clothing"))
{
filter &= ~(0x1 << LLInventoryType::IT_WEARABLE);
filtered_by_all_types = FALSE;
}
if (!childGetValue("check_gesture"))
{
filter &= ~(0x1 << LLInventoryType::IT_GESTURE);
filtered_by_all_types = FALSE;
}
if (!childGetValue("check_landmark"))
{
filter &= ~(0x1 << LLInventoryType::IT_LANDMARK);
filtered_by_all_types = FALSE;
}
if (!childGetValue("check_notecard"))
{
filter &= ~(0x1 << LLInventoryType::IT_NOTECARD);
filtered_by_all_types = FALSE;
}
if (!childGetValue("check_object"))
{
filter &= ~(0x1 << LLInventoryType::IT_OBJECT);
filter &= ~(0x1 << LLInventoryType::IT_ATTACHMENT);
filtered_by_all_types = FALSE;
}
if (!childGetValue("check_script"))
{
filter &= ~(0x1 << LLInventoryType::IT_LSL);
filtered_by_all_types = FALSE;
}
if (!childGetValue("check_sound"))
{
filter &= ~(0x1 << LLInventoryType::IT_SOUND);
filtered_by_all_types = FALSE;
}
if (!childGetValue("check_texture"))
{
filter &= ~(0x1 << LLInventoryType::IT_TEXTURE);
filtered_by_all_types = FALSE;
}
if (!childGetValue("check_snapshot"))
{
filter &= ~(0x1 << LLInventoryType::IT_SNAPSHOT);
filtered_by_all_types = FALSE;
}
if (!filtered_by_all_types)
{
// don't include folders in filter, unless I've selected everything
filter &= ~(0x1 << LLInventoryType::IT_CATEGORY);
}
// update the panel, panel will update the filter
mInventoryView->mActivePanel->setShowFolderState(getCheckShowEmpty() ?
LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
mInventoryView->mActivePanel->setFilterTypes(filter);
if (getCheckSinceLogoff())
{
mSpinSinceDays->set(0);
mSpinSinceHours->set(0);
}
U32 days = (U32)mSpinSinceDays->get();
U32 hours = (U32)mSpinSinceHours->get();
if (hours > 24)
{
days += hours / 24;
hours = (U32)hours % 24;
mSpinSinceDays->set((F32)days);
mSpinSinceHours->set((F32)hours);
}
hours += days * 24;
mInventoryView->mActivePanel->setHoursAgo(hours);
mInventoryView->mActivePanel->setSinceLogoff(getCheckSinceLogoff());
mInventoryView->setFilterTextFromFilter();
LLFloater::draw();
}
void LLInventoryViewFinder::onClose(bool app_quitting)
{
if (mInventoryView) mInventoryView->getControl("Inventory.ShowFilters")->setValue(FALSE);
// If you want to reset the filter on close, do it here. This functionality was
// hotly debated - Paulm
#if 0
if (mInventoryView)
{
LLInventoryView::onResetFilter((void *)mInventoryView);
}
#endif
destroy();
}
BOOL LLInventoryViewFinder::getCheckShowEmpty()
{
return childGetValue("check_show_empty");
}
BOOL LLInventoryViewFinder::getCheckSinceLogoff()
{
return childGetValue("check_since_logoff");
}
void LLInventoryViewFinder::onCloseBtn(void* user_data)
{
LLInventoryViewFinder* finderp = (LLInventoryViewFinder*)user_data;
finderp->close();
}
// static
void LLInventoryViewFinder::selectAllTypes(void* user_data)
{
LLInventoryViewFinder* self = (LLInventoryViewFinder*)user_data;
if(!self) return;
self->childSetValue("check_animation", TRUE);
self->childSetValue("check_calling_card", TRUE);
self->childSetValue("check_clothing", TRUE);
self->childSetValue("check_gesture", TRUE);
self->childSetValue("check_landmark", TRUE);
self->childSetValue("check_notecard", TRUE);
self->childSetValue("check_object", TRUE);
self->childSetValue("check_script", TRUE);
self->childSetValue("check_sound", TRUE);
self->childSetValue("check_texture", TRUE);
self->childSetValue("check_snapshot", TRUE);
/*
self->mCheckCallingCard->set(TRUE);
self->mCheckClothing->set(TRUE);
self->mCheckGesture->set(TRUE);
self->mCheckLandmark->set(TRUE);
self->mCheckNotecard->set(TRUE);
self->mCheckObject->set(TRUE);
self->mCheckScript->set(TRUE);
self->mCheckSound->set(TRUE);
self->mCheckTexture->set(TRUE);
self->mCheckSnapshot->set(TRUE);*/
}
//static
void LLInventoryViewFinder::selectNoTypes(void* user_data)
{
LLInventoryViewFinder* self = (LLInventoryViewFinder*)user_data;
if(!self) return;
/*
self->childSetValue("check_animation", FALSE);
self->mCheckCallingCard->set(FALSE);
self->mCheckClothing->set(FALSE);
self->mCheckGesture->set(FALSE);
self->mCheckLandmark->set(FALSE);
self->mCheckNotecard->set(FALSE);
self->mCheckObject->set(FALSE);
self->mCheckScript->set(FALSE);
self->mCheckSound->set(FALSE);
self->mCheckTexture->set(FALSE);
self->mCheckSnapshot->set(FALSE);*/
self->childSetValue("check_animation", FALSE);
self->childSetValue("check_calling_card", FALSE);
self->childSetValue("check_clothing", FALSE);
self->childSetValue("check_gesture", FALSE);
self->childSetValue("check_landmark", FALSE);
self->childSetValue("check_notecard", FALSE);
self->childSetValue("check_object", FALSE);
self->childSetValue("check_script", FALSE);
self->childSetValue("check_sound", FALSE);
self->childSetValue("check_texture", FALSE);
self->childSetValue("check_snapshot", FALSE);
}
///----------------------------------------------------------------------------
/// LLInventoryView
///----------------------------------------------------------------------------
void LLSaveFolderState::setApply(BOOL apply)
{
mApply = apply;
// before generating new list of open folders, clear the old one
if(!apply)
{
clearOpenFolders();
}
}
void LLSaveFolderState::doFolder(LLFolderViewFolder* folder)
{
if(mApply)
{
// we're applying the open state
LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener();
if(!bridge) return;
LLUUID id(bridge->getUUID());
if(mOpenFolders.find(id) != mOpenFolders.end())
{
folder->setOpen(TRUE);
}
else
{
// keep selected filter in its current state, this is less jarring to user
if (!folder->isSelected())
{
folder->setOpen(FALSE);
}
}
}
else
{
// we're recording state at this point
if(folder->isOpen())
{
LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener();
if(!bridge) return;
mOpenFolders.insert(bridge->getUUID());
}
}
}
// Default constructor
LLInventoryView::LLInventoryView(const std::string& name,
const std::string& rect,
LLInventoryModel* inventory) :
LLFloater(name, rect, std::string("Inventory"), RESIZE_YES,
INV_MIN_WIDTH, INV_MIN_HEIGHT, DRAG_ON_TOP,
MINIMIZE_NO, CLOSE_YES),
mActivePanel(NULL)
//LLHandle<LLFloater> mFinderHandle takes care of its own initialization
{
init(inventory);
}
LLInventoryView::LLInventoryView(const std::string& name,
const LLRect& rect,
LLInventoryModel* inventory) :
LLFloater(name, rect, std::string("Inventory"), RESIZE_YES,
INV_MIN_WIDTH, INV_MIN_HEIGHT, DRAG_ON_TOP,
MINIMIZE_NO, CLOSE_YES),
mActivePanel(NULL)
//LLHandle<LLFloater> mFinderHandle takes care of its own initialization
{
init(inventory);
setRect(rect); // override XML
}
void LLInventoryView::init(LLInventoryModel* inventory)
{
// Callbacks
init_inventory_actions(this);
// Controls
addBoolControl("Inventory.ShowFilters", FALSE);
addBoolControl("Inventory.SortByName", FALSE);
addBoolControl("Inventory.SortByDate", TRUE);
addBoolControl("Inventory.FoldersAlwaysByName", TRUE);
addBoolControl("Inventory.SystemFoldersToTop", TRUE);
updateSortControls();
addBoolControl("Inventory.SearchName", TRUE);
addBoolControl("Inventory.SearchDesc", FALSE);
addBoolControl("Inventory.SearchCreator", FALSE);
mSavedFolderState = new LLSaveFolderState();
mSavedFolderState->setApply(FALSE);
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory.xml", NULL);
mFilterTabs = (LLTabContainer*)getChild<LLTabContainer>("inventory filter tabs");
// Set up the default inv. panel/filter settings.
mActivePanel = getChild<LLInventoryPanel>("All Items");
if (mActivePanel)
{
// "All Items" is the previous only view, so it gets the InventorySortOrder
mActivePanel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::DEFAULT_SORT_ORDER));
mActivePanel->getFilter()->markDefault();
mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
mActivePanel->setSelectCallback(onSelectionChange, mActivePanel);
}
LLInventoryPanel* recent_items_panel = getChild<LLInventoryPanel>("Recent Items");
if (recent_items_panel)
{
recent_items_panel->setSinceLogoff(TRUE);
recent_items_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::RECENTITEMS_SORT_ORDER));
recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
recent_items_panel->getFilter()->markDefault();
recent_items_panel->setSelectCallback(onSelectionChange, recent_items_panel);
}
LLInventoryPanel* worn_items_panel = getChild<LLInventoryPanel>("Worn Items");
if (worn_items_panel)
{
worn_items_panel->setSortOrder(gSavedSettings.getU32(LLInventoryPanel::WORNITEMS_SORT_ORDER));
worn_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS);
worn_items_panel->getFilter()->markDefault();
worn_items_panel->setFilterWorn(true);
worn_items_panel->setSelectCallback(onSelectionChange, worn_items_panel);
}
// Now load the stored settings from disk, if available.
std::ostringstream filterSaveName;
filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "filters.xml");
llinfos << "LLInventoryView::init: reading from " << filterSaveName << llendl;
llifstream file(filterSaveName.str());
LLSD savedFilterState;
if (file.is_open())
{
LLSDSerialize::fromXML(savedFilterState, file);
file.close();
// Load the persistent "Recent Items" settings.
// Note that the "All Items" and "Worn Items" settings do not persist per-account.
if(recent_items_panel)
{
if(savedFilterState.has(recent_items_panel->getFilter()->getName()))
{
LLSD recent_items = savedFilterState.get(
recent_items_panel->getFilter()->getName());
recent_items_panel->getFilter()->fromLLSD(recent_items);
}
}
}
mSearchEditor = getChild<LLSearchEditor>("inventory search editor");
if (mSearchEditor)
{
mSearchEditor->setSearchCallback(onSearchEdit, this);
}
mQuickFilterCombo = getChild<LLComboBox>("Quick Filter");
if (mQuickFilterCombo)
{
mQuickFilterCombo->setCommitCallback(onQuickFilterCommit);
}
sActiveViews.put(this);
gInventory.addObserver(this);
}
BOOL LLInventoryView::postBuild()
{
childSetTabChangeCallback("inventory filter tabs", "All Items", onFilterSelected, this);
childSetTabChangeCallback("inventory filter tabs", "Recent Items", onFilterSelected, this);
childSetTabChangeCallback("inventory filter tabs", "Worn Items", onFilterSelected, this);
childSetAction("Inventory.ResetAll",onResetAll,this);
childSetAction("Inventory.ExpandAll",onExpandAll,this);
//panel->getFilter()->markDefault();
return TRUE;
}
// Destroys the object
LLInventoryView::~LLInventoryView( void )
{
// Save the filters state.
LLSD filterRoot;
LLInventoryPanel* all_items_panel = getChild<LLInventoryPanel>("All Items");
if (all_items_panel)
{
LLInventoryFilter* filter = all_items_panel->getFilter();
LLSD filterState;
filter->toLLSD(filterState);
filterRoot[filter->getName()] = filterState;
}
LLInventoryPanel* recent_items_panel = getChild<LLInventoryPanel>("Recent Items");
if (recent_items_panel)
{
LLInventoryFilter* filter = recent_items_panel->getFilter();
LLSD filterState;
filter->toLLSD(filterState);
filterRoot[filter->getName()] = filterState;
}
LLInventoryPanel* worn_items_panel = getChild<LLInventoryPanel>("Worn Items");
if (worn_items_panel)
{
LLInventoryFilter* filter = worn_items_panel->getFilter();
LLSD filterState;
filter->toLLSD(filterState);
filterRoot[filter->getName()] = filterState;
}
std::ostringstream filterSaveName;
filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "filters.xml");
llofstream filtersFile(filterSaveName.str());
if(!LLSDSerialize::toPrettyXML(filterRoot, filtersFile))
{
llwarns << "Could not write to filters save file " << filterSaveName << llendl;
}
else
filtersFile.close();
sActiveViews.removeObj(this);
gInventory.removeObserver(this);
delete mSavedFolderState;
}
void LLInventoryView::draw()
{
if (LLInventoryModel::isEverythingFetched())
{
LLLocale locale(LLLocale::USER_LOCALE);
std::ostringstream title;
title << "Inventory";
std::string item_count_string;
LLResMgr::getInstance()->getIntegerString(item_count_string, gInventory.getItemCount());
title << " (" << item_count_string << " items)";
title << mFilterText;
setTitle(title.str());
}
if (mActivePanel && mSearchEditor)
{
mSearchEditor->setText(mActivePanel->getFilterSubString());
}
if (mActivePanel && mQuickFilterCombo)
{
refreshQuickFilter( mQuickFilterCombo );
}
LLFloater::draw();
}
void LLOpenFilteredFolders::doItem(LLFolderViewItem *item)
{
if (item->getFiltered())
{
item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
}
}
void LLOpenFilteredFolders::doFolder(LLFolderViewFolder* folder)
{
if (folder->getFiltered() && folder->getParentFolder())
{
folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
}
// if this folder didn't pass the filter, and none of its descendants did
else if (!folder->getFiltered() && !folder->hasFilteredDescendants())
{
folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO);
}
}
void LLSelectFirstFilteredItem::doItem(LLFolderViewItem *item)
{
if (item->getFiltered() && !mItemSelected)
{
item->getRoot()->setSelection(item, FALSE, FALSE);
if (item->getParentFolder())
{
item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
}
item->getRoot()->scrollToShowSelection();
mItemSelected = TRUE;
}
}
void LLSelectFirstFilteredItem::doFolder(LLFolderViewFolder* folder)
{
if (folder->getFiltered() && !mItemSelected)
{
folder->getRoot()->setSelection(folder, FALSE, FALSE);
if (folder->getParentFolder())
{
folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
}
folder->getRoot()->scrollToShowSelection();
mItemSelected = TRUE;
}
}
void LLOpenFoldersWithSelection::doItem(LLFolderViewItem *item)
{
if (item->getParentFolder() && item->isSelected())
{
item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
}
}
void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder)
{
if (folder->getParentFolder() && folder->isSelected())
{
folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
}
}
void LLInventoryView::startSearch()
{
// this forces focus to line editor portion of search editor
if (mSearchEditor)
{
mSearchEditor->focusFirstItem(TRUE);
}
}
// virtual, from LLView
void LLInventoryView::setVisible( BOOL visible )
{
gSavedSettings.setBOOL("ShowInventory", visible);
LLFloater::setVisible(visible);
}
// Destroy all but the last floater, which is made invisible.
void LLInventoryView::onClose(bool app_quitting)
{
// S32 count = sActiveViews.count();
// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g)
// See LLInventoryView::closeAll() on why we're doing it this way
S32 count = 0;
for (S32 idx = 0, cnt = sActiveViews.count(); idx < cnt; idx++)
{
if (!sActiveViews.get(idx)->isDead())
count++;
}
// [/RLVa:KB]
if (count > 1)
{
destroy();
}
else
{
if (!app_quitting)
{
gSavedSettings.setBOOL("ShowInventory", FALSE);
}
// clear filters, but save user's folder state first
if (!mActivePanel->getRootFolder()->isFilterModified())
{
mSavedFolderState->setApply(FALSE);
mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState);
}
// onClearSearch(this);
// pass up
LLFloater::setVisible(FALSE);
}
}
BOOL LLInventoryView::handleKeyHere(KEY key, MASK mask)
{
LLFolderView* root_folder = mActivePanel ? mActivePanel->getRootFolder() : NULL;
if (root_folder)
{
// first check for user accepting current search results
if (mSearchEditor
&& mSearchEditor->hasFocus()
&& (key == KEY_RETURN
|| key == KEY_DOWN)
&& mask == MASK_NONE)
{
// move focus to inventory proper
root_folder->setFocus(TRUE);
root_folder->scrollToShowSelection();
return TRUE;
}
if (root_folder->hasFocus() && key == KEY_UP)
{
startSearch();
}
}
return LLFloater::handleKeyHere(key, mask);
}
void LLInventoryView::changed(U32 mask)
{
std::ostringstream title;
title << "Inventory";
if (LLInventoryModel::backgroundFetchActive())
{
LLLocale locale(LLLocale::USER_LOCALE);
std::string item_count_string;
LLResMgr::getInstance()->getIntegerString(item_count_string, gInventory.getItemCount());
title << " (Fetched " << item_count_string << " items...)";
}
title << mFilterText;
setTitle(title.str());
}
// static
// *TODO: remove take_keyboard_focus param
LLInventoryView* LLInventoryView::showAgentInventory(BOOL take_keyboard_focus)
{
if (gDisconnected || gNoRender)
{
return NULL;
}
// [RLVa:KB] - Checked: 2009-07-10 (RLVa-1.0.0g)
if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWINV))
{
return NULL;
}
// [/RLVa:KB]
LLInventoryView* iv = LLInventoryView::getActiveInventory();
#if 0 && !LL_RELEASE_FOR_DOWNLOAD
if (sActiveViews.count() == 1)
{
delete iv;
iv = NULL;
}
#endif
if(!iv && !gAgent.cameraMouselook())
{
// create one.
iv = new LLInventoryView(std::string("Inventory"),
std::string("FloaterInventoryRect"),
&gInventory);
iv->open();
// keep onscreen
gFloaterView->adjustToFitScreen(iv, FALSE);
gSavedSettings.setBOOL("ShowInventory", TRUE);
}
if(iv)
{
// Make sure it's in front and it makes a noise
iv->setTitle(std::string("Inventory"));
iv->open(); /*Flawfinder: ignore*/
}
//if (take_keyboard_focus)
//{
// iv->startSearch();
// gFocusMgr.triggerFocusFlash();
//}
return iv;
}
// static
LLInventoryView* LLInventoryView::getActiveInventory()
{
LLInventoryView* iv = NULL;
S32 count = sActiveViews.count();
if(count > 0)
{
iv = sActiveViews.get(0);
S32 z_order = gFloaterView->getZOrder(iv);
S32 z_next = 0;
LLInventoryView* next_iv = NULL;
for(S32 i = 1; i < count; ++i)
{
next_iv = sActiveViews.get(i);
z_next = gFloaterView->getZOrder(next_iv);
if(z_next < z_order)
{
iv = next_iv;
z_order = z_next;
}
}
}
return iv;
}
// static
void LLInventoryView::toggleVisibility()
{
S32 count = sActiveViews.count();
if (0 == count)
{
showAgentInventory(TRUE);
}
else if (1 == count)
{
if (sActiveViews.get(0)->getVisible())
{
sActiveViews.get(0)->close();
gSavedSettings.setBOOL("ShowInventory", FALSE);
}
else
{
showAgentInventory(TRUE);
}
}
else
{
// With more than one open, we know at least one
// is visible.
// Close all the last one spawned.
S32 last_index = sActiveViews.count() - 1;
sActiveViews.get(last_index)->close();
}
}
// static
void LLInventoryView::cleanup()
{
S32 count = sActiveViews.count();
for (S32 i = 0; i < count; i++)
{
sActiveViews.get(i)->destroy();
}
}
void LLInventoryView::toggleFindOptions()
{
LLFloater *floater = getFinder();
if (!floater)
{
LLInventoryViewFinder * finder = new LLInventoryViewFinder(std::string("Inventory Finder"),
LLRect(getRect().mLeft - INV_FINDER_WIDTH, getRect().mTop, getRect().mLeft, getRect().mTop - INV_FINDER_HEIGHT),
this);
mFinderHandle = finder->getHandle();
finder->open(); /*Flawfinder: ignore*/
addDependentFloater(mFinderHandle);
// start background fetch of folders
gInventory.startBackgroundFetch();
mFloaterControls[std::string("Inventory.ShowFilters")]->setValue(TRUE);
}
else
{
floater->close();
mFloaterControls[std::string("Inventory.ShowFilters")]->setValue(FALSE);
}
}
void LLInventoryView::updateSortControls()
{
U32 order = mActivePanel ? mActivePanel->getSortOrder() : gSavedSettings.getU32("InventorySortOrder");
bool sort_by_date = order & LLInventoryFilter::SO_DATE;
bool folders_by_name = order & LLInventoryFilter::SO_FOLDERS_BY_NAME;
bool sys_folders_on_top = order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP;
getControl("Inventory.SortByDate")->setValue(sort_by_date);
getControl("Inventory.SortByName")->setValue(!sort_by_date);
getControl("Inventory.FoldersAlwaysByName")->setValue(folders_by_name);
getControl("Inventory.SystemFoldersToTop")->setValue(sys_folders_on_top);
}
// static
BOOL LLInventoryView::filtersVisible(void* user_data)
{
LLInventoryView* self = (LLInventoryView*)user_data;
if(!self) return FALSE;
return self->getFinder() != NULL;
}
// static
void LLInventoryView::onClearSearch(void* user_data)
{
LLInventoryView* self = (LLInventoryView*)user_data;
if(!self) return;
LLFloater *finder = self->getFinder();
if (self->mActivePanel)
{
self->mActivePanel->setFilterSubString(LLStringUtil::null);
self->mActivePanel->setFilterTypes(0xffffffff);
}
if (finder)
{
LLInventoryViewFinder::selectAllTypes(finder);
}
// re-open folders that were initially open
if (self->mActivePanel)
{
self->mSavedFolderState->setApply(TRUE);
self->mActivePanel->getRootFolder()->applyFunctorRecursively(*self->mSavedFolderState);
LLOpenFoldersWithSelection opener;
self->mActivePanel->getRootFolder()->applyFunctorRecursively(opener);
self->mActivePanel->getRootFolder()->scrollToShowSelection();
}
}
//static
void LLInventoryView::onSearchEdit(const std::string& search_string, void* user_data )
{
if (search_string == "")
{
onClearSearch(user_data);
}
LLInventoryView* self = (LLInventoryView*)user_data;
if (!self->mActivePanel)
{
return;
}
gInventory.startBackgroundFetch();
std::string filter_text = search_string;
std::string uppercase_search_string = filter_text;
LLStringUtil::toUpper(uppercase_search_string);
if (self->mActivePanel->getFilterSubString().empty() && uppercase_search_string.empty())
{
// current filter and new filter empty, do nothing
return;
}
// save current folder open state if no filter currently applied
if (!self->mActivePanel->getRootFolder()->isFilterModified())
{
self->mSavedFolderState->setApply(FALSE);
self->mActivePanel->getRootFolder()->applyFunctorRecursively(*self->mSavedFolderState);
}
// set new filter string
self->mActivePanel->setFilterSubString(uppercase_search_string);
}
//static
void LLInventoryView::onQuickFilterCommit(LLUICtrl* ctrl, void* user_data)
{
LLComboBox* quickfilter = (LLComboBox*)ctrl;
LLInventoryView* view = (LLInventoryView*)(quickfilter->getParent());
if (!view->mActivePanel)
{
return;
}
std::string item_type = quickfilter->getSimple();
U32 filter_type;
if (view->getString("filter_type_animation") == item_type)
{
filter_type = 0x1 << LLInventoryType::IT_ANIMATION;
}
else if (view->getString("filter_type_callingcard") == item_type)
{
filter_type = 0x1 << LLInventoryType::IT_CALLINGCARD;
}
else if (view->getString("filter_type_wearable") == item_type)
{
filter_type = 0x1 << LLInventoryType::IT_WEARABLE;
}
else if (view->getString("filter_type_gesture") == item_type)
{
filter_type = 0x1 << LLInventoryType::IT_GESTURE;
}
else if (view->getString("filter_type_landmark") == item_type)
{
filter_type = 0x1 << LLInventoryType::IT_LANDMARK;
}
else if (view->getString("filter_type_notecard") == item_type)
{
filter_type = 0x1 << LLInventoryType::IT_NOTECARD;
}
else if (view->getString("filter_type_object") == item_type)
{
filter_type = 0x1 << LLInventoryType::IT_OBJECT;
}
else if (view->getString("filter_type_script") == item_type)
{
filter_type = 0x1 << LLInventoryType::IT_LSL;
}
else if (view->getString("filter_type_sound") == item_type)
{
filter_type = 0x1 << LLInventoryType::IT_SOUND;
}
else if (view->getString("filter_type_texture") == item_type)
{
filter_type = 0x1 << LLInventoryType::IT_TEXTURE;
}
else if (view->getString("filter_type_snapshot") == item_type)
{
filter_type = 0x1 << LLInventoryType::IT_SNAPSHOT;
}
else if (view->getString("filter_type_custom") == item_type)
{
// When they select custom, show the floater then return
if( !(view->filtersVisible(view)) )
{
view->toggleFindOptions();
}
return;
}
else if (view->getString("filter_type_all") == item_type)
{
// Show all types
filter_type = 0xffffffff;
}
else
{
llwarns << "Ignoring unknown filter: " << item_type << llendl;
return;
}
view->mActivePanel->setFilterTypes( filter_type );
// Force the filters window to update itself, if it's open.
LLInventoryViewFinder* finder = view->getFinder();
if( finder )
{
finder->updateElementsFromFilter();
}
// llinfos << "Quick Filter: " << item_type << llendl;
}
//static
void LLInventoryView::refreshQuickFilter(LLUICtrl* ctrl)
{
LLInventoryView* view = (LLInventoryView*)(ctrl->getParent());
if (!view->mActivePanel)
{
return;
}
LLComboBox* quickfilter = view->getChild<LLComboBox>("Quick Filter");
if (!quickfilter)
{
return;
}
U32 filter_type = view->mActivePanel->getFilterTypes();
// Mask to extract only the bit fields we care about.
// *TODO: There's probably a cleaner way to construct this mask.
U32 filter_mask = 0;
filter_mask |= (0x1 << LLInventoryType::IT_ANIMATION);
filter_mask |= (0x1 << LLInventoryType::IT_CALLINGCARD);
filter_mask |= (0x1 << LLInventoryType::IT_WEARABLE);
filter_mask |= (0x1 << LLInventoryType::IT_GESTURE);
filter_mask |= (0x1 << LLInventoryType::IT_LANDMARK);
filter_mask |= (0x1 << LLInventoryType::IT_NOTECARD);
filter_mask |= (0x1 << LLInventoryType::IT_OBJECT);
filter_mask |= (0x1 << LLInventoryType::IT_LSL);
filter_mask |= (0x1 << LLInventoryType::IT_SOUND);
filter_mask |= (0x1 << LLInventoryType::IT_TEXTURE);
filter_mask |= (0x1 << LLInventoryType::IT_SNAPSHOT);
filter_type &= filter_mask;
//llinfos << "filter_type: " << filter_type << llendl;
std::string selection;
if (filter_type == filter_mask)
{
selection = view->getString("filter_type_all");
}
else if (filter_type == (0x1 << LLInventoryType::IT_ANIMATION))
{
selection = view->getString("filter_type_animation");
}
else if (filter_type == (0x1 << LLInventoryType::IT_CALLINGCARD))
{
selection = view->getString("filter_type_callingcard");
}
else if (filter_type == (0x1 << LLInventoryType::IT_WEARABLE))
{
selection = view->getString("filter_type_wearable");
}
else if (filter_type == (0x1 << LLInventoryType::IT_GESTURE))
{
selection = view->getString("filter_type_gesture");
}
else if (filter_type == (0x1 << LLInventoryType::IT_LANDMARK))
{
selection = view->getString("filter_type_landmark");
}
else if (filter_type == (0x1 << LLInventoryType::IT_NOTECARD))
{
selection = view->getString("filter_type_notecard");
}
else if (filter_type == (0x1 << LLInventoryType::IT_OBJECT))
{
selection = view->getString("filter_type_object");
}
else if (filter_type == (0x1 << LLInventoryType::IT_LSL))
{
selection = view->getString("filter_type_script");
}
else if (filter_type == (0x1 << LLInventoryType::IT_SOUND))
{
selection = view->getString("filter_type_sound");
}
else if (filter_type == (0x1 << LLInventoryType::IT_TEXTURE))
{
selection = view->getString("filter_type_texture");
}
else if (filter_type == (0x1 << LLInventoryType::IT_SNAPSHOT))
{
selection = view->getString("filter_type_snapshot");
}
else
{
selection = view->getString("filter_type_custom");
}
// Select the chosen item by label text
BOOL result = quickfilter->setSimple( (selection) );
if( !result )
{
llinfos << "The item didn't exist: " << selection << llendl;
}
}
// static
// BOOL LLInventoryView::incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward)
// {
// LLInventoryView* active_view = NULL;
// for (S32 i = 0; i < sActiveViews.count(); i++)
// {
// if (gFocusMgr.childHasKeyboardFocus(sActiveViews[i]))
// {
// active_view = sActiveViews[i];
// break;
// }
// }
// if (!active_view)
// {
// return FALSE;
// }
// std::string search_string(find_text);
// if (search_string.empty())
// {
// return FALSE;
// }
// if (active_view->mActivePanel &&
// active_view->mActivePanel->getRootFolder()->search(first_item, search_string, backward))
// {
// return TRUE;
// }
// return FALSE;
// }
void LLInventoryView::onResetAll(void* userdata)
{
LLInventoryView* self = (LLInventoryView*) userdata;
self->mActivePanel = (LLInventoryPanel*)self->childGetVisibleTab("inventory filter tabs");
if (!self->mActivePanel)
{
return;
}
if (self->mActivePanel && self->mSearchEditor)
{
self->mSearchEditor->setText(LLStringUtil::null);
}
self->onSearchEdit("",userdata);
self->mActivePanel->closeAllFolders();
}
//static
void LLInventoryView::onExpandAll(void* userdata)
{
LLInventoryView* self = (LLInventoryView*) userdata;
self->mActivePanel = (LLInventoryPanel*)self->childGetVisibleTab("inventory filter tabs");
if (!self->mActivePanel)
{
return;
}
self->mActivePanel->openAllFolders();
}
//static
void LLInventoryView::onFilterSelected(void* userdata, bool from_click)
{
LLInventoryView* self = (LLInventoryView*) userdata;
LLInventoryFilter* filter;
LLInventoryViewFinder *finder = self->getFinder();
// Find my index
self->mActivePanel = (LLInventoryPanel*)self->childGetVisibleTab("inventory filter tabs");
if (!self->mActivePanel)
{
return;
}
filter = self->mActivePanel->getFilter();
if (finder)
{
finder->changeFilter(filter);
}
if (filter->isActive())
{
// If our filter is active we may be the first thing requiring a fetch so we better start it here.
gInventory.startBackgroundFetch();
}
self->setFilterTextFromFilter();
self->updateSortControls();
}
// static
void LLInventoryView::onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action, void* data)
{
LLInventoryPanel* panel = (LLInventoryPanel*)data;
LLFolderView* fv = panel->getRootFolder();
if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename
{
fv->setNeedsAutoRename(FALSE);
if (items.size()) // new asset is visible and selected
{
fv->startRenamingSelectedItem();
}
}
}
BOOL LLInventoryView::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg)
{
// Check to see if we are auto scrolling from the last frame
LLInventoryPanel* panel = (LLInventoryPanel*)this->getActivePanel();
BOOL needsToScroll = panel->getScrollableContainer()->needsToScroll(x, y, LLScrollableContainerView::VERTICAL);
if(mFilterTabs)
{
if(needsToScroll)
{
mFilterTabs->startDragAndDropDelayTimer();
}
}
BOOL handled = LLFloater::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
return handled;
}
std::string get_item_icon_name(LLAssetType::EType asset_type,
LLInventoryType::EType inventory_type,
U32 attachment_point,
BOOL item_is_multi )
{
EInventoryIcon idx = OBJECT_ICON_NAME;
if ( item_is_multi )
{
idx = OBJECT_MULTI_ICON_NAME;
}
switch(asset_type)
{
case LLAssetType::AT_TEXTURE:
if(LLInventoryType::IT_SNAPSHOT == inventory_type)
{
idx = SNAPSHOT_ICON_NAME;
}
else
{
idx = TEXTURE_ICON_NAME;
}
break;
case LLAssetType::AT_SOUND:
idx = SOUND_ICON_NAME;
break;
case LLAssetType::AT_CALLINGCARD:
if(attachment_point!= 0)
{
idx = CALLINGCARD_ONLINE_ICON_NAME;
}
else
{
idx = CALLINGCARD_OFFLINE_ICON_NAME;
}
break;
case LLAssetType::AT_LANDMARK:
if(attachment_point!= 0)
{
idx = LANDMARK_VISITED_ICON_NAME;
}
else
{
idx = LANDMARK_ICON_NAME;
}
break;
case LLAssetType::AT_SCRIPT:
case LLAssetType::AT_LSL_TEXT:
case LLAssetType::AT_LSL_BYTECODE:
idx = SCRIPT_ICON_NAME;
break;
case LLAssetType::AT_CLOTHING:
idx = CLOTHING_ICON_NAME;
case LLAssetType::AT_BODYPART :
if(LLAssetType::AT_BODYPART == asset_type)
{
idx = BODYPART_ICON_NAME;
}
switch(LLInventoryItem::II_FLAGS_WEARABLES_MASK & attachment_point)
{
case WT_SHAPE:
idx = BODYPART_SHAPE_ICON_NAME;
break;
case WT_SKIN:
idx = BODYPART_SKIN_ICON_NAME;
break;
case WT_HAIR:
idx = BODYPART_HAIR_ICON_NAME;
break;
case WT_EYES:
idx = BODYPART_EYES_ICON_NAME;
break;
case WT_SHIRT:
idx = CLOTHING_SHIRT_ICON_NAME;
break;
case WT_PANTS:
idx = CLOTHING_PANTS_ICON_NAME;
break;
case WT_SHOES:
idx = CLOTHING_SHOES_ICON_NAME;
break;
case WT_SOCKS:
idx = CLOTHING_SOCKS_ICON_NAME;
break;
case WT_JACKET:
idx = CLOTHING_JACKET_ICON_NAME;
break;
case WT_GLOVES:
idx = CLOTHING_GLOVES_ICON_NAME;
break;
case WT_UNDERSHIRT:
idx = CLOTHING_UNDERSHIRT_ICON_NAME;
break;
case WT_UNDERPANTS:
idx = CLOTHING_UNDERPANTS_ICON_NAME;
break;
case WT_SKIRT:
idx = CLOTHING_SKIRT_ICON_NAME;
break;
case WT_ALPHA:
idx = CLOTHING_ALPHA_ICON_NAME;
break;
case WT_TATTOO:
idx = CLOTHING_TATTOO_ICON_NAME;
break;
default:
// no-op, go with choice above
break;
}
break;
case LLAssetType::AT_NOTECARD:
idx = NOTECARD_ICON_NAME;
break;
case LLAssetType::AT_ANIMATION:
idx = ANIMATION_ICON_NAME;
break;
case LLAssetType::AT_GESTURE:
idx = GESTURE_ICON_NAME;
break;
default:
break;
}
return ICON_NAME[idx];
}
LLUIImagePtr get_item_icon(LLAssetType::EType asset_type,
LLInventoryType::EType inventory_type,
U32 attachment_point,
BOOL item_is_multi)
{
const std::string& icon_name = get_item_icon_name(asset_type, inventory_type, attachment_point, item_is_multi );
return LLUI::getUIImage(icon_name);
}
const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder");
const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder");
const std::string LLInventoryPanel::WORNITEMS_SORT_ORDER = std::string("WornItemsSortOrder");
const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string("");
LLInventoryPanel::LLInventoryPanel(const std::string& name,
const std::string& sort_order_setting,
const LLRect& rect,
LLInventoryModel* inventory,
BOOL allow_multi_select,
LLView *parent_view) :
LLPanel(name, rect, TRUE),
mInventory(inventory),
mInventoryObserver(NULL),
mFolders(NULL),
mScroller(NULL),
mAllowMultiSelect(allow_multi_select),
mSortOrderSetting(sort_order_setting)
{
setBackgroundColor(gColors.getColor("InventoryBackgroundColor"));
setBackgroundVisible(TRUE);
setBackgroundOpaque(TRUE);
}
BOOL LLInventoryPanel::postBuild()
{
init_inventory_panel_actions(this);
LLRect folder_rect(0,
0,
getRect().getWidth(),
0);
mFolders = new LLFolderView(getName(), NULL, folder_rect, LLUUID::null, this);
mFolders->setAllowMultiSelect(mAllowMultiSelect);
// scroller
LLRect scroller_view_rect = getRect();
scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
mScroller = new LLScrollableContainerView(std::string("Inventory Scroller"),
scroller_view_rect,
mFolders);
mScroller->setFollowsAll();
mScroller->setReserveScrollCorner(TRUE);
addChild(mScroller);
mFolders->setScrollContainer(mScroller);
// set up the callbacks from the inventory we're viewing, and then
// build everything.
mInventoryObserver = new LLInventoryPanelObserver(this);
mInventory->addObserver(mInventoryObserver);
rebuildViewsFor(LLUUID::null, LLInventoryObserver::ADD);
// bit of a hack to make sure the inventory is open.
mFolders->openFolder(std::string("My Inventory"));
if (mSortOrderSetting != INHERIT_SORT_ORDER)
{
setSortOrder(gSavedSettings.getU32(mSortOrderSetting));
}
else
{
setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER));
}
mFolders->setSortOrder(mFolders->getFilter()->getSortOrder());
return TRUE;
}
LLInventoryPanel::~LLInventoryPanel()
{
// should this be a global setting?
U32 sort_order = mFolders->getSortOrder();
if (mSortOrderSetting != INHERIT_SORT_ORDER)
{
gSavedSettings.setU32(mSortOrderSetting, sort_order);
}
// LLView destructor will take care of the sub-views.
mInventory->removeObserver(mInventoryObserver);
delete mInventoryObserver;
mScroller = NULL;
}
// virtual
LLXMLNodePtr LLInventoryPanel::getXML(bool save_children) const
{
LLXMLNodePtr node = LLPanel::getXML(false); // Do not print out children
node->setName(LL_INVENTORY_PANEL_TAG);
node->createChild("allow_multi_select", TRUE)->setBoolValue(mFolders->getAllowMultiSelect());
return node;
}
LLView* LLInventoryPanel::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory)
{
LLInventoryPanel* panel;
std::string name("inventory_panel");
node->getAttributeString("name", name);
BOOL allow_multi_select = TRUE;
node->getAttributeBOOL("allow_multi_select", allow_multi_select);
LLRect rect;
createRect(node, rect, parent, LLRect());
std::string sort_order(INHERIT_SORT_ORDER);
node->getAttributeString("sort_order", sort_order);
panel = new LLInventoryPanel(name, sort_order,
rect, &gInventory,
allow_multi_select, parent);
panel->initFromXML(node, parent);
panel->postBuild();
return panel;
}
void LLInventoryPanel::draw()
{
// select the desired item (in case it wasn't loaded when the selection was requested)
if (mSelectThisID.notNull())
{
setSelection(mSelectThisID, false);
}
LLPanel::draw();
}
void LLInventoryPanel::setFilterTypes(U32 filter_types)
{
mFolders->getFilter()->setFilterTypes(filter_types);
}
void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask)
{
mFolders->getFilter()->setFilterPermissions(filter_perm_mask);
}
void LLInventoryPanel::setFilterSubString(const std::string& string)
{
mFolders->getFilter()->setFilterSubString(string);
}
void LLInventoryPanel::setFilterWorn(bool worn)
{
mFolders->getFilter()->setFilterWorn(worn);
}
void LLInventoryPanel::setSortOrder(U32 order)
{
mFolders->getFilter()->setSortOrder(order);
if (mFolders->getFilter()->isModified())
{
mFolders->setSortOrder(order);
// try to keep selection onscreen, even if it wasn't to start with
mFolders->scrollToShowSelection();
}
}
void LLInventoryPanel::setSinceLogoff(BOOL sl)
{
mFolders->getFilter()->setDateRangeLastLogoff(sl);
}
void LLInventoryPanel::setHoursAgo(U32 hours)
{
mFolders->getFilter()->setHoursAgo(hours);
}
void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show)
{
mFolders->getFilter()->setShowFolderState(show);
}
LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState()
{
return mFolders->getFilter()->getShowFolderState();
}
void LLInventoryPanel::modelChanged(U32 mask)
{
LLFastTimer t2(LLFastTimer::FTM_REFRESH);
bool handled = false;
if(mask & LLInventoryObserver::LABEL)
{
handled = true;
// label change - empty out the display name for each object
// in this change set.
const std::set<LLUUID>& changed_items = gInventory.getChangedIDs();
std::set<LLUUID>::const_iterator id_it = changed_items.begin();
std::set<LLUUID>::const_iterator id_end = changed_items.end();
LLFolderViewItem* view = NULL;
LLInvFVBridge* bridge = NULL;
for (;id_it != id_end; ++id_it)
{
view = mFolders->getItemByID(*id_it);
if(view)
{
// request refresh on this item (also flags for filtering)
bridge = (LLInvFVBridge*)view->getListener();
if(bridge)
{ // Clear the display name first, so it gets properly re-built during refresh()
bridge->clearDisplayName();
}
view->refresh();
}
}
}
if((mask & (LLInventoryObserver::STRUCTURE
| LLInventoryObserver::ADD
| LLInventoryObserver::REMOVE)) != 0)
{
handled = true;
// Record which folders are open by uuid.
LLInventoryModel* model = getModel();
if (model)
{
const std::set<LLUUID>& changed_items = gInventory.getChangedIDs();
std::set<LLUUID>::const_iterator id_it = changed_items.begin();
std::set<LLUUID>::const_iterator id_end = changed_items.end();
for (;id_it != id_end; ++id_it)
{
// sync view with model
LLInventoryObject* model_item = model->getObject(*id_it);
LLFolderViewItem* view_item = mFolders->getItemByID(*id_it);
if (model_item)
{
if (!view_item)
{
// this object was just created, need to build a view for it
if ((mask & LLInventoryObserver::ADD) != LLInventoryObserver::ADD)
{
llwarns << *id_it << " is in model but not in view, but ADD flag not set" << llendl;
}
buildNewViews(*id_it);
// select any newly created object
// that has the auto rename at top of folder
// root set
if(mFolders->getRoot()->needsAutoRename())
{
setSelection(*id_it, FALSE);
}
}
else
{
// this object was probably moved, check its parent
if ((mask & LLInventoryObserver::STRUCTURE) != LLInventoryObserver::STRUCTURE)
{
llwarns << *id_it << " is in model and in view, but STRUCTURE flag not set" << llendl;
}
LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolders->getItemByID(model_item->getParentUUID());
if (new_parent)
{
if (view_item->getParentFolder() != new_parent)
{
view_item->getParentFolder()->extractItem(view_item);
view_item->addToFolder(new_parent, mFolders);
}
}
else
{
llwarns << model_item->getParentUUID() << ": parent folder gone !" << llendl;
}
}
}
else
{
if (view_item)
{
if ((mask & LLInventoryObserver::REMOVE) != LLInventoryObserver::REMOVE)
{
llwarns << *id_it << " is not in model but in view, but REMOVE flag not set" << llendl;
}
// item in view but not model, need to delete view
view_item->destroyView();
}
else
{
llwarns << *id_it << ": Item does not exist in either view or model, but notification triggered" << llendl;
}
}
}
}
}
if (!handled)
{
// it's a small change that only requires a refresh.
// *TODO: figure out a more efficient way to do the refresh
// since it is expensive on large inventories
mFolders->refresh();
}
}
void LLInventoryPanel::rebuildViewsFor(const LLUUID& id, U32 mask)
{
LLFolderViewItem* old_view = NULL;
// get old LLFolderViewItem
old_view = mFolders->getItemByID(id);
if (old_view && id.notNull())
{
old_view->destroyView();
}
buildNewViews(id);
}
void LLInventoryPanel::buildNewViews(const LLUUID& id)
{
LLFolderViewItem* itemp = NULL;
LLInventoryObject* objectp = gInventory.getObject(id);
if (objectp)
{
if (objectp->getType() <= LLAssetType::AT_NONE ||
objectp->getType() >= LLAssetType::AT_COUNT)
{
llwarns << "LLInventoryPanel::buildNewViews called with objectp->mType == "
<< ((S32) objectp->getType())
<< " (shouldn't happen)" << llendl;
}
else if ((objectp->getType() == LLAssetType::AT_CATEGORY) &&
(objectp->getActualType() != LLAssetType::AT_LINK_FOLDER)) // build new view for category
{
LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(),
objectp->getType(),
LLInventoryType::IT_CATEGORY,
this,
objectp->getUUID());
if (new_listener)
{
LLFolderViewFolder* folderp = new LLFolderViewFolder(new_listener->getDisplayName(),
new_listener->getIcon(),
mFolders,
new_listener);
folderp->setItemSortOrder(mFolders->getSortOrder());
itemp = folderp;
}
}
else // build new view for item
{
LLInventoryItem* item = (LLInventoryItem*)objectp;
LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(
item->getType(),
item->getActualType(),
item->getInventoryType(),
this,
item->getUUID(),
item->getFlags());
if (new_listener)
{
itemp = new LLFolderViewItem(new_listener->getDisplayName(),
new_listener->getIcon(),
new_listener->getCreationDate(),
mFolders,
new_listener);
}
}
LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolders->getItemByID(objectp->getParentUUID());
if (itemp)
{
if (parent_folder)
{
itemp->addToFolder(parent_folder, mFolders);
}
else
{
llwarns << "Couldn't find parent folder for child " << itemp->getLabel() << llendl;
delete itemp;
}
}
}
if ((id.isNull() ||
(objectp && objectp->getType() == LLAssetType::AT_CATEGORY)))
{
LLViewerInventoryCategory::cat_array_t* categories;
LLViewerInventoryItem::item_array_t* items;
mInventory->lockDirectDescendentArrays(id, categories, items);
if(categories)
{
S32 count = categories->count();
for(S32 i = 0; i < count; ++i)
{
LLInventoryCategory* cat = categories->get(i);
buildNewViews(cat->getUUID());
}
}
if(items)
{
S32 count = items->count();
for(S32 i = 0; i < count; ++i)
{
LLInventoryItem* item = items->get(i);
buildNewViews(item->getUUID());
}
}
mInventory->unlockDirectDescendentArrays(id);
}
}
struct LLConfirmPurgeData
{
LLUUID mID;
LLInventoryModel* mModel;
};
class LLIsNotWorn : public LLInventoryCollectFunctor
{
public:
LLIsNotWorn() {}
virtual ~LLIsNotWorn() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item)
{
return !gAgent.isWearingItem(item->getUUID());
}
};
class LLOpenFolderByID : public LLFolderViewFunctor
{
public:
LLOpenFolderByID(const LLUUID& id) : mID(id) {}
virtual ~LLOpenFolderByID() {}
virtual void doFolder(LLFolderViewFolder* folder)
{
if (folder->getListener() && folder->getListener()->getUUID() == mID) folder->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
}
virtual void doItem(LLFolderViewItem* item) {}
protected:
const LLUUID& mID;
};
void LLInventoryPanel::openSelected()
{
LLFolderViewItem* folder_item = mFolders->getCurSelectedItem();
if(!folder_item) return;
LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener();
if(!bridge) return;
bridge->openItem();
}
BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask)
{
BOOL handled = LLView::handleHover(x, y, mask);
if(handled)
{
ECursorType cursor = getWindow()->getCursor();
if (LLInventoryModel::backgroundFetchActive() && cursor == UI_CURSOR_ARROW)
{
// replace arrow cursor with arrow and hourglass cursor
getWindow()->setCursor(UI_CURSOR_WORKING);
}
}
else
{
getWindow()->setCursor(UI_CURSOR_ARROW);
}
return TRUE;
}
BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
EDragAndDropType cargo_type,
void* cargo_data,
EAcceptance* accept,
std::string& tooltip_msg)
{
BOOL handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
if (handled)
{
mFolders->setDragAndDropThisFrame();
}
return handled;
}
void LLInventoryPanel::openAllFolders()
{
mFolders->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN);
mFolders->arrangeAll();
}
void LLInventoryPanel::closeAllFolders()
{
mFolders->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN);
mFolders->arrangeAll();
}
void LLInventoryPanel::openDefaultFolderForType(LLAssetType::EType type)
{
LLUUID category_id = mInventory->findCategoryUUIDForType(type);
LLOpenFolderByID opener(category_id);
mFolders->applyFunctorRecursively(opener);
}
void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus)
{
LLFolderViewItem* itemp = mFolders->getItemByID(obj_id);
if(itemp && itemp->getListener())
{
itemp->getListener()->arrangeAndSet(itemp, TRUE, take_keyboard_focus);
mSelectThisID.setNull();
return;
}
else
{
// save the desired item to be selected later (if/when ready)
mSelectThisID = obj_id;
}
}
void LLInventoryPanel::clearSelection()
{
mFolders->clearSelection();
mSelectThisID.setNull();
}
void LLInventoryPanel::createNewItem(const std::string& name,
const LLUUID& parent_id,
LLAssetType::EType asset_type,
LLInventoryType::EType inv_type,
U32 next_owner_perm)
{
std::string desc;
LLAssetType::generateDescriptionFor(asset_type, desc);
next_owner_perm = (next_owner_perm) ? next_owner_perm : PERM_MOVE | PERM_TRANSFER;
if (inv_type == LLInventoryType::IT_GESTURE)
{
LLPointer<LLInventoryCallback> cb = new CreateGestureCallback();
create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
parent_id, LLTransactionID::tnull, name, desc, asset_type, inv_type,
NOT_WEARABLE, next_owner_perm, cb);
}
else
{
LLPointer<LLInventoryCallback> cb = NULL;
create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
parent_id, LLTransactionID::tnull, name, desc, asset_type, inv_type,
NOT_WEARABLE, next_owner_perm, cb);
}
}
// static DEBUG ONLY:
void LLInventoryPanel::dumpSelectionInformation(void* user_data)
{
LLInventoryPanel* iv = (LLInventoryPanel*)user_data;
iv->mFolders->dumpSelectionInformation();
}