diff options
Diffstat (limited to 'indra/newview/llinventorypanel.cpp')
-rw-r--r-- | indra/newview/llinventorypanel.cpp | 999 |
1 files changed, 999 insertions, 0 deletions
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp new file mode 100644 index 0000000000..83c2d62ee8 --- /dev/null +++ b/indra/newview/llinventorypanel.cpp @@ -0,0 +1,999 @@ +/* + * @file llinventorypanel.cpp + * @brief Implementation of the inventory panel 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 "llinventorypanel.h" + +#include <utility> // for std::pair<> + +#include "llagent.h" +#include "llagentwearables.h" +#include "llappearancemgr.h" +#include "llfloaterinventory.h" +#include "llfloaterreg.h" +#include "llimfloater.h" +#include "llimview.h" +#include "llinventorybridge.h" +#include "llinventoryfunctions.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llsidepanelinventory.h" +#include "llsidetray.h" +#include "llscrollcontainer.h" +#include "llviewerfoldertype.h" +#include "llvoavatarself.h" + +static LLDefaultChildRegistry::Register<LLInventoryPanel> r("inventory_panel"); + +const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder"); +const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder"); +const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string(""); +static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER; + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInventoryPanelObserver +// +// Bridge to support knowing when the inventory has changed. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInventoryPanelObserver : public LLInventoryObserver +{ +public: + LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {} + virtual ~LLInventoryPanelObserver() {} + virtual void changed(U32 mask) + { + mIP->modelChanged(mask); + } +protected: + LLInventoryPanel* mIP; +}; + +LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) : + LLPanel(p), + mInventoryObserver(NULL), + mFolders(NULL), + mScroller(NULL), + mSortOrderSetting(p.sort_order_setting), + mInventory(p.inventory), + mAllowMultiSelect(p.allow_multi_select), + mViewsInitialized(false), + mStartFolderString(p.start_folder), + mBuildDefaultHierarchy(true), + mInvFVBridgeBuilder(NULL) +{ + mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER; + + // contex menu callbacks + mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2)); + mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH)); + mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND)); + mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLInventoryPanel::doCreate, this, _2)); + mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&LLInventoryPanel::attachObject, this, _2)); + mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this)); + + if (mStartFolderString != "") + { + mBuildDefaultHierarchy = false; + } +} + +BOOL LLInventoryPanel::postBuild() +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_POST_BUILD); + + mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves + + // Create root folder + { + LLRect folder_rect(0, + 0, + getRect().getWidth(), + 0); + LLFolderView::Params p; + p.name = getName(); + p.title = getLabel(); + p.rect = folder_rect; + p.parent_panel = this; + p.tool_tip = p.name; + mFolders = LLUICtrlFactory::create<LLFolderView>(p); + mFolders->setAllowMultiSelect(mAllowMultiSelect); + } + + mCommitCallbackRegistrar.popScope(); + + mFolders->setCallbackRegistrar(&mCommitCallbackRegistrar); + + // Scroller + { + LLRect scroller_view_rect = getRect(); + scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); + LLScrollContainer::Params p; + p.name("Inventory Scroller"); + p.rect(scroller_view_rect); + p.follows.flags(FOLLOWS_ALL); + p.reserve_scroll_corner(true); + p.tab_stop(true); + mScroller = LLUICtrlFactory::create<LLScrollContainer>(p); + addChild(mScroller); + mScroller->addChild(mFolders); + mFolders->setScrollContainer(mScroller); + mFolders->addChild(mFolders->mStatusTextBox); + } + + // Set up the callbacks from the inventory we're viewing, and then build everything. + mInventoryObserver = new LLInventoryPanelObserver(this); + mInventory->addObserver(mInventoryObserver); + + // Build view of inventory if we need default full hierarchy and inventory ready, + // otherwise wait for idle callback. + if (mBuildDefaultHierarchy && mInventory->isInventoryUsable() && !mViewsInitialized) + { + initializeViews(); + } + gIdleCallbacks.addFunction(onIdle, (void*)this); + + if (mSortOrderSetting != INHERIT_SORT_ORDER) + { + setSortOrder(gSavedSettings.getU32(mSortOrderSetting)); + } + else + { + setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER)); + } + mFolders->setSortOrder(getFilter()->getSortOrder()); + + return TRUE; +} + +LLInventoryPanel::~LLInventoryPanel() +{ + if (mFolders) + { + 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; +} + +void LLInventoryPanel::draw() +{ + // Select the desired item (in case it wasn't loaded when the selection was requested) + mFolders->updateSelection(); + LLPanel::draw(); +} + +LLInventoryFilter* LLInventoryPanel::getFilter() +{ + if (mFolders) + { + return mFolders->getFilter(); + } + return NULL; +} + +void LLInventoryPanel::setFilterTypes(U64 types, LLInventoryFilter::EFilterType filter_type) +{ + if (filter_type == LLInventoryFilter::FILTERTYPE_OBJECT) + getFilter()->setFilterObjectTypes(types); + if (filter_type == LLInventoryFilter::FILTERTYPE_CATEGORY) + getFilter()->setFilterCategoryTypes(types); +} + +void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) +{ + getFilter()->setFilterPermissions(filter_perm_mask); +} + +void LLInventoryPanel::setFilterSubString(const std::string& string) +{ + getFilter()->setFilterSubString(string); +} + +void LLInventoryPanel::setSortOrder(U32 order) +{ + getFilter()->setSortOrder(order); + if (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) +{ + getFilter()->setDateRangeLastLogoff(sl); +} + +void LLInventoryPanel::setHoursAgo(U32 hours) +{ + getFilter()->setHoursAgo(hours); +} + +void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show) +{ + getFilter()->setShowFolderState(show); +} + +LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState() +{ + return getFilter()->getShowFolderState(); +} + +void LLInventoryPanel::modelChanged(U32 mask) +{ + static LLFastTimer::DeclareTimer FTM_REFRESH("Inventory Refresh"); + LLFastTimer t2(FTM_REFRESH); + + bool handled = false; + + if (!mViewsInitialized) return; + + const LLInventoryModel* model = getModel(); + if (!model) return; + + const LLInventoryModel::changed_items_t& changed_items = model->getChangedIDs(); + if (changed_items.empty()) return; + + for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin(); + items_iter != changed_items.end(); + ++items_iter) + { + const LLUUID& item_id = (*items_iter); + const LLInventoryObject* model_item = model->getObject(item_id); + LLFolderViewItem* view_item = mFolders->getItemByID(item_id); + LLFolderViewFolder* view_folder = mFolders->getFolderByID(item_id); + + ////////////////////////////// + // LABEL Operation + // Empty out the display name for relabel. + if (mask & LLInventoryObserver::LABEL) + { + handled = true; + if (view_item) + { + // Request refresh on this item (also flags for filtering) + LLInvFVBridge* bridge = (LLInvFVBridge*)view_item->getListener(); + if(bridge) + { // Clear the display name first, so it gets properly re-built during refresh() + bridge->clearDisplayName(); + + view_item->refresh(); + } + } + } + + ////////////////////////////// + // REBUILD Operation + // Destroy and regenerate the UI. + if (mask & LLInventoryObserver::REBUILD) + { + handled = true; + if (model_item && view_item) + { + view_item->destroyView(); + } + buildNewViews(item_id); + } + + ////////////////////////////// + // INTERNAL Operation + // This could be anything. For now, just refresh the item. + if (mask & LLInventoryObserver::INTERNAL) + { + if (view_item) + { + view_item->refresh(); + } + } + + ////////////////////////////// + // SORT Operation + // Sort the folder. + if (mask & LLInventoryObserver::SORT) + { + if (view_folder) + { + view_folder->requestSort(); + } + } + + // We don't typically care which of these masks the item is actually flagged with, since the masks + // may not be accurate (e.g. in the main inventory panel, I move an item from My Inventory into + // Landmarks; this is a STRUCTURE change for that panel but is an ADD change for the Landmarks + // panel). What's relevant is that the item and UI are probably out of sync and thus need to be + // resynchronized. + if (mask & (LLInventoryObserver::STRUCTURE | + LLInventoryObserver::ADD | + LLInventoryObserver::REMOVE)) + { + handled = true; + + ////////////////////////////// + // ADD Operation + // Item exists in memory but a UI element hasn't been created for it. + if (model_item && !view_item) + { + // Add the UI element for this item. + buildNewViews(item_id); + // Select any newly created object that has the auto rename at top of folder root set. + if(mFolders->getRoot()->needsAutoRename()) + { + setSelection(item_id, FALSE); + } + } + + ////////////////////////////// + // STRUCTURE Operation + // This item already exists in both memory and UI. It was probably reparented. + if (model_item && view_item) + { + // Don't process the item if it's hanging from the root, since its + // model_item's parent will be NULL. + if (view_item->getRoot() != view_item->getParent()) + { + LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolders->getItemByID(model_item->getParentUUID()); + // Item has been moved. + if (view_item->getParentFolder() != new_parent) + { + if (new_parent != NULL) + { + // Item is to be moved and we found its new parent in the panel's directory, so move the item's UI. + view_item->getParentFolder()->extractItem(view_item); + view_item->addToFolder(new_parent, mFolders); + } + else + { + // Item is to be moved outside the panel's directory (e.g. moved to trash for a panel that + // doesn't include trash). Just remove the item's UI. + view_item->destroyView(); + } + } + } + } + + ////////////////////////////// + // REMOVE Operation + // This item has been removed from memory, but its associated UI element still exists. + if (!model_item && view_item) + { + // Remove the item's UI. + view_item->destroyView(); + } + } + } +} + +// static +void LLInventoryPanel::onIdle(void *userdata) +{ + if (!gInventory.isInventoryUsable()) + return; + + LLInventoryPanel *self = (LLInventoryPanel*)userdata; + // Inventory just initialized, do complete build + if (!self->mViewsInitialized) + { + self->initializeViews(); + } + if (self->mViewsInitialized) + { + gIdleCallbacks.deleteFunction(onIdle, (void*)self); + } +} + +void LLInventoryPanel::initializeViews() +{ + if (!gInventory.isInventoryUsable()) return; + + // Determine the root folder in case specified, and + // build the views starting with that folder. + const LLFolderType::EType preferred_type = LLViewerFolderType::lookupTypeFromNewCategoryName(mStartFolderString); + + if ("LIBRARY" == mStartFolderString) + { + mStartFolderID = gInventory.getLibraryRootFolderID(); + } + else + { + mStartFolderID = (preferred_type != LLFolderType::FT_NONE ? gInventory.findCategoryUUIDForType(preferred_type) : LLUUID::null); + } + rebuildViewsFor(mStartFolderID); + + mViewsInitialized = true; + + openStartFolderOrMyInventory(); + + // Special case for new user login + if (gAgent.isFirstLogin()) + { + // Auto open the user's library + LLFolderViewFolder* lib_folder = mFolders->getFolderByID(gInventory.getLibraryRootFolderID()); + if (lib_folder) + { + lib_folder->setOpen(TRUE); + } + + // Auto close the user's my inventory folder + LLFolderViewFolder* my_inv_folder = mFolders->getFolderByID(gInventory.getRootFolderID()); + if (my_inv_folder) + { + my_inv_folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); + } + } +} + +void LLInventoryPanel::rebuildViewsFor(const LLUUID& id) +{ + // Destroy the old view for this ID so we can rebuild it. + LLFolderViewItem* old_view = mFolders->getItemByID(id); + if (old_view && id.notNull()) + { + old_view->destroyView(); + } + + buildNewViews(id); +} + +void LLInventoryPanel::buildNewViews(const LLUUID& id) +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_BUILD_NEW_VIEWS); + LLFolderViewItem* itemp = NULL; + LLInventoryObject* objectp = gInventory.getObject(id); + if (objectp) + { + const LLUUID &parent_id = objectp->getParentUUID(); + LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolders->getItemByID(parent_id); + if (id == mStartFolderID) + { + parent_folder = mFolders; + } + else if ((mStartFolderID != LLUUID::null) && (!gInventory.isObjectDescendentOf(id, mStartFolderID))) + { + // This item exists outside the inventory's hierarchy, so don't add it. + return; + } + + if (objectp->getType() <= LLAssetType::AT_NONE || + objectp->getType() >= LLAssetType::AT_COUNT) + { + llwarns << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : " + << ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID() + << llendl; + return; + } + + if ((objectp->getType() == LLAssetType::AT_CATEGORY) && + (objectp->getActualType() != LLAssetType::AT_LINK_FOLDER)) + { + LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(objectp->getType(), + objectp->getType(), + LLInventoryType::IT_CATEGORY, + this, + objectp->getUUID()); + + if (new_listener) + { + LLFolderViewFolder::Params params; + params.name = new_listener->getDisplayName(); + params.icon = new_listener->getIcon(); + params.icon_open = new_listener->getOpenIcon(); + params.root = mFolders; + params.listener = new_listener; + params.tool_tip = params.name; + LLFolderViewFolder* folderp = LLUICtrlFactory::create<LLFolderViewFolder>(params); + folderp->setItemSortOrder(mFolders->getSortOrder()); + itemp = folderp; + + // Hide the root folder, so we can show the contents of a folder flat + // but still have the parent folder present for listener-related operations. + if (id == mStartFolderID) + { + folderp->setHidden(TRUE); + } + const LLViewerInventoryCategory *cat = dynamic_cast<LLViewerInventoryCategory *>(objectp); + if (cat && getIsHiddenFolderType(cat->getPreferredType())) + { + folderp->setHidden(TRUE); + } + } + } + else + { + // Build new view for item. + LLInventoryItem* item = (LLInventoryItem*)objectp; + LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(item->getType(), + item->getActualType(), + item->getInventoryType(), + this, + item->getUUID(), + item->getFlags()); + + if (new_listener) + { + LLFolderViewItem::Params params; + params.name = new_listener->getDisplayName(); + params.icon = new_listener->getIcon(); + params.icon_open = new_listener->getOpenIcon(); + params.creation_date = new_listener->getCreationDate(); + params.root = mFolders; + params.listener = new_listener; + params.rect = LLRect (0, 0, 0, 0); + params.tool_tip = params.name; + itemp = LLUICtrlFactory::create<LLFolderViewItem> (params); + } + } + + if (itemp) + { + itemp->addToFolder(parent_folder, mFolders); + + // Don't add children of hidden folders unless this is the panel's root folder. + if (itemp->getHidden() && (id != mStartFolderID)) + { + return; + } + } + } + + // If this is a folder, add the children of the folder and recursively add any + // child folders. + if ((id == mStartFolderID) || + (objectp && objectp->getType() == LLAssetType::AT_CATEGORY)) + { + LLViewerInventoryCategory::cat_array_t* categories; + LLViewerInventoryItem::item_array_t* items; + mInventory->lockDirectDescendentArrays(id, categories, items); + + if(categories) + { + for (LLViewerInventoryCategory::cat_array_t::const_iterator cat_iter = categories->begin(); + cat_iter != categories->end(); + ++cat_iter) + { + const LLViewerInventoryCategory* cat = (*cat_iter); + buildNewViews(cat->getUUID()); + } + } + + if(items) + { + for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items->begin(); + item_iter != items->end(); + ++item_iter) + { + const LLViewerInventoryItem* item = (*item_iter); + buildNewViews(item->getUUID()); + } + } + mInventory->unlockDirectDescendentArrays(id); + } +} + +// bit of a hack to make sure the inventory is open. +void LLInventoryPanel::openStartFolderOrMyInventory() +{ + if (mStartFolderString != "") + { + mFolders->openFolder(mStartFolderString); + } + else + { + // Find My Inventory folder and open it up by name + for (LLView *child = mFolders->getFirstChild(); child; child = mFolders->findNextSibling(child)) + { + LLFolderViewFolder *fchild = dynamic_cast<LLFolderViewFolder*>(child); + if (fchild && fchild->getListener() && + (fchild->getListener()->getUUID() == gInventory.getRootFolderID())) + { + const std::string& child_name = child->getName(); + mFolders->openFolder(child_name); + break; + } + } + } +} + +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 (LLInventoryModelBackgroundFetch::instance().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 folder view is empty the (x, y) point won't be in its rect + // so the handler must be called explicitly. + if (!mFolders->hasVisibleChildren()) + { + handled = mFolders->handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + } + + if (handled) + { + mFolders->setDragAndDropThisFrame(); + } + + return handled; +} + +// virtual +void LLInventoryPanel::onMouseEnter(S32 x, S32 y, MASK mask) +{ + LLPanel::onMouseEnter(x, y, mask); + // don't auto-scroll a list when cursor is over Inventory. See EXT-3981. + mFolders->setEnableScroll(false); +} + +// virtual +void LLInventoryPanel::onMouseLeave(S32 x, S32 y, MASK mask) +{ + LLPanel::onMouseLeave(x, y, mask); + mFolders->setEnableScroll(true); +} + +void LLInventoryPanel::onFocusLost() +{ + // inventory no longer handles cut/copy/paste/delete + if (LLEditMenuHandler::gEditMenuHandler == mFolders) + { + LLEditMenuHandler::gEditMenuHandler = NULL; + } + + LLPanel::onFocusLost(); +} + +void LLInventoryPanel::onFocusReceived() +{ + // inventory now handles cut/copy/paste/delete + LLEditMenuHandler::gEditMenuHandler = mFolders; + + LLPanel::onFocusReceived(); +} + +void LLInventoryPanel::openAllFolders() +{ + mFolders->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); + mFolders->arrangeAll(); +} + +void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus) +{ + // Don't select objects in COF (e.g. to prevent refocus when items are worn). + const LLInventoryObject *obj = gInventory.getObject(obj_id); + if (obj && obj->getParentUUID() == LLAppearanceMgr::instance().getCOF()) + { + return; + } + mFolders->setSelectionByID(obj_id, take_keyboard_focus); +} + +void LLInventoryPanel::setSelectCallback(const LLFolderView::signal_t::slot_type& cb) +{ + if (mFolders) + { + mFolders->setSelectCallback(cb); + } +} + +void LLInventoryPanel::clearSelection() +{ + mFolders->clearSelection(); +} + +void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& items, BOOL user_action) +{ + LLFolderView* fv = 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(); + } + } + // Seraph - Put determineFolderType in here for ensemble typing? +} + +void LLInventoryPanel::doToSelected(const LLSD& userdata) +{ + mFolders->doToSelected(&gInventory, userdata); +} + +void LLInventoryPanel::doCreate(const LLSD& userdata) +{ + menu_create_inventory_item(mFolders, LLFolderBridge::sSelf, userdata); +} + +bool LLInventoryPanel::beginIMSession() +{ + std::set<LLUUID> selected_items; + mFolders->getSelectionList(selected_items); + + std::string name; + static int session_num = 1; + + LLDynamicArray<LLUUID> members; + EInstantMessage type = IM_SESSION_CONFERENCE_START; + + std::set<LLUUID>::const_iterator iter; + for (iter = selected_items.begin(); iter != selected_items.end(); iter++) + { + + LLUUID item = *iter; + LLFolderViewItem* folder_item = mFolders->getItemByID(item); + + if(folder_item) + { + LLFolderViewEventListener* fve_listener = folder_item->getListener(); + if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY)) + { + + LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getListener(); + if(!bridge) return true; + LLViewerInventoryCategory* cat = bridge->getCategory(); + if(!cat) return true; + name = cat->getName(); + LLUniqueBuddyCollector is_buddy; + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendentsIf(bridge->getUUID(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_buddy); + S32 count = item_array.count(); + if(count > 0) + { + //*TODO by what to replace that? + //LLFloaterReg::showInstance("communicate"); + + // create the session + LLAvatarTracker& at = LLAvatarTracker::instance(); + LLUUID id; + for(S32 i = 0; i < count; ++i) + { + id = item_array.get(i)->getCreatorUUID(); + if(at.isBuddyOnline(id)) + { + members.put(id); + } + } + } + } + else + { + LLFolderViewItem* folder_item = mFolders->getItemByID(item); + if(!folder_item) return true; + LLInvFVBridge* listenerp = (LLInvFVBridge*)folder_item->getListener(); + + if (listenerp->getInventoryType() == LLInventoryType::IT_CALLINGCARD) + { + LLInventoryItem* inv_item = gInventory.getItem(listenerp->getUUID()); + + if (inv_item) + { + LLAvatarTracker& at = LLAvatarTracker::instance(); + LLUUID id = inv_item->getCreatorUUID(); + + if(at.isBuddyOnline(id)) + { + members.put(id); + } + } + } //if IT_CALLINGCARD + } //if !IT_CATEGORY + } + } //for selected_items + + // the session_id is randomly generated UUID which will be replaced later + // with a server side generated number + + if (name.empty()) + { + name = llformat("Session %d", session_num++); + } + + LLUUID session_id = gIMMgr->addSession(name, type, members[0], members); + if (session_id != LLUUID::null) + { + LLIMFloater::show(session_id); + } + + return true; +} + +bool LLInventoryPanel::attachObject(const LLSD& userdata) +{ + std::set<LLUUID> selected_items; + mFolders->getSelectionList(selected_items); + + std::string joint_name = userdata.asString(); + LLViewerJointAttachment* attachmentp = NULL; + for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); + iter != gAgentAvatarp->mAttachmentPoints.end(); ) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if (attachment->getName() == joint_name) + { + attachmentp = attachment; + break; + } + } + if (attachmentp == NULL) + { + return true; + } + + for (std::set<LLUUID>::const_iterator set_iter = selected_items.begin(); + set_iter != selected_items.end(); + ++set_iter) + { + const LLUUID &id = *set_iter; + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(id); + if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID())) + { + rez_attachment(item, attachmentp); + } + else if(item && item->isComplete()) + { + // must be in library. copy it to our inventory and put it on. + LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(attachmentp); + copy_inventory_item(gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + LLUUID::null, + std::string(), + cb); + } + } + gFocusMgr.setKeyboardFocus(NULL); + + return true; +} + +BOOL LLInventoryPanel::getSinceLogoff() +{ + return getFilter()->isSinceLogoff(); +} + +// DEBUG ONLY +// static +void LLInventoryPanel::dumpSelectionInformation(void* user_data) +{ + LLInventoryPanel* iv = (LLInventoryPanel*)user_data; + iv->mFolders->dumpSelectionInformation(); +} + +BOOL is_inventorysp_active() +{ + if (!LLSideTray::getInstance()->isPanelActive("sidepanel_inventory")) return FALSE; + LLSidepanelInventory *inventorySP = dynamic_cast<LLSidepanelInventory *>(LLSideTray::getInstance()->getPanel("sidepanel_inventory")); + if (!inventorySP) return FALSE; + return inventorySP->isMainInventoryPanelActive(); +} + +// static +LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open) +{ + // A. If the inventory side panel is open, use that preferably. + if (is_inventorysp_active()) + { + LLSidepanelInventory *inventorySP = dynamic_cast<LLSidepanelInventory *>(LLSideTray::getInstance()->getPanel("sidepanel_inventory")); + if (inventorySP) + { + return inventorySP->getActivePanel(); + } + } + + // B. Iterate through the inventory floaters and return whichever is on top. + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); + S32 z_min = S32_MAX; + LLInventoryPanel* res = NULL; + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) + { + LLFloaterInventory* iv = dynamic_cast<LLFloaterInventory*>(*iter); + if (iv && iv->getVisible()) + { + S32 z_order = gFloaterView->getZOrder(iv); + if (z_order < z_min) + { + res = iv->getPanel(); + z_min = z_order; + } + } + } + if (res) return res; + + // C. If no panels are open and we don't want to force open a panel, then just abort out. + if (!auto_open) return NULL; + + // D. Open the inventory side panel and use that. + LLSD key; + LLSidepanelInventory *sidepanel_inventory = + dynamic_cast<LLSidepanelInventory *>(LLSideTray::getInstance()->showPanel("sidepanel_inventory", key)); + if (sidepanel_inventory) + { + return sidepanel_inventory->getActivePanel(); + } + + return NULL; +} + +void LLInventoryPanel::addHideFolderType(LLFolderType::EType folder_type) +{ + if (!getIsHiddenFolderType(folder_type)) + { + mHiddenFolderTypes.push_back(folder_type); + } +} + +BOOL LLInventoryPanel::getIsHiddenFolderType(LLFolderType::EType folder_type) const +{ + return (std::find(mHiddenFolderTypes.begin(), mHiddenFolderTypes.end(), folder_type) != mHiddenFolderTypes.end()); +} |