//virtual
void LLPanelWearing::onOpen(const LLSD& /*info*/)
{
	if (!mIsInitialized)
	{
		// *TODO: I'm not sure is this check necessary but it never match while developing.
		if (!gInventory.isInventoryUsable())
			return;

		const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);

		// *TODO: I'm not sure is this check necessary but it never match while developing.
		LLViewerInventoryCategory* category = gInventory.getCategory(cof);
		if (!category)
			return;

		gInventory.addObserver(mCategoriesObserver);

		// Start observing changes in Current Outfit category.
		mCategoriesObserver->addCategory(cof, boost::bind(&LLWearableItemsList::updateList, mCOFItemsList, cof));

		// Fetch Current Outfit contents and refresh the list to display
		// initially fetched items. If not all items are fetched now
		// the observer will refresh the list as soon as the new items
		// arrive.
		category->fetch();

		mCOFItemsList->updateList(cof);

		mIsInitialized = true;
	}
}
void LLInventoryFetchDescendentsObserver::startFetch()
{
	for (uuid_vec_t::const_iterator it = mIDs.begin(); it != mIDs.end(); ++it)
	{
		LLViewerInventoryCategory* cat = gInventory.getCategory(*it);
		if (!cat) continue;
		if (!isCategoryComplete(cat))
		{
			cat->fetch();		//blindly fetch it without seeing if anything else is fetching it.
			mIncomplete.push_back(*it);	//Add to list of things being downloaded for this observer.
		}
		else
		{
			mComplete.push_back(*it);
		}
	}
}
Esempio n. 3
0
//virtual
void LLOutfitsList::onOpen(const LLSD& /*info*/)
{
	if (!mIsInitialized)
	{
		// *TODO: I'm not sure is this check necessary but it never match while developing.
		if (!gInventory.isInventoryUsable())
			return;

		const LLUUID outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);

		// *TODO: I'm not sure is this check necessary but it never match while developing.
		LLViewerInventoryCategory* category = gInventory.getCategory(outfits);
		if (!category)
			return;

		gInventory.addObserver(mCategoriesObserver);

		// Start observing changes in "My Outfits" category.
		mCategoriesObserver->addCategory(outfits,
			boost::bind(&LLOutfitsList::refreshList, this, outfits));

		const LLUUID cof = gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);

		// Start observing changes in Current Outfit category.
		mCategoriesObserver->addCategory(cof, boost::bind(&LLOutfitsList::onCOFChanged, this));

		LLOutfitObserver::instance().addBOFChangedCallback(boost::bind(&LLOutfitsList::highlightBaseOutfit, this));
		LLOutfitObserver::instance().addBOFReplacedCallback(boost::bind(&LLOutfitsList::highlightBaseOutfit, this));

		// Fetch "My Outfits" contents and refresh the list to display
		// initially fetched items. If not all items are fetched now
		// the observer will refresh the list as soon as the new items
		// arrive.
		category->fetch();
		refreshList(outfits);
		highlightBaseOutfit();

		mIsInitialized = true;
	}

	LLAccordionCtrlTab* selected_tab = mAccordion->getSelectedTab();
	if (!selected_tab) return;

	// Pass focus to the selected outfit tab.
	selected_tab->showAndFocusHeader();
}
Esempio n. 4
0
void LLOutfitsList::refreshList(const LLUUID& category_id)
{
	LLInventoryModel::cat_array_t cat_array;
	LLInventoryModel::item_array_t item_array;

	// Collect all sub-categories of a given category.
	LLIsType is_category(LLAssetType::AT_CATEGORY);
	gInventory.collectDescendentsIf(
		category_id,
		cat_array,
		item_array,
		LLInventoryModel::EXCLUDE_TRASH,
		is_category);

	uuid_vec_t vadded;
	uuid_vec_t vremoved;

	// Create added and removed items vectors.
	computeDifference(cat_array, vadded, vremoved);

	// Handle added tabs.
	for (uuid_vec_t::const_iterator iter = vadded.begin();
		 iter != vadded.end();
		 ++iter)
	{
		const LLUUID cat_id = (*iter);
		LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
		if (!cat) continue;

		std::string name = cat->getName();

		outfit_accordion_tab_params tab_params(get_accordion_tab_params());
		LLAccordionCtrlTab* tab = LLUICtrlFactory::create<LLAccordionCtrlTab>(tab_params);
		if (!tab) continue;
		LLWearableItemsList* wearable_list = LLUICtrlFactory::create<LLWearableItemsList>(tab_params.wearable_list);
		wearable_list->setShape(tab->getLocalRect());
		tab->addChild(wearable_list);

		tab->setName(name);
		tab->setTitle(name);

		// *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated.
		tab->setDisplayChildren(false);
		mAccordion->addCollapsibleCtrl(tab);

		// Start observing the new outfit category.
		LLWearableItemsList* list  = tab->getChild<LLWearableItemsList>("wearable_items_list");
		if (!mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id)))
		{
			// Remove accordion tab if category could not be added to observer.
			mAccordion->removeCollapsibleCtrl(tab);

			// kill removed tab
				tab->die();
			continue;
		}

		// Map the new tab with outfit category UUID.
		mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab));

		tab->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onAccordionTabRightClick, this,
			_1, _2, _3, cat_id));

		// Setting tab focus callback to monitor currently selected outfit.
		tab->setFocusReceivedCallback(boost::bind(&LLOutfitsList::changeOutfitSelection, this, list, cat_id));

		// Setting callback to reset items selection inside outfit on accordion collapsing and expanding (EXT-7875)
		tab->setDropDownStateChangedCallback(boost::bind(&LLOutfitsList::resetItemSelection, this, list, cat_id));

		// force showing list items that don't match current filter(EXT-7158)
		list->setForceShowingUnmatchedItems(true);

		// Setting list commit callback to monitor currently selected wearable item.
		list->setCommitCallback(boost::bind(&LLOutfitsList::onSelectionChange, this, _1));

		// Setting list refresh callback to apply filter on list change.
		list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onFilteredWearableItemsListRefresh, this, _1));

		list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3));

		// Fetch the new outfit contents.
		cat->fetch();

		// Refresh the list of outfit items after fetch().
		// Further list updates will be triggered by the category observer.
		list->updateList(cat_id);

		// If filter is currently applied we store the initial tab state and
		// open it to show matched items if any.
		if (!sFilterSubString.empty())
		{
			tab->notifyChildren(LLSD().with("action","store_state"));
			tab->setDisplayChildren(true);

			// Setting mForceRefresh flag will make the list refresh its contents
			// even if it is not currently visible. This is required to apply the
			// filter to the newly added list.
			list->setForceRefresh(true);

			list->setFilterSubString(sFilterSubString);
		}
	}

	// Handle removed tabs.
	for (uuid_vec_t::const_iterator iter=vremoved.begin(); iter != vremoved.end(); ++iter)
	{
		outfits_map_t::iterator outfits_iter = mOutfitsMap.find((*iter));
		if (outfits_iter != mOutfitsMap.end())
		{
			const LLUUID& outfit_id = outfits_iter->first;
			LLAccordionCtrlTab* tab = outfits_iter->second;

			// An outfit is removed from the list. Do the following:
			// 1. Remove outfit category from observer to stop monitoring its changes.
			mCategoriesObserver->removeCategory(outfit_id);

			// 2. Remove the outfit from selection.
			deselectOutfit(outfit_id);

			// 3. Remove category UUID to accordion tab mapping.
			mOutfitsMap.erase(outfits_iter);

			// 4. Remove outfit tab from accordion.
			mAccordion->removeCollapsibleCtrl(tab);

			// kill removed tab
			if (tab != NULL)
			{
				tab->die();
			}
		}
	}

	// Get changed items from inventory model and update outfit tabs
	// which might have been renamed.
	const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs();
	for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin();
		 items_iter != changed_items.end();
		 ++items_iter)
	{
		updateOutfitTab(*items_iter);
	}

	mAccordion->sort();
}
void LLInventoryModelBackgroundFetch::backgroundFetch()
{
	if (mBackgroundFetchActive && gAgent.getRegion())
	{
		// If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
		std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2");   
		if (gSavedSettings.getBOOL("UseHTTPInventory") && !url.empty()) 
		{
			bulkFetch(url);
			return;
		}
		
#if 1
		//--------------------------------------------------------------------------------
		// DEPRECATED OLD CODE
		//

		// No more categories to fetch, stop fetch process.
		if (mFetchQueue.empty())
		{
			llinfos << "Inventory fetch completed" << llendl;

			setAllFoldersFetched();
			return;
		}

		F32 fast_fetch_time = lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.1f);
		F32 slow_fetch_time = lerp(mMinTimeBetweenFetches, mMaxTimeBetweenFetches, 0.5f);
		if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() > slow_fetch_time)
		{
			// Double timeouts on failure.
			mMinTimeBetweenFetches = llmin(mMinTimeBetweenFetches * 2.f, 10.f);
			mMaxTimeBetweenFetches = llmin(mMaxTimeBetweenFetches * 2.f, 120.f);
			llinfos << "Inventory fetch times grown to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl;
			// fetch is no longer considered "timely" although we will wait for full time-out.
			mTimelyFetchPending = FALSE;
		}

		while(1)
		{
			if (mFetchQueue.empty())
			{
				break;
			}

			if(gDisconnected)
			{
				// Just bail if we are disconnected.
				break;
			}

			const FetchQueueInfo info = mFetchQueue.front();
			LLViewerInventoryCategory* cat = gInventory.getCategory(info.mCatUUID);

			// Category has been deleted, remove from queue.
			if (!cat)
			{
				mFetchQueue.pop_front();
				continue;
			}
			
			if (mFetchTimer.getElapsedTimeF32() > mMinTimeBetweenFetches && 
				LLViewerInventoryCategory::VERSION_UNKNOWN == cat->getVersion())
			{
				// Category exists but has no children yet, fetch the descendants
				// for now, just request every time and rely on retry timer to throttle.
				if (cat->fetch())
				{
					mFetchTimer.reset();
					mTimelyFetchPending = TRUE;
				}
				else
				{
					//  The catagory also tracks if it has expired and here it says it hasn't
					//  yet.  Get out of here because nothing is going to happen until we
					//  update the timers.
					break;
				}
			}
			// Do I have all my children?
			else if (gInventory.isCategoryComplete(info.mCatUUID))
			{
				// Finished with this category, remove from queue.
				mFetchQueue.pop_front();

				// Add all children to queue.
				LLInventoryModel::cat_array_t* categories;
				LLInventoryModel::item_array_t* items;
				gInventory.getDirectDescendentsOf(cat->getUUID(), categories, items);
				for (LLInventoryModel::cat_array_t::const_iterator it = categories->begin();
					 it != categories->end();
					 ++it)
				{
					mFetchQueue.push_back(FetchQueueInfo((*it)->getUUID(),info.mRecursive));
				}

				// We received a response in less than the fast time.
				if (mTimelyFetchPending && mFetchTimer.getElapsedTimeF32() < fast_fetch_time)
				{
					// Shrink timeouts based on success.
					mMinTimeBetweenFetches = llmax(mMinTimeBetweenFetches * 0.8f, 0.3f);
					mMaxTimeBetweenFetches = llmax(mMaxTimeBetweenFetches * 0.8f, 10.f);
					//llinfos << "Inventory fetch times shrunk to (" << mMinTimeBetweenFetches << ", " << mMaxTimeBetweenFetches << ")" << llendl;
				}

				mTimelyFetchPending = FALSE;
				continue;
			}
			else if (mFetchTimer.getElapsedTimeF32() > mMaxTimeBetweenFetches)
			{
				// Received first packet, but our num descendants does not match db's num descendants
				// so try again later.
				mFetchQueue.pop_front();

				if (mNumFetchRetries++ < MAX_FETCH_RETRIES)
				{
					// push on back of queue
					mFetchQueue.push_back(info);
				}
				mTimelyFetchPending = FALSE;
				mFetchTimer.reset();
				break;
			}

			// Not enough time has elapsed to do a new fetch
			break;
		}

		//
		// DEPRECATED OLD CODE
		//--------------------------------------------------------------------------------
#endif
	}
}
Esempio n. 6
0
void LLOutfitsList::refreshList(const LLUUID& category_id)
{
	LLInventoryModel::cat_array_t cat_array;
	LLInventoryModel::item_array_t item_array;

	// Collect all sub-categories of a given category.

	// <FS:ND> FIRE-6958/VWR-2862; Make sure to only collect folders of type FT_OUTFIT

	class ndOutfitsCollector: public LLIsType
	{
	public:
		ndOutfitsCollector()
			: LLIsType( LLAssetType::AT_CATEGORY )
		{ }

		virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item)
		{
			if( !LLIsType::operator()( cat, item ) )
				return false;

			if( cat && LLFolderType::FT_OUTFIT == cat->getPreferredType() )
				return true;

			return false;
		}
	};

	//	LLIsType is_category(LLAssetType::AT_CATEGORY);
	ndOutfitsCollector is_category;

	// </FS:ND>
	
	gInventory.collectDescendentsIf(
		category_id,
		cat_array,
		item_array,
		LLInventoryModel::EXCLUDE_TRASH,
		is_category);

	uuid_vec_t vadded;
	uuid_vec_t vremoved;

	// Create added and removed items vectors.
	computeDifference(cat_array, vadded, vremoved);

	// <FS:ND> FIRE-6958/VWR-2862; Handle large amounts of outfits, write a least a warning into the logs.
	if( vadded.size() > 128 )
		LL_WARNS() << "Large amount of outfits found: " << vadded.size() << " this may cause hangs and disconnects" << LL_ENDL;

	U32 nCap = gSavedSettings.getU32( "FSDisplaySavedOutfitsCap" );
	if( nCap && nCap < vadded.size() )
	{
		vadded.resize( nCap );
		LL_WARNS() << "Capped outfits to " << nCap << " due to debug setting FSDisplaySavedOutfitsCap" << LL_ENDL;
	}
	// </FS:ND>

	// <FS:Ansariel> FIRE-12939: Add outfit count to outfits list
	getChild<LLTextBox>("OutfitcountText")->setTextArg("COUNT", llformat("%d", cat_array.size()));

	// Handle added tabs.
	for (uuid_vec_t::const_iterator iter = vadded.begin();
		 iter != vadded.end();
		 ++iter)
	{
		const LLUUID cat_id = (*iter);
		LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
		if (!cat) continue;

		std::string name = cat->getName();

		outfit_accordion_tab_params tab_params(get_accordion_tab_params());
		LLAccordionCtrlTab* tab = LLUICtrlFactory::create<LLAccordionCtrlTab>(tab_params);
		if (!tab) continue;
		LLWearableItemsList* wearable_list = LLUICtrlFactory::create<LLWearableItemsList>(tab_params.wearable_list);
		wearable_list->setShape(tab->getLocalRect());
		tab->addChild(wearable_list);

		tab->setName(name);
		tab->setTitle(name);

		// *TODO: LLUICtrlFactory::defaultBuilder does not use "display_children" from xml. Should be investigated.
		tab->setDisplayChildren(false);

		// <FS:ND> Calling this when there's a lot of outfits causes horrible perfomance and disconnects, due to arrange eating so many cpu cycles.
		// mAccordion->addCollapsibleCtrl(tab);
		mAccordion->addCollapsibleCtrl(tab, false );
		// </FS:ND>	

		// Start observing the new outfit category.
		LLWearableItemsList* list  = tab->getChild<LLWearableItemsList>("wearable_items_list");
		if (!mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id)))
		{
			// Remove accordion tab if category could not be added to observer.
			mAccordion->removeCollapsibleCtrl(tab);

			// kill removed tab
				tab->die();
			continue;
		}

		// Map the new tab with outfit category UUID.
		mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab));

		tab->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onAccordionTabRightClick, this,
			_1, _2, _3, cat_id));

		// Setting tab focus callback to monitor currently selected outfit.
		tab->setFocusReceivedCallback(boost::bind(&LLOutfitsList::changeOutfitSelection, this, list, cat_id));

		// Setting callback to reset items selection inside outfit on accordion collapsing and expanding (EXT-7875)
		tab->setDropDownStateChangedCallback(boost::bind(&LLOutfitsList::resetItemSelection, this, list, cat_id));

		// force showing list items that don't match current filter(EXT-7158)
		list->setForceShowingUnmatchedItems(true);

		// Setting list commit callback to monitor currently selected wearable item.
		list->setCommitCallback(boost::bind(&LLOutfitsList::onSelectionChange, this, _1));

		// Setting list refresh callback to apply filter on list change.
		list->setRefreshCompleteCallback(boost::bind(&LLOutfitsList::onFilteredWearableItemsListRefresh, this, _1));

		list->setRightMouseDownCallback(boost::bind(&LLOutfitsList::onWearableItemsListRightClick, this, _1, _2, _3));

		// Fetch the new outfit contents.
		cat->fetch();

		// Refresh the list of outfit items after fetch().
		// Further list updates will be triggered by the category observer.
		list->updateList(cat_id);

		// If filter is currently applied we store the initial tab state and
		// open it to show matched items if any.
		if (!sFilterSubString.empty())
		{
			tab->notifyChildren(LLSD().with("action","store_state"));
			tab->setDisplayChildren(true);

			// Setting mForceRefresh flag will make the list refresh its contents
			// even if it is not currently visible. This is required to apply the
			// filter to the newly added list.
			list->setForceRefresh(true);

			list->setFilterSubString(sFilterSubString);
		}
	}

	// <FS:ND> We called mAccordion->addCollapsibleCtrl with false as second paramter and did not let it arrange itself each time. Do this here after all is said and done.
	mAccordion->arrange();
	// </FS:ND>

	// Handle removed tabs.
	for (uuid_vec_t::const_iterator iter=vremoved.begin(); iter != vremoved.end(); ++iter)
	{
		outfits_map_t::iterator outfits_iter = mOutfitsMap.find((*iter));
		if (outfits_iter != mOutfitsMap.end())
		{
			const LLUUID& outfit_id = outfits_iter->first;
			LLAccordionCtrlTab* tab = outfits_iter->second;

			// An outfit is removed from the list. Do the following:
			// 1. Remove outfit category from observer to stop monitoring its changes.
			mCategoriesObserver->removeCategory(outfit_id);

			// 2. Remove the outfit from selection.
			deselectOutfit(outfit_id);

			// 3. Remove category UUID to accordion tab mapping.
			mOutfitsMap.erase(outfits_iter);

			// 4. Remove outfit tab from accordion.
			mAccordion->removeCollapsibleCtrl(tab);

			// kill removed tab
			if (tab != NULL)
			{
				tab->die();
			}
		}
	}

	// Get changed items from inventory model and update outfit tabs
	// which might have been renamed.
	const LLInventoryModel::changed_items_t& changed_items = gInventory.getChangedIDs();
	for (LLInventoryModel::changed_items_t::const_iterator items_iter = changed_items.begin();
		 items_iter != changed_items.end();
		 ++items_iter)
	{
		updateOutfitTab(*items_iter);
	}

	mAccordion->sort();
}