PageRenderTime 111ms CodeModel.GetById 19ms app.highlight 81ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llinventorypanel.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1244 lines | 917 code | 194 blank | 133 comment | 159 complexity | 87378bb3e05079b6d3d7b886bcdb2829 MD5 | raw file
   1/* 
   2 * @file llinventorypanel.cpp
   3 * @brief Implementation of the inventory panel and associated stuff.
   4 *
   5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
   6 * Second Life Viewer Source Code
   7 * Copyright (C) 2010, Linden Research, Inc.
   8 * 
   9 * This library is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU Lesser General Public
  11 * License as published by the Free Software Foundation;
  12 * version 2.1 of the License only.
  13 * 
  14 * This library is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  17 * Lesser General Public License for more details.
  18 * 
  19 * You should have received a copy of the GNU Lesser General Public
  20 * License along with this library; if not, write to the Free Software
  21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  22 * 
  23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  24 * $/LicenseInfo$
  25 */
  26
  27#include "llviewerprecompiledheaders.h"
  28#include "llinventorypanel.h"
  29
  30#include <utility> // for std::pair<>
  31
  32#include "llagent.h"
  33#include "llagentwearables.h"
  34#include "llappearancemgr.h"
  35#include "llavataractions.h"
  36#include "llfloaterinventory.h"
  37#include "llfloaterreg.h"
  38#include "llfloatersidepanelcontainer.h"
  39#include "llfolderview.h"
  40#include "llimfloater.h"
  41#include "llimview.h"
  42#include "llinventorybridge.h"
  43#include "llinventoryfunctions.h"
  44#include "llinventorymodelbackgroundfetch.h"
  45#include "llsidepanelinventory.h"
  46#include "llviewerattachmenu.h"
  47#include "llviewerfoldertype.h"
  48#include "llvoavatarself.h"
  49
  50static LLDefaultChildRegistry::Register<LLInventoryPanel> r("inventory_panel");
  51
  52const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder");
  53const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder");
  54const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string("");
  55static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER;
  56
  57
  58//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  59// Class LLInventoryPanelObserver
  60//
  61// Bridge to support knowing when the inventory has changed.
  62//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  63
  64class LLInventoryPanelObserver : public LLInventoryObserver
  65{
  66public:
  67	LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {}
  68	virtual ~LLInventoryPanelObserver() {}
  69	virtual void changed(U32 mask) 
  70	{
  71		mIP->modelChanged(mask);
  72	}
  73protected:
  74	LLInventoryPanel* mIP;
  75};
  76
  77//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  78// Class LLInvPanelComplObserver
  79//
  80// Calls specified callback when all specified items become complete.
  81//
  82// Usage:
  83// observer = new LLInvPanelComplObserver(boost::bind(onComplete));
  84// inventory->addObserver(observer);
  85// observer->reset(); // (optional)
  86// observer->watchItem(incomplete_item1_id);
  87// observer->watchItem(incomplete_item2_id);
  88//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  89
  90class LLInvPanelComplObserver : public LLInventoryCompletionObserver
  91{
  92public:
  93	typedef boost::function<void()> callback_t;
  94
  95	LLInvPanelComplObserver(callback_t cb)
  96	:	mCallback(cb)
  97	{
  98	}
  99
 100	void reset();
 101
 102private:
 103	/*virtual*/ void done();
 104
 105	/// Called when all the items are complete.
 106	callback_t	mCallback;
 107};
 108
 109void LLInvPanelComplObserver::reset()
 110{
 111	mIncomplete.clear();
 112	mComplete.clear();
 113}
 114
 115void LLInvPanelComplObserver::done()
 116{
 117	mCallback();
 118}
 119
 120//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 121// Class LLInventoryPanel
 122//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 123
 124LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :	
 125	LLPanel(p),
 126	mInventoryObserver(NULL),
 127	mCompletionObserver(NULL),
 128	mFolderRoot(NULL),
 129	mScroller(NULL),
 130	mSortOrderSetting(p.sort_order_setting),
 131	mInventory(p.inventory),
 132	mAcceptsDragAndDrop(p.accepts_drag_and_drop),
 133	mAllowMultiSelect(p.allow_multi_select),
 134	mShowItemLinkOverlays(p.show_item_link_overlays),
 135	mShowEmptyMessage(p.show_empty_message),
 136	mShowLoadStatus(p.show_load_status),
 137	mViewsInitialized(false),
 138	mInvFVBridgeBuilder(NULL)
 139{
 140	mInvFVBridgeBuilder = &INVENTORY_BRIDGE_BUILDER;
 141
 142	// contex menu callbacks
 143	mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2));
 144	mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLFolderType::FT_TRASH));
 145	mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLFolderType::FT_LOST_AND_FOUND));
 146	mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLInventoryPanel::doCreate, this, _2));
 147	mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&LLInventoryPanel::attachObject, this, _2));
 148	mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this));
 149	mCommitCallbackRegistrar.add("Inventory.Share",  boost::bind(&LLAvatarActions::shareWithAvatars));
 150
 151}
 152
 153void LLInventoryPanel::buildFolderView(const LLInventoryPanel::Params& params)
 154{
 155	// Determine the root folder in case specified, and
 156	// build the views starting with that folder.
 157	
 158	std::string start_folder_name(params.start_folder());
 159	
 160	const LLFolderType::EType preferred_type = LLViewerFolderType::lookupTypeFromNewCategoryName(start_folder_name);
 161
 162	LLUUID root_id;
 163
 164	if ("LIBRARY" == params.start_folder())
 165	{
 166		root_id = gInventory.getLibraryRootFolderID();
 167	}
 168	else
 169	{
 170		root_id = (preferred_type != LLFolderType::FT_NONE)
 171				? gInventory.findCategoryUUIDForType(preferred_type, false, false) 
 172				: LLUUID::null;
 173	}
 174	
 175	if ((root_id == LLUUID::null) && !start_folder_name.empty())
 176	{
 177		llwarns << "No category found that matches start_folder: " << start_folder_name << llendl;
 178		root_id = LLUUID::generateNewID();
 179	}
 180	
 181	LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(LLAssetType::AT_CATEGORY,
 182																	LLAssetType::AT_CATEGORY,
 183																	LLInventoryType::IT_CATEGORY,
 184																	this,
 185																	NULL,
 186																	root_id);
 187	
 188	mFolderRoot = createFolderView(new_listener, params.use_label_suffix());
 189}
 190
 191void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)
 192{
 193	LLMemType mt(LLMemType::MTYPE_INVENTORY_POST_BUILD);
 194
 195	mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves
 196	
 197	buildFolderView(params);
 198
 199	mCommitCallbackRegistrar.popScope();
 200	
 201	mFolderRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
 202	
 203	// Scroller
 204	{
 205		LLRect scroller_view_rect = getRect();
 206		scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
 207		LLScrollContainer::Params scroller_params(params.scroll());
 208		scroller_params.rect(scroller_view_rect);
 209		mScroller = LLUICtrlFactory::create<LLScrollContainer>(scroller_params);
 210		addChild(mScroller);
 211		mScroller->addChild(mFolderRoot);
 212		mFolderRoot->setScrollContainer(mScroller);
 213		mFolderRoot->addChild(mFolderRoot->mStatusTextBox);
 214	}
 215
 216	// Set up the callbacks from the inventory we're viewing, and then build everything.
 217	mInventoryObserver = new LLInventoryPanelObserver(this);
 218	mInventory->addObserver(mInventoryObserver);
 219
 220	mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this));
 221	mInventory->addObserver(mCompletionObserver);
 222
 223	// Build view of inventory if we need default full hierarchy and inventory ready,
 224	// otherwise wait for idle callback.
 225	if (mInventory->isInventoryUsable() && !mViewsInitialized)
 226	{
 227		initializeViews();
 228	}
 229	gIdleCallbacks.addFunction(onIdle, (void*)this);
 230
 231	if (mSortOrderSetting != INHERIT_SORT_ORDER)
 232	{
 233		setSortOrder(gSavedSettings.getU32(mSortOrderSetting));
 234	}
 235	else
 236	{
 237		setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER));
 238	}
 239
 240	// hide inbox
 241	getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_INBOX));
 242	getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() & ~(1ULL << LLFolderType::FT_OUTBOX));
 243
 244	// set the filter for the empty folder if the debug setting is on
 245	if (gSavedSettings.getBOOL("DebugHideEmptySystemFolders"))
 246	{
 247		getFilter()->setFilterEmptySystemFolders();
 248	}
 249	
 250	// Initialize base class params.
 251	LLPanel::initFromParams(params);
 252}
 253
 254LLInventoryPanel::~LLInventoryPanel()
 255{
 256	if (mFolderRoot)
 257	{
 258		U32 sort_order = mFolderRoot->getSortOrder();
 259		if (mSortOrderSetting != INHERIT_SORT_ORDER)
 260		{
 261			gSavedSettings.setU32(mSortOrderSetting, sort_order);
 262		}
 263	}
 264
 265	gIdleCallbacks.deleteFunction(onIdle, this);
 266
 267	// LLView destructor will take care of the sub-views.
 268	mInventory->removeObserver(mInventoryObserver);
 269	mInventory->removeObserver(mCompletionObserver);
 270	delete mInventoryObserver;
 271	delete mCompletionObserver;
 272
 273	mScroller = NULL;
 274}
 275
 276void LLInventoryPanel::draw()
 277{
 278	// Select the desired item (in case it wasn't loaded when the selection was requested)
 279	mFolderRoot->updateSelection();
 280	LLPanel::draw();
 281}
 282
 283LLInventoryFilter* LLInventoryPanel::getFilter()
 284{
 285	if (mFolderRoot) 
 286	{
 287		return mFolderRoot->getFilter();
 288	}
 289	return NULL;
 290}
 291
 292const LLInventoryFilter* LLInventoryPanel::getFilter() const
 293{
 294	if (mFolderRoot)
 295	{
 296		return mFolderRoot->getFilter();
 297	}
 298	return NULL;
 299}
 300
 301void LLInventoryPanel::setFilterTypes(U64 types, LLInventoryFilter::EFilterType filter_type)
 302{
 303	if (filter_type == LLInventoryFilter::FILTERTYPE_OBJECT)
 304		getFilter()->setFilterObjectTypes(types);
 305	if (filter_type == LLInventoryFilter::FILTERTYPE_CATEGORY)
 306		getFilter()->setFilterCategoryTypes(types);
 307}
 308
 309U32 LLInventoryPanel::getFilterObjectTypes() const 
 310{ 
 311	return mFolderRoot->getFilterObjectTypes(); 
 312}
 313
 314U32 LLInventoryPanel::getFilterPermMask() const 
 315{ 
 316	return mFolderRoot->getFilterPermissions(); 
 317}
 318
 319
 320void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask)
 321{
 322	getFilter()->setFilterPermissions(filter_perm_mask);
 323}
 324
 325void LLInventoryPanel::setFilterWearableTypes(U64 types)
 326{
 327	getFilter()->setFilterWearableTypes(types);
 328}
 329
 330void LLInventoryPanel::setFilterSubString(const std::string& string)
 331{
 332	getFilter()->setFilterSubString(string);
 333}
 334
 335const std::string LLInventoryPanel::getFilterSubString() 
 336{ 
 337	return mFolderRoot->getFilterSubString(); 
 338}
 339
 340
 341void LLInventoryPanel::setSortOrder(U32 order)
 342{
 343	getFilter()->setSortOrder(order);
 344	if (getFilter()->isModified())
 345	{
 346		mFolderRoot->setSortOrder(order);
 347		// try to keep selection onscreen, even if it wasn't to start with
 348		mFolderRoot->scrollToShowSelection();
 349	}
 350}
 351
 352U32 LLInventoryPanel::getSortOrder() const 
 353{ 
 354	return mFolderRoot->getSortOrder(); 
 355}
 356
 357void LLInventoryPanel::requestSort()
 358{
 359	mFolderRoot->requestSort();
 360}
 361
 362void LLInventoryPanel::setSinceLogoff(BOOL sl)
 363{
 364	getFilter()->setDateRangeLastLogoff(sl);
 365}
 366
 367void LLInventoryPanel::setHoursAgo(U32 hours)
 368{
 369	getFilter()->setHoursAgo(hours);
 370}
 371
 372void LLInventoryPanel::setFilterLinks(U64 filter_links)
 373{
 374	getFilter()->setFilterLinks(filter_links);
 375}
 376
 377void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show)
 378{
 379	getFilter()->setShowFolderState(show);
 380}
 381
 382LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState()
 383{
 384	return getFilter()->getShowFolderState();
 385}
 386
 387void LLInventoryPanel::modelChanged(U32 mask)
 388{
 389	static LLFastTimer::DeclareTimer FTM_REFRESH("Inventory Refresh");
 390	LLFastTimer t2(FTM_REFRESH);
 391
 392	bool handled = false;
 393
 394	if (!mViewsInitialized) return;
 395	
 396	const LLInventoryModel* model = getModel();
 397	if (!model) return;
 398
 399	const LLInventoryModel::changed_items_t& changed_items = model->getChangedIDs();
 400	if (changed_items.empty()) return;
 401
 402	for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin();
 403		 items_iter != changed_items.end();
 404		 ++items_iter)
 405	{
 406		const LLUUID& item_id = (*items_iter);
 407		const LLInventoryObject* model_item = model->getObject(item_id);
 408		LLFolderViewItem* view_item = mFolderRoot->getItemByID(item_id);
 409
 410		// LLFolderViewFolder is derived from LLFolderViewItem so dynamic_cast from item
 411		// to folder is the fast way to get a folder without searching through folders tree.
 412		LLFolderViewFolder* view_folder = dynamic_cast<LLFolderViewFolder*>(view_item);
 413
 414		//////////////////////////////
 415		// LABEL Operation
 416		// Empty out the display name for relabel.
 417		if (mask & LLInventoryObserver::LABEL)
 418		{
 419			handled = true;
 420			if (view_item)
 421			{
 422				// Request refresh on this item (also flags for filtering)
 423				LLInvFVBridge* bridge = (LLInvFVBridge*)view_item->getListener();
 424				if(bridge)
 425				{	// Clear the display name first, so it gets properly re-built during refresh()
 426					bridge->clearDisplayName();
 427
 428					view_item->refresh();
 429				}
 430			}
 431		}
 432
 433		//////////////////////////////
 434		// REBUILD Operation
 435		// Destroy and regenerate the UI.
 436		if (mask & LLInventoryObserver::REBUILD)
 437		{
 438			handled = true;
 439			if (model_item && view_item)
 440			{
 441				view_item->destroyView();
 442			}
 443			view_item = buildNewViews(item_id);
 444			view_folder = dynamic_cast<LLFolderViewFolder *>(view_item);
 445		}
 446
 447		//////////////////////////////
 448		// INTERNAL Operation
 449		// This could be anything.  For now, just refresh the item.
 450		if (mask & LLInventoryObserver::INTERNAL)
 451		{
 452			if (view_item)
 453			{
 454				view_item->refresh();
 455			}
 456		}
 457
 458		//////////////////////////////
 459		// SORT Operation
 460		// Sort the folder.
 461		if (mask & LLInventoryObserver::SORT)
 462		{
 463			if (view_folder)
 464			{
 465				view_folder->requestSort();
 466			}
 467		}	
 468
 469		// We don't typically care which of these masks the item is actually flagged with, since the masks
 470		// may not be accurate (e.g. in the main inventory panel, I move an item from My Inventory into
 471		// Landmarks; this is a STRUCTURE change for that panel but is an ADD change for the Landmarks
 472		// panel).  What's relevant is that the item and UI are probably out of sync and thus need to be
 473		// resynchronized.
 474		if (mask & (LLInventoryObserver::STRUCTURE |
 475					LLInventoryObserver::ADD |
 476					LLInventoryObserver::REMOVE))
 477		{
 478			handled = true;
 479
 480			//////////////////////////////
 481			// ADD Operation
 482			// Item exists in memory but a UI element hasn't been created for it.
 483			if (model_item && !view_item)
 484			{
 485				// Add the UI element for this item.
 486				buildNewViews(item_id);
 487				// Select any newly created object that has the auto rename at top of folder root set.
 488				if(mFolderRoot->getRoot()->needsAutoRename())
 489				{
 490					setSelection(item_id, FALSE);
 491				}
 492			}
 493
 494			//////////////////////////////
 495			// STRUCTURE Operation
 496			// This item already exists in both memory and UI.  It was probably reparented.
 497			else if (model_item && view_item)
 498			{
 499				// Don't process the item if it is the root
 500				if (view_item->getRoot() != view_item)
 501				{
 502					LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolderRoot->getItemByID(model_item->getParentUUID());
 503					// Item has been moved.
 504					if (view_item->getParentFolder() != new_parent)
 505					{
 506						if (new_parent != NULL)
 507						{
 508							// Item is to be moved and we found its new parent in the panel's directory, so move the item's UI.
 509							view_item->getParentFolder()->extractItem(view_item);
 510							view_item->addToFolder(new_parent, mFolderRoot);
 511						}
 512						else 
 513						{
 514							// Item is to be moved outside the panel's directory (e.g. moved to trash for a panel that 
 515							// doesn't include trash).  Just remove the item's UI.
 516							view_item->destroyView();
 517						}
 518					}
 519				}
 520			}
 521			
 522			//////////////////////////////
 523			// REMOVE Operation
 524			// This item has been removed from memory, but its associated UI element still exists.
 525			else if (!model_item && view_item)
 526			{
 527				// Remove the item's UI.
 528				view_item->destroyView();
 529			}
 530		}
 531	}
 532}
 533
 534LLFolderView* LLInventoryPanel::getRootFolder() 
 535{ 
 536	return mFolderRoot; 
 537}
 538
 539
 540// static
 541void LLInventoryPanel::onIdle(void *userdata)
 542{
 543	if (!gInventory.isInventoryUsable())
 544		return;
 545
 546	LLInventoryPanel *self = (LLInventoryPanel*)userdata;
 547	// Inventory just initialized, do complete build
 548	if (!self->mViewsInitialized)
 549	{
 550		self->initializeViews();
 551	}
 552	if (self->mViewsInitialized)
 553	{
 554		gIdleCallbacks.deleteFunction(onIdle, (void*)self);
 555	}
 556}
 557
 558const LLUUID& LLInventoryPanel::getRootFolderID() const
 559{
 560	return mFolderRoot->getListener()->getUUID();
 561}
 562
 563void LLInventoryPanel::initializeViews()
 564{
 565	if (!gInventory.isInventoryUsable()) return;
 566
 567	rebuildViewsFor(getRootFolderID());
 568
 569	mViewsInitialized = true;
 570	
 571	openStartFolderOrMyInventory();
 572	
 573	// Special case for new user login
 574	if (gAgent.isFirstLogin())
 575	{
 576		// Auto open the user's library
 577		LLFolderViewFolder* lib_folder = mFolderRoot->getFolderByID(gInventory.getLibraryRootFolderID());
 578		if (lib_folder)
 579		{
 580			lib_folder->setOpen(TRUE);
 581		}
 582		
 583		// Auto close the user's my inventory folder
 584		LLFolderViewFolder* my_inv_folder = mFolderRoot->getFolderByID(gInventory.getRootFolderID());
 585		if (my_inv_folder)
 586		{
 587			my_inv_folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN);
 588		}
 589	}
 590}
 591
 592LLFolderViewItem* LLInventoryPanel::rebuildViewsFor(const LLUUID& id)
 593{
 594	// Destroy the old view for this ID so we can rebuild it.
 595	LLFolderViewItem* old_view = mFolderRoot->getItemByID(id);
 596	if (old_view)
 597	{
 598		old_view->destroyView();
 599	}
 600
 601	return buildNewViews(id);
 602}
 603
 604LLFolderView * LLInventoryPanel::createFolderView(LLInvFVBridge * bridge, bool useLabelSuffix)
 605{
 606	LLRect folder_rect(0,
 607					   0,
 608					   getRect().getWidth(),
 609					   0);
 610
 611	LLFolderView::Params p;
 612	
 613	p.name = getName();
 614	p.title = getLabel();
 615	p.rect = folder_rect;
 616	p.parent_panel = this;
 617	p.tool_tip = p.name;
 618	p.listener =  bridge;
 619	p.use_label_suffix = useLabelSuffix;
 620	p.allow_multiselect = mAllowMultiSelect;
 621	p.show_empty_message = mShowEmptyMessage;
 622	p.show_load_status = mShowLoadStatus;
 623
 624	return LLUICtrlFactory::create<LLFolderView>(p);
 625}
 626
 627LLFolderViewFolder * LLInventoryPanel::createFolderViewFolder(LLInvFVBridge * bridge)
 628{
 629	LLFolderViewFolder::Params params;
 630
 631	params.name = bridge->getDisplayName();
 632	params.icon = bridge->getIcon();
 633	params.icon_open = bridge->getOpenIcon();
 634
 635	if (mShowItemLinkOverlays) // if false, then links show up just like normal items
 636	{
 637		params.icon_overlay = LLUI::getUIImage("Inv_Link");
 638	}
 639	
 640	params.root = mFolderRoot;
 641	params.listener = bridge;
 642	params.tool_tip = params.name;
 643
 644	return LLUICtrlFactory::create<LLFolderViewFolder>(params);
 645}
 646
 647LLFolderViewItem * LLInventoryPanel::createFolderViewItem(LLInvFVBridge * bridge)
 648{
 649	LLFolderViewItem::Params params;
 650	
 651	params.name = bridge->getDisplayName();
 652	params.icon = bridge->getIcon();
 653	params.icon_open = bridge->getOpenIcon();
 654
 655	if (mShowItemLinkOverlays) // if false, then links show up just like normal items
 656	{
 657		params.icon_overlay = LLUI::getUIImage("Inv_Link");
 658	}
 659
 660	params.creation_date = bridge->getCreationDate();
 661	params.root = mFolderRoot;
 662	params.listener = bridge;
 663	params.rect = LLRect (0, 0, 0, 0);
 664	params.tool_tip = params.name;
 665	
 666	return LLUICtrlFactory::create<LLFolderViewItem>(params);
 667}
 668
 669LLFolderViewItem* LLInventoryPanel::buildNewViews(const LLUUID& id)
 670{
 671 	LLInventoryObject const* objectp = gInventory.getObject(id);
 672 	LLUUID root_id = mFolderRoot->getListener()->getUUID();
 673 	LLFolderViewFolder* parent_folder = NULL;
 674	LLFolderViewItem* itemp = NULL;
 675	
 676 	if (id == root_id)
 677 	{
 678 		parent_folder = mFolderRoot;
 679 	}
 680 	else if (objectp)
 681 	{
 682 		const LLUUID &parent_id = objectp->getParentUUID();
 683 		parent_folder = (LLFolderViewFolder*)mFolderRoot->getItemByID(parent_id);
 684  		
 685  		if (parent_folder)
 686  		{
 687  			if (objectp->getType() <= LLAssetType::AT_NONE ||
 688  				objectp->getType() >= LLAssetType::AT_COUNT)
 689  			{
 690  				llwarns << "LLInventoryPanel::buildNewViews called with invalid objectp->mType : "
 691  						<< ((S32) objectp->getType()) << " name " << objectp->getName() << " UUID " << objectp->getUUID()
 692  						<< llendl;
 693  				return NULL;
 694  			}
 695  		
 696  			if ((objectp->getType() == LLAssetType::AT_CATEGORY) &&
 697  				(objectp->getActualType() != LLAssetType::AT_LINK_FOLDER))
 698  			{
 699  				LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(objectp->getType(),
 700  																				objectp->getType(),
 701  																				LLInventoryType::IT_CATEGORY,
 702  																				this,
 703  																				mFolderRoot,
 704  																				objectp->getUUID());
 705  				if (new_listener)
 706  				{
 707					LLFolderViewFolder* folderp = createFolderViewFolder(new_listener);
 708					if (folderp)
 709					{
 710						folderp->setItemSortOrder(mFolderRoot->getSortOrder());
 711					}
 712  					itemp = folderp;
 713  				}
 714  			}
 715  			else
 716  			{
 717  				// Build new view for item.
 718  				LLInventoryItem* item = (LLInventoryItem*)objectp;
 719  				LLInvFVBridge* new_listener = mInvFVBridgeBuilder->createBridge(item->getType(),
 720  																				item->getActualType(),
 721  																				item->getInventoryType(),
 722  																				this,
 723  																				mFolderRoot,
 724  																				item->getUUID(),
 725  																				item->getFlags());
 726 
 727  				if (new_listener)
 728  				{
 729					itemp = createFolderViewItem(new_listener);
 730  				}
 731  			}
 732 
 733  			if (itemp)
 734  			{
 735  				itemp->addToFolder(parent_folder, mFolderRoot);
 736   			}
 737		}
 738	}
 739
 740	// If this is a folder, add the children of the folder and recursively add any 
 741	// child folders.
 742	if (id.isNull()
 743		||	(objectp
 744			&& objectp->getType() == LLAssetType::AT_CATEGORY))
 745	{
 746		LLViewerInventoryCategory::cat_array_t* categories;
 747		LLViewerInventoryItem::item_array_t* items;
 748		mInventory->lockDirectDescendentArrays(id, categories, items);
 749		
 750		if(categories)
 751		{
 752			for (LLViewerInventoryCategory::cat_array_t::const_iterator cat_iter = categories->begin();
 753				 cat_iter != categories->end();
 754				 ++cat_iter)
 755			{
 756				const LLViewerInventoryCategory* cat = (*cat_iter);
 757				buildNewViews(cat->getUUID());
 758			}
 759		}
 760		
 761		if(items && parent_folder)
 762		{
 763			for (LLViewerInventoryItem::item_array_t::const_iterator item_iter = items->begin();
 764				 item_iter != items->end();
 765				 ++item_iter)
 766			{
 767				const LLViewerInventoryItem* item = (*item_iter);
 768				buildNewViews(item->getUUID());
 769			}
 770		}
 771		mInventory->unlockDirectDescendentArrays(id);
 772	}
 773	
 774	return itemp;
 775}
 776
 777// bit of a hack to make sure the inventory is open.
 778void LLInventoryPanel::openStartFolderOrMyInventory()
 779{
 780	// Find My Inventory folder and open it up by name
 781	for (LLView *child = mFolderRoot->getFirstChild(); child; child = mFolderRoot->findNextSibling(child))
 782	{
 783		LLFolderViewFolder *fchild = dynamic_cast<LLFolderViewFolder*>(child);
 784		if (fchild
 785			&& fchild->getListener()
 786				&& fchild->getListener()->getUUID() == gInventory.getRootFolderID())
 787		{
 788			fchild->setOpen(TRUE);
 789			break;
 790		}
 791	}
 792}
 793
 794void LLInventoryPanel::onItemsCompletion()
 795{
 796	if (mFolderRoot) mFolderRoot->updateMenu();
 797}
 798
 799void LLInventoryPanel::openSelected()
 800{
 801	LLFolderViewItem* folder_item = mFolderRoot->getCurSelectedItem();
 802	if(!folder_item) return;
 803	LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener();
 804	if(!bridge) return;
 805	bridge->openItem();
 806}
 807
 808void LLInventoryPanel::unSelectAll()	
 809{ 
 810	mFolderRoot->setSelection(NULL, FALSE, FALSE); 
 811}
 812
 813
 814BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask)
 815{
 816	BOOL handled = LLView::handleHover(x, y, mask);
 817	if(handled)
 818	{
 819		ECursorType cursor = getWindow()->getCursor();
 820		if (LLInventoryModelBackgroundFetch::instance().backgroundFetchActive() && cursor == UI_CURSOR_ARROW)
 821		{
 822			// replace arrow cursor with arrow and hourglass cursor
 823			getWindow()->setCursor(UI_CURSOR_WORKING);
 824		}
 825	}
 826	else
 827	{
 828		getWindow()->setCursor(UI_CURSOR_ARROW);
 829	}
 830	return TRUE;
 831}
 832
 833BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 834								   EDragAndDropType cargo_type,
 835								   void* cargo_data,
 836								   EAcceptance* accept,
 837								   std::string& tooltip_msg)
 838{
 839	BOOL handled = FALSE;
 840
 841	if (mAcceptsDragAndDrop)
 842	{
 843		handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
 844
 845		// If folder view is empty the (x, y) point won't be in its rect
 846		// so the handler must be called explicitly.
 847		// but only if was not handled before. See EXT-6746.
 848		if (!handled && !mFolderRoot->hasVisibleChildren())
 849		{
 850			handled = mFolderRoot->handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg);
 851		}
 852
 853		if (handled)
 854		{
 855			mFolderRoot->setDragAndDropThisFrame();
 856		}
 857	}
 858
 859	return handled;
 860}
 861
 862void LLInventoryPanel::onFocusLost()
 863{
 864	// inventory no longer handles cut/copy/paste/delete
 865	if (LLEditMenuHandler::gEditMenuHandler == mFolderRoot)
 866	{
 867		LLEditMenuHandler::gEditMenuHandler = NULL;
 868	}
 869
 870	LLPanel::onFocusLost();
 871}
 872
 873void LLInventoryPanel::onFocusReceived()
 874{
 875	// inventory now handles cut/copy/paste/delete
 876	LLEditMenuHandler::gEditMenuHandler = mFolderRoot;
 877
 878	LLPanel::onFocusReceived();
 879}
 880
 881bool LLInventoryPanel::addBadge(LLBadge * badge)
 882{
 883	bool badge_added = false;
 884
 885	if (acceptsBadge())
 886	{
 887		badge_added = badge->addToView(mFolderRoot);
 888	}
 889
 890	return badge_added;
 891}
 892
 893void LLInventoryPanel::openAllFolders()
 894{
 895	mFolderRoot->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN);
 896	mFolderRoot->arrangeAll();
 897}
 898
 899void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus)
 900{
 901	// Don't select objects in COF (e.g. to prevent refocus when items are worn).
 902	const LLInventoryObject *obj = gInventory.getObject(obj_id);
 903	if (obj && obj->getParentUUID() == LLAppearanceMgr::instance().getCOF())
 904	{
 905		return;
 906	}
 907	mFolderRoot->setSelectionByID(obj_id, take_keyboard_focus);
 908}
 909
 910void LLInventoryPanel::setSelectCallback(const boost::function<void (const std::deque<LLFolderViewItem*>& items, BOOL user_action)>& cb) 
 911{ 
 912	if (mFolderRoot) 
 913	{
 914		mFolderRoot->setSelectCallback(cb);
 915	}
 916}
 917
 918void LLInventoryPanel::clearSelection()
 919{
 920	mFolderRoot->clearSelection();
 921}
 922
 923void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& items, BOOL user_action)
 924{
 925	// Schedule updating the folder view context menu when all selected items become complete (STORM-373).
 926	mCompletionObserver->reset();
 927	for (std::deque<LLFolderViewItem*>::const_iterator it = items.begin(); it != items.end(); ++it)
 928	{
 929		LLUUID id = (*it)->getListener()->getUUID();
 930		LLViewerInventoryItem* inv_item = mInventory->getItem(id);
 931
 932		if (inv_item && !inv_item->isFinished())
 933		{
 934			mCompletionObserver->watchItem(id);
 935		}
 936	}
 937
 938	LLFolderView* fv = getRootFolder();
 939	if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename
 940	{
 941		fv->setNeedsAutoRename(FALSE);
 942		if (items.size()) // new asset is visible and selected
 943		{
 944			fv->startRenamingSelectedItem();
 945		}
 946	}
 947}
 948
 949void LLInventoryPanel::doToSelected(const LLSD& userdata)
 950{
 951	mFolderRoot->doToSelected(&gInventory, userdata);
 952}
 953
 954void LLInventoryPanel::doCreate(const LLSD& userdata)
 955{
 956	menu_create_inventory_item(mFolderRoot, LLFolderBridge::sSelf.get(), userdata);
 957}
 958
 959bool LLInventoryPanel::beginIMSession()
 960{
 961	std::set<LLUUID> selected_items = mFolderRoot->getSelectionList();
 962
 963	std::string name;
 964	static int session_num = 1;
 965
 966	LLDynamicArray<LLUUID> members;
 967	EInstantMessage type = IM_SESSION_CONFERENCE_START;
 968
 969	std::set<LLUUID>::const_iterator iter;
 970	for (iter = selected_items.begin(); iter != selected_items.end(); iter++)
 971	{
 972
 973		LLUUID item = *iter;
 974		LLFolderViewItem* folder_item = mFolderRoot->getItemByID(item);
 975			
 976		if(folder_item) 
 977		{
 978			LLFolderViewEventListener* fve_listener = folder_item->getListener();
 979			if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY))
 980			{
 981
 982				LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getListener();
 983				if(!bridge) return true;
 984				LLViewerInventoryCategory* cat = bridge->getCategory();
 985				if(!cat) return true;
 986				name = cat->getName();
 987				LLUniqueBuddyCollector is_buddy;
 988				LLInventoryModel::cat_array_t cat_array;
 989				LLInventoryModel::item_array_t item_array;
 990				gInventory.collectDescendentsIf(bridge->getUUID(),
 991												cat_array,
 992												item_array,
 993												LLInventoryModel::EXCLUDE_TRASH,
 994												is_buddy);
 995				S32 count = item_array.count();
 996				if(count > 0)
 997				{
 998					//*TODO by what to replace that?
 999					//LLFloaterReg::showInstance("communicate");
1000
1001					// create the session
1002					LLAvatarTracker& at = LLAvatarTracker::instance();
1003					LLUUID id;
1004					for(S32 i = 0; i < count; ++i)
1005					{
1006						id = item_array.get(i)->getCreatorUUID();
1007						if(at.isBuddyOnline(id))
1008						{
1009							members.put(id);
1010						}
1011					}
1012				}
1013			}
1014			else
1015			{
1016				LLFolderViewItem* folder_item = mFolderRoot->getItemByID(item);
1017				if(!folder_item) return true;
1018				LLInvFVBridge* listenerp = (LLInvFVBridge*)folder_item->getListener();
1019
1020				if (listenerp->getInventoryType() == LLInventoryType::IT_CALLINGCARD)
1021				{
1022					LLInventoryItem* inv_item = gInventory.getItem(listenerp->getUUID());
1023
1024					if (inv_item)
1025					{
1026						LLAvatarTracker& at = LLAvatarTracker::instance();
1027						LLUUID id = inv_item->getCreatorUUID();
1028
1029						if(at.isBuddyOnline(id))
1030						{
1031							members.put(id);
1032						}
1033					}
1034				} //if IT_CALLINGCARD
1035			} //if !IT_CATEGORY
1036		}
1037	} //for selected_items	
1038
1039	// the session_id is randomly generated UUID which will be replaced later
1040	// with a server side generated number
1041
1042	if (name.empty())
1043	{
1044		name = llformat("Session %d", session_num++);
1045	}
1046
1047	LLUUID session_id = gIMMgr->addSession(name, type, members[0], members);
1048	if (session_id != LLUUID::null)
1049	{
1050		LLIMFloater::show(session_id);
1051	}
1052		
1053	return true;
1054}
1055
1056bool LLInventoryPanel::attachObject(const LLSD& userdata)
1057{
1058	// Copy selected item UUIDs to a vector.
1059	std::set<LLUUID> selected_items = mFolderRoot->getSelectionList();
1060	uuid_vec_t items;
1061	for (std::set<LLUUID>::const_iterator set_iter = selected_items.begin(); 
1062		 set_iter != selected_items.end(); 
1063		 ++set_iter)
1064	{
1065		items.push_back(*set_iter);
1066	}
1067
1068	// Attach selected items.
1069	LLViewerAttachMenu::attachObjects(items, userdata.asString());
1070
1071	gFocusMgr.setKeyboardFocus(NULL);
1072
1073	return true;
1074}
1075
1076BOOL LLInventoryPanel::getSinceLogoff()
1077{
1078	return getFilter()->isSinceLogoff();
1079}
1080
1081// DEBUG ONLY
1082// static 
1083void LLInventoryPanel::dumpSelectionInformation(void* user_data)
1084{
1085	LLInventoryPanel* iv = (LLInventoryPanel*)user_data;
1086	iv->mFolderRoot->dumpSelectionInformation();
1087}
1088
1089BOOL is_inventorysp_active()
1090{
1091	LLSidepanelInventory *sidepanel_inventory =	LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
1092	if (!sidepanel_inventory || !sidepanel_inventory->isInVisibleChain()) return FALSE;
1093	return sidepanel_inventory->isMainInventoryPanelActive();
1094}
1095
1096// static
1097LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open)
1098{
1099	S32 z_min = S32_MAX;
1100	LLInventoryPanel* res = NULL;
1101	LLFloater* active_inv_floaterp = NULL;
1102
1103	LLFloater* floater_inventory = LLFloaterReg::getInstance("inventory");
1104	if (!floater_inventory)
1105	{
1106		llwarns << "Could not find My Inventory floater" << llendl;
1107		return FALSE;
1108	}
1109
1110	LLSidepanelInventory *inventory_panel =	LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
1111
1112	// Iterate through the inventory floaters and return whichever is on top.
1113	LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
1114	for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
1115	{
1116		LLFloaterSidePanelContainer* inventory_floater = dynamic_cast<LLFloaterSidePanelContainer*>(*iter);
1117		inventory_panel = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
1118
1119		if (inventory_floater && inventory_panel && inventory_floater->getVisible())
1120		{
1121			S32 z_order = gFloaterView->getZOrder(inventory_floater);
1122			if (z_order < z_min)
1123			{
1124				res = inventory_panel->getActivePanel();
1125				z_min = z_order;
1126				active_inv_floaterp = inventory_floater;
1127			}
1128		}
1129	}
1130
1131	if (res)
1132	{
1133		// Make sure the floater is not minimized (STORM-438).
1134		if (active_inv_floaterp && active_inv_floaterp->isMinimized())
1135		{
1136			active_inv_floaterp->setMinimized(FALSE);
1137		}
1138	}	
1139	else if (auto_open)
1140	{
1141		floater_inventory->openFloater();
1142
1143		res = inventory_panel->getActivePanel();
1144	}
1145
1146	return res;
1147}
1148
1149//static
1150void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const LLUUID& obj_id)
1151{
1152	LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open);
1153
1154	if (active_panel)
1155	{
1156		LL_DEBUGS("Messaging") << "Highlighting" << obj_id  << LL_ENDL;
1157		
1158		LLViewerInventoryItem * item = gInventory.getItem(obj_id);
1159		LLViewerInventoryCategory * cat = gInventory.getCategory(obj_id);
1160		
1161		bool in_inbox = false;
1162		
1163		LLViewerInventoryCategory * parent_cat = NULL;
1164		
1165		if (item)
1166		{
1167			parent_cat = gInventory.getCategory(item->getParentUUID());
1168		}
1169		else if (cat)
1170		{
1171			parent_cat = gInventory.getCategory(cat->getParentUUID());
1172		}
1173		
1174		if (parent_cat)
1175		{
1176			in_inbox = (LLFolderType::FT_INBOX == parent_cat->getPreferredType());
1177		}
1178		
1179		if (in_inbox)
1180		{
1181			LLSidepanelInventory * sidepanel_inventory =	LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
1182			LLInventoryPanel * inventory_panel = NULL;
1183			
1184			if (in_inbox)
1185			{
1186				sidepanel_inventory->openInbox();
1187				inventory_panel = sidepanel_inventory->getInboxPanel();
1188			}
1189
1190			if (inventory_panel)
1191			{
1192				inventory_panel->setSelection(obj_id, TAKE_FOCUS_YES);
1193			}
1194		}
1195		else
1196		{
1197			active_panel->setSelection(obj_id, TAKE_FOCUS_YES);
1198		}
1199	}
1200}
1201
1202void LLInventoryPanel::addHideFolderType(LLFolderType::EType folder_type)
1203{
1204	getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() & ~(1ULL << folder_type));
1205}
1206
1207BOOL LLInventoryPanel::getIsHiddenFolderType(LLFolderType::EType folder_type) const
1208{
1209	return !(getFilter()->getFilterCategoryTypes() & (1ULL << folder_type));
1210}
1211
1212
1213/************************************************************************/
1214/* Recent Inventory Panel related class                                 */
1215/************************************************************************/
1216class LLInventoryRecentItemsPanel;
1217static LLDefaultChildRegistry::Register<LLInventoryRecentItemsPanel> t_recent_inventory_panel("recent_inventory_panel");
1218
1219static const LLRecentInventoryBridgeBuilder RECENT_ITEMS_BUILDER;
1220class LLInventoryRecentItemsPanel : public LLInventoryPanel
1221{
1222public:
1223	struct Params :	public LLInitParam::Block<Params, LLInventoryPanel::Params>
1224	{};
1225
1226	void initFromParams(const Params& p)
1227	{
1228		LLInventoryPanel::initFromParams(p);
1229		// turn on inbox for recent items
1230		getFilter()->setFilterCategoryTypes(getFilter()->getFilterCategoryTypes() | (1ULL << LLFolderType::FT_INBOX));
1231	}
1232
1233protected:
1234	LLInventoryRecentItemsPanel (const Params&);
1235	friend class LLUICtrlFactory;
1236};
1237
1238LLInventoryRecentItemsPanel::LLInventoryRecentItemsPanel( const Params& params)
1239: LLInventoryPanel(params)
1240{
1241	// replace bridge builder to have necessary View bridges.
1242	mInvFVBridgeBuilder = &RECENT_ITEMS_BUILDER;
1243}
1244