Example #1
0
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLInventoryPanel *panel = mPtr;
		LLInventoryModel* model = panel->getModel();
		if(!model) return true;
		std::set<LLUUID> selected_items;
		panel->getRootFolder()->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 = panel->getRootFolder()->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;
					model->collectDescendentsIf(bridge->getUUID(),
												cat_array,
												item_array,
												LLInventoryModel::EXCLUDE_TRASH,
												is_buddy);
					S32 count = item_array.count();
					if(count > 0)
					{
						// create the session
						gIMMgr->setFloaterOpen(TRUE);
						S32 i;
						
						LLAvatarTracker& at = LLAvatarTracker::instance();
						LLUUID id;
						for(i = 0; i < count; ++i)
						{
							id = item_array.get(i)->getCreatorUUID();
							if(at.isBuddyOnline(id))
							{
								members.put(id);
							}
						}
					}
				}
				else
				{
					LLFolderViewItem* folder_item = panel->getRootFolder()->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++);
		}


		gIMMgr->addSession(
			name,
			type,
			members[0],
			members);
		
		return true;
	}
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
	}
}
// If we get back a normal response, handle it here.
void LLInventoryModelFetchDescendentsResponder::result(const LLSD& content)
{
	LLInventoryModelBackgroundFetch *fetcher = LLInventoryModelBackgroundFetch::getInstance();
	if (content.has("folders"))	
	{

		for(LLSD::array_const_iterator folder_it = content["folders"].beginArray();
			folder_it != content["folders"].endArray();
			++folder_it)
		{	
			LLSD folder_sd = *folder_it;
			

			//LLUUID agent_id = folder_sd["agent_id"];

			//if(agent_id != gAgent.getID())	//This should never happen.
			//{
			//	llwarns << "Got a UpdateInventoryItem for the wrong agent."
			//			<< llendl;
			//	break;
			//}

			LLUUID parent_id = folder_sd["folder_id"];
			LLUUID owner_id = folder_sd["owner_id"];
			S32    version  = (S32)folder_sd["version"].asInteger();
			S32    descendents = (S32)folder_sd["descendents"].asInteger();
			LLPointer<LLViewerInventoryCategory> tcategory = new LLViewerInventoryCategory(owner_id);

            if (parent_id.isNull())
            {
			    LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
			    for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray();
				    item_it != folder_sd["items"].endArray();
				    ++item_it)
			    {	
                    const LLUUID lost_uuid = gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND);
                    if (lost_uuid.notNull())
                    {
				        LLSD item = *item_it;
				        titem->unpackMessage(item);
				
                        LLInventoryModel::update_list_t update;
                        LLInventoryModel::LLCategoryUpdate new_folder(lost_uuid, 1);
                        update.push_back(new_folder);
                        gInventory.accountForUpdate(update);

                        titem->setParent(lost_uuid);
                        titem->updateParentOnServer(FALSE);
                        gInventory.updateItem(titem);
                        gInventory.notifyObservers("fetchDescendents");
                        
                    }
                }
            }

	        LLViewerInventoryCategory* pcat = gInventory.getCategory(parent_id);
			if (!pcat)
			{
				continue;
			}

			for(LLSD::array_const_iterator category_it = folder_sd["categories"].beginArray();
				category_it != folder_sd["categories"].endArray();
				++category_it)
			{	
				LLSD category = *category_it;
				tcategory->fromLLSD(category); 
				
				const BOOL recursive = getIsRecursive(tcategory->getUUID());
				
				if (recursive)
				{
					fetcher->mFetchQueue.push_back(LLInventoryModelBackgroundFetch::FetchQueueInfo(tcategory->getUUID(), recursive));
				}
				else if ( !gInventory.isCategoryComplete(tcategory->getUUID()) )
				{
					gInventory.updateCategory(tcategory);
				}

			}
			LLPointer<LLViewerInventoryItem> titem = new LLViewerInventoryItem;
			for(LLSD::array_const_iterator item_it = folder_sd["items"].beginArray();
				item_it != folder_sd["items"].endArray();
				++item_it)
			{	
				LLSD item = *item_it;
				titem->unpackMessage(item);
				
				gInventory.updateItem(titem);
			}

			// Set version and descendentcount according to message.
			LLViewerInventoryCategory* cat = gInventory.getCategory(parent_id);
			if(cat)
			{
				cat->setVersion(version);
				cat->setDescendentCount(descendents);
				cat->determineFolderType();
			}

		}
	}
		
	if (content.has("bad_folders"))
	{
		for(LLSD::array_const_iterator folder_it = content["bad_folders"].beginArray();
			folder_it != content["bad_folders"].endArray();
			++folder_it)
		{	
			LLSD folder_sd = *folder_it;
			
			// These folders failed on the dataserver.  We probably don't want to retry them.
			llinfos << "Folder " << folder_sd["folder_id"].asString() 
					<< "Error: " << folder_sd["error"].asString() << llendl;
		}
	}

	fetcher->incrBulkFetch(-1);
	
	if (fetcher->isBulkFetchProcessingComplete())
	{
		llinfos << "Inventory fetch completed" << llendl;
		fetcher->setAllFoldersFetched();
	}
	
	gInventory.notifyObservers("fetchDescendents");
}
Example #4
0
// Checked: 2010-03-14 (RLVa-1.1.3a) | Added: RLVa-1.2.0a
void RlvRenameOnWearObserver::doneIdle()
{
	const LLViewerInventoryCategory* pRlvRoot = NULL; LLVOAvatar* pAvatar = gAgent.getAvatarObject();
	if ( (RlvSettings::getEnableSharedWear()) || (!RlvSettings::getSharedInvAutoRename()) || (LLStartUp::getStartupState() < STATE_STARTED) || 
		 (!pAvatar) || ((pRlvRoot = RlvInventory::instance().getSharedRoot()) == NULL) )
	{
		delete this;
		return;
	}

	const LLViewerJointAttachment* pAttachPt = NULL; S32 idxAttachPt = 0;
//	RLV_ASSERT(mComplete.size() > 0);	// Catch instances where we forgot to call startFetch()
	for (uuid_vec_t::const_iterator itItem = mComplete.begin(); itItem != mComplete.end(); ++itItem)
	{
		const LLUUID& idAttachItem = *itItem;

		// If the item resides under #RLV we'll rename it directly; otherwise settle for "renaming" all of its links residing under #RLV
		LLInventoryModel::item_array_t items;
		if (gInventory.isObjectDescendentOf(idAttachItem, pRlvRoot->getUUID()))
			items.push_back(gInventory.getItem(idAttachItem));
		else
			items = gInventory.collectLinkedItems(idAttachItem, pRlvRoot->getUUID());
		if (items.empty())
			continue;

		if ( ((pAttachPt = pAvatar->getWornAttachmentPoint(idAttachItem)) == NULL) ||
			 ((idxAttachPt = RlvAttachPtLookup::getAttachPointIndex(pAttachPt)) == 0) )
		{
//			RLV_ASSERT(false);
			continue;
		}

		for (S32 idxItem = 0, cntItem = items.count(); idxItem < cntItem; idxItem++)
		{
			LLViewerInventoryItem* pItem = items.get(idxItem);
			if (!pItem)
				continue;

			S32 idxAttachPtItem = RlvAttachPtLookup::getAttachPointIndex(pItem);
			if ( (idxAttachPt == idxAttachPtItem) || (idxAttachPtItem) )
				continue;

			std::string strAttachPt = pAttachPt->getName();
			LLStringUtil::toLower(strAttachPt);

			// If we can modify the item then we rename it directly, otherwise we create a new folder and move it
			if (pItem->getPermissions().allowModifyBy(gAgent.getID()))
			{
				std::string strName = pItem->getName();
				LLStringUtil::truncate(strName, DB_INV_ITEM_NAME_STR_LEN - strAttachPt.length() - 3);

				strName += " (" + strAttachPt + ")";

				pItem->rename(strName);
				pItem->updateServer(FALSE);
				gInventory.addChangedMask(LLInventoryObserver::LABEL, pItem->getUUID());
			}
			else
			{
				// Don't do anything if the item is a direct descendant of the shared root, or a folded folder
				LLViewerInventoryCategory* pFolder = gInventory.getCategory(pItem->getParentUUID());
				if ( (pFolder) && (pFolder->getUUID() != pRlvRoot->getUUID()) && (!RlvInventory::isFoldedFolder(pFolder, false)) )
				{
					std::string strFolderName = ".(" + strAttachPt + ")";

					// Rename the item's parent folder if it's called "New Folder", isn't directly under #RLV and contains exactly 1 object
					if ( (NEW_CATEGORY_NAME == pFolder->getName()) && 
						 (pFolder->getParentUUID() != pRlvRoot->getUUID()) && 
						 (1 == RlvInventory::getDirectDescendentsCount(pFolder, LLAssetType::AT_OBJECT)) )
					{
						pFolder->rename(strFolderName);
						pFolder->updateServer(FALSE);
						gInventory.addChangedMask(LLInventoryObserver::LABEL, pFolder->getUUID());
					}
					else
					{
						// "No modify" item with a non-renameable parent: create a new folder named and move the item into it
						LLUUID idAttachFolder = gInventory.createNewCategory(pFolder->getUUID(), LLAssetType::AT_NONE, strFolderName);
						move_inventory_item(gAgent.getID(), gAgent.getSessionID(), pItem->getUUID(), idAttachFolder, std::string(), NULL);
					}
				}
			}
		}
	}
	gInventory.notifyObservers();

	delete this;
}
Example #5
0
//static
void LLLocalInventory::loadInvCache(std::string filename)
{
	std::string extension = gDirUtilp->getExtension(filename);
	std::string inv_filename = filename;
	if(extension == "gz")
	{
		LLUUID random;
		random.generate();
		inv_filename = filename.substr(0, filename.length() - 3) + "." + random.asString();

		if(!gunzip_file(filename, inv_filename))
		{
			// failure... message?
			return;
		}
	}

	LLInventoryModel::cat_array_t cats;
	LLInventoryModel::item_array_t items;
	bool is_cache_obsolete = false;
	if(LLInventoryModel::loadFromFile(inv_filename, cats, items, is_cache_obsolete))
	{
		// create a container category for everything
		LLViewerInventoryCategory* container = new LLViewerInventoryCategory(gAgent.getID());
		container->rename(gDirUtilp->getBaseFileName(filename, false));
		LLUUID container_id;
		container_id.generate();
		container->setUUID(container_id);
		container->setParent(gSystemFolderRoot);
		container->setPreferredType(LLAssetType::AT_NONE);
		LLInventoryModel::update_map_t container_update;
		++container_update[container->getParentUUID()];
		gInventory.accountForUpdate(container_update);
		gInventory.updateCategory(container);
		gInventory.notifyObservers();

		LLViewerInventoryCategory* orphaned_items = new LLViewerInventoryCategory(gAgent.getID());
		orphaned_items->rename("Orphaned Items");
		LLUUID orphaned_items_id;

		orphaned_items_id.generate();
		orphaned_items->setUUID(orphaned_items_id);
		orphaned_items->setParent(container_id);
		orphaned_items->setPreferredType(LLAssetType::AT_NONE);
		
		LLInventoryModel::update_map_t orphaned_items_update;
		++orphaned_items_update[orphaned_items->getParentUUID()];
		gInventory.accountForUpdate(orphaned_items_update);
		gInventory.updateCategory(orphaned_items);
		gInventory.notifyObservers();
		
		//conflict handling
		std::map<LLUUID,LLUUID> conflicting_cats;
		int dropped_cats = 0;
		int dropped_items = 0;

		// Add all categories
		LLInventoryModel::cat_array_t::iterator cat_iter = cats.begin();
		LLInventoryModel::cat_array_t::iterator cat_end = cats.end();
		for(; cat_iter != cat_end; ++cat_iter)
		{
			// Conditionally change its parent
			// Note: Should I search for missing parent id's?

			//if the parent is null, it goes in the very root of the tree!
			if((*cat_iter)->getParentUUID().isNull())
			{
				(*cat_iter)->setParent(container_id);
			}
			// If the parent exists and outside of pretend inventory, generate a new uuid
			else if(gInventory.getCategory((*cat_iter)->getParentUUID()))
			{
				if(!gInventory.isObjectDescendentOf((*cat_iter)->getParentUUID(), gSystemFolderRoot, TRUE))
				{
					std::map<LLUUID,LLUUID>::iterator itr = conflicting_cats.find((*cat_iter)->getParentUUID());
					if(itr == conflicting_cats.end())
					{
						dropped_cats++;
						continue;
					}
					(*cat_iter)->setParent(itr->second);
				}
			} else {
				//well balls, this is orphaned.
				(*cat_iter)->setParent(orphaned_items_id);
			}
			// If this category already exists, generate a new uuid
			if(gInventory.getCategory((*cat_iter)->getUUID()))
			{
				LLUUID cat_random;
				cat_random.generate();
				conflicting_cats[(*cat_iter)->getUUID()] = cat_random;
				(*cat_iter)->setUUID(cat_random);
			}

			LLInventoryModel::update_map_t update;
			++update[(*cat_iter)->getParentUUID()];
			gInventory.accountForUpdate(update);
			gInventory.updateCategory(*cat_iter);
			gInventory.notifyObservers();
		}

		// Add all items
		LLInventoryModel::item_array_t::iterator item_iter = items.begin();
		LLInventoryModel::item_array_t::iterator item_end = items.end();
		for(; item_iter != item_end; ++item_iter)
		{
			// Conditionally change its parent
			// Note: Should I search for missing parent id's?

			//if the parent is null, it goes in the very root of the tree!
			if((*item_iter)->getParentUUID().isNull())
			{
				(*item_iter)->setParent(container_id);
			}

			// If the parent exists and outside of pretend inventory, generate a new uuid
			if(gInventory.getCategory((*item_iter)->getParentUUID()))
			{
				if(!gInventory.isObjectDescendentOf((*item_iter)->getParentUUID(), gSystemFolderRoot, TRUE))
				{
					std::map<LLUUID,LLUUID>::iterator itr = conflicting_cats.find((*item_iter)->getParentUUID());
					if(itr == conflicting_cats.end())
					{
						dropped_items++;
						continue;
					}
					(*item_iter)->setParent(itr->second);
				}
			} else {
				//well balls, this is orphaned.
				(*item_iter)->setParent(orphaned_items_id);
			}
			// Avoid conflicts with real inventory...
			// If this item id already exists, generate a new uuid
			if(gInventory.getItem((*item_iter)->getUUID()))
			{
				LLUUID item_random;
				item_random.generate();
				(*item_iter)->setUUID(item_random);
			}
			
			LLInventoryModel::update_map_t update;
			++update[(*item_iter)->getParentUUID()];
			gInventory.accountForUpdate(update);
			gInventory.updateItem(*item_iter);
			gInventory.notifyObservers();
		}
		
		// Quality time
		if(dropped_items || dropped_cats)
		{
			std::ostringstream message;
			message << "Some items were ignored due to conflicts:\n\n";
			if(dropped_cats) message << dropped_cats << " folders\n";
			if(dropped_items) message << dropped_items << " items\n";

			LLSD args;
			args["ERROR_MESSAGE"] = message.str();
			LLNotifications::instance().add("ErrorMessage", args);
		}
		conflicting_cats.clear();// srsly dont think this is need but w/e :D
	}

	// remove temporary unzipped file
	if(extension == "gz")
	{
		LLFile::remove(inv_filename);
	}

}
Example #6
0
void LLInventoryCategoriesObserver::changed(U32 mask)
{
    if (!mCategoryMap.size())
        return;

    std::vector<LLUUID> deleted_categories_ids;

    for (category_map_t::iterator iter = mCategoryMap.begin();
            iter != mCategoryMap.end();
            ++iter)
    {
        const LLUUID& cat_id = (*iter).first;
        LLCategoryData& cat_data = (*iter).second;

        LLViewerInventoryCategory* category = gInventory.getCategory(cat_id);
        if (!category)
        {
            LL_WARNS() << "Category : Category id = " << cat_id << " disappeared" << LL_ENDL;
            cat_data.mCallback();
            // Keep track of those deleted categories so we can remove them
            deleted_categories_ids.push_back(cat_id);
            continue;
        }

        const S32 version = category->getVersion();
        const S32 expected_num_descendents = category->getDescendentCount();
        if ((version == LLViewerInventoryCategory::VERSION_UNKNOWN) ||
                (expected_num_descendents == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN))
        {
            continue;
        }

        // Check number of known descendents to find out whether it has changed.
        LLInventoryModel::cat_array_t* cats;
        LLInventoryModel::item_array_t* items;
        gInventory.getDirectDescendentsOf(cat_id, cats, items);
        if (!cats || !items)
        {
            LL_WARNS() << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << LL_ENDL;
            // NULL means the call failed -- cats/items map doesn't exist (note: this does NOT mean
            // that the cat just doesn't have any items or subfolders).
            // Unrecoverable, so just skip this category.

            llassert(cats != NULL && items != NULL);

            continue;
        }

        const S32 current_num_known_descendents = cats->count() + items->count();

        bool cat_changed = false;

        // If category version or descendents count has changed
        // update category data in mCategoryMap
        if (version != cat_data.mVersion || current_num_known_descendents != cat_data.mDescendentsCount)
        {
            cat_data.mVersion = version;
            cat_data.mDescendentsCount = current_num_known_descendents;
            cat_changed = true;
        }

        // If any item names have changed, update the name hash
        // Only need to check if (a) name hash has not previously been
        // computed, or (b) a name has changed.
        if (!cat_data.mIsNameHashInitialized || (mask & LLInventoryObserver::LABEL))
        {
            LLMD5 item_name_hash = gInventory.hashDirectDescendentNames(cat_id);
            if (cat_data.mItemNameHash != item_name_hash)
            {
                cat_data.mIsNameHashInitialized = true;
                cat_data.mItemNameHash = item_name_hash;
                cat_changed = true;
            }
        }

        // If anything has changed above, fire the callback.
        if (cat_changed)
            cat_data.mCallback();
    }

    // Remove deleed categories from the list
    for (std::vector<LLUUID>::iterator deleted_id = deleted_categories_ids.begin(); deleted_id != deleted_categories_ids.end(); ++deleted_id)
    {
        removeCategory(*deleted_id);
    }
}
	bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
	{
		LLInventoryPanel *panel = mPtr;
		LLInventoryModel* model = panel->getModel();
		if(!model) return true;
		std::set<LLUUID> selected_items = panel->getRootFolder()->getSelectionList();

		std::string name;
		static int session_num = 1;

		std::vector<LLUUID> members;
		EInstantMessage type = IM_SESSION_CONFERENCE_START;

// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9)
		bool fRlvCanStartIM = true;
// [/RLVa:KB]

		for (std::set<LLUUID>::const_iterator iter = selected_items.begin(); iter != selected_items.end(); iter++)
		{

			LLUUID item = *iter;
			LLFolderViewItem* folder_item = panel->getRootFolder()->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;
					model->collectDescendentsIf(bridge->getUUID(),
												cat_array,
												item_array,
												LLInventoryModel::EXCLUDE_TRASH,
												is_buddy);
					S32 count = item_array.size();
					if(count > 0)
					{
						// create the session
						gIMMgr->setFloaterOpen(TRUE);

						LLAvatarTracker& at = LLAvatarTracker::instance();
						LLUUID id;
						for(S32 i = 0; i < count; ++i)
						{
							id = item_array.at(i)->getCreatorUUID();
							if(at.isBuddyOnline(id))
							{
// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9)
								fRlvCanStartIM &= RlvActions::canStartIM(id);
// [RLVa:KB]
								members.push_back(id);
							}
						}
					}
				}
				else
				{
					LLFolderViewItem* folder_item = panel->getRootFolder()->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))
							{
// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9)
								fRlvCanStartIM &= RlvActions::canStartIM(id);
// [RLVa:KB]
								members.push_back(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

// [RLVa:KB] - Checked: 2013-05-08 (RLVa-1.4.9)
		if (!fRlvCanStartIM)
		{
			make_ui_sound("UISndIvalidOp");
			RlvUtil::notifyBlocked(RLV_STRING_BLOCKED_STARTCONF);
			return true;
		}
// [/RLVa:KB]

		if (name.empty())
		{
			name = llformat("Session %d", session_num++);
		}


		gIMMgr->addSession(
			name,
			type,
			members[0],
			members);
		
		return true;
	}
void AISUpdate::parseMeta(const LLSD& update)
{
	// parse _categories_removed -> mObjectsDeletedIds
	uuid_list_t cat_ids;
	parseUUIDArray(update,"_categories_removed",cat_ids);
	for (uuid_list_t::const_iterator it = cat_ids.begin();
		 it != cat_ids.end(); ++it)
	{
		LLViewerInventoryCategory *cat = gInventory.getCategory(*it);
		if(cat)
		{
			mCatDescendentDeltas[cat->getParentUUID()]--;
			mObjectsDeletedIds.insert(*it);
		}
		else
		{
			LL_WARNS("Inventory") << "removed category not found " << *it << LL_ENDL;
		}
	}

	// parse _categories_items_removed -> mObjectsDeletedIds
	uuid_list_t item_ids;
	parseUUIDArray(update,"_category_items_removed",item_ids);
	parseUUIDArray(update,"_removed_items",item_ids);
	for (uuid_list_t::const_iterator it = item_ids.begin();
		 it != item_ids.end(); ++it)
	{
		LLViewerInventoryItem *item = gInventory.getItem(*it);
		if(item)
		{
			mCatDescendentDeltas[item->getParentUUID()]--;
			mObjectsDeletedIds.insert(*it);
		}
		else
		{
			LL_WARNS("Inventory") << "removed item not found " << *it << LL_ENDL;
		}
	}

	// parse _broken_links_removed -> mObjectsDeletedIds
	uuid_list_t broken_link_ids;
	parseUUIDArray(update,"_broken_links_removed",broken_link_ids);
	for (uuid_list_t::const_iterator it = broken_link_ids.begin();
		 it != broken_link_ids.end(); ++it)
	{
		LLViewerInventoryItem *item = gInventory.getItem(*it);
		if(item)
		{
			mCatDescendentDeltas[item->getParentUUID()]--;
			mObjectsDeletedIds.insert(*it);
		}
		else
		{
			LL_WARNS("Inventory") << "broken link not found " << *it << LL_ENDL;
		}
	}

	// parse _created_items
	parseUUIDArray(update,"_created_items",mItemIds);

	// parse _created_categories
	parseUUIDArray(update,"_created_categories",mCategoryIds);

	// Parse updated category versions.
	const std::string& ucv = "_updated_category_versions";
	if (update.has(ucv))
	{
		for(LLSD::map_const_iterator it = update[ucv].beginMap(),
				end = update[ucv].endMap();
			it != end; ++it)
		{
			const LLUUID id((*it).first);
			S32 version = (*it).second.asInteger();
			mCatVersionsUpdated[id] = version;
		}
	}
}
void AISUpdate::doUpdate()
{
	// Do version/descendent accounting.
	for (std::map<LLUUID,S32>::const_iterator catit = mCatDescendentDeltas.begin();
		 catit != mCatDescendentDeltas.end(); ++catit)
	{
		LL_DEBUGS("Inventory") << "descendent accounting for " << catit->first << LL_ENDL;

		const LLUUID cat_id(catit->first);
		// Don't account for update if we just created this category.
		if (mCategoriesCreated.find(cat_id) != mCategoriesCreated.end())
		{
			LL_DEBUGS("Inventory") << "Skipping version increment for new category " << cat_id << LL_ENDL;
			continue;
		}

		// Don't account for update unless AIS told us it updated that category.
		if (mCatVersionsUpdated.find(cat_id) == mCatVersionsUpdated.end())
		{
			LL_DEBUGS("Inventory") << "Skipping version increment for non-updated category " << cat_id << LL_ENDL;
			continue;
		}

		// If we have a known descendent count, set that now.
		LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
		if (cat)
		{
			S32 descendent_delta = catit->second;
			S32 old_count = cat->getDescendentCount();
			LL_DEBUGS("Inventory") << "Updating descendent count for "
								   << cat->getName() << " " << cat_id
								   << " with delta " << descendent_delta << " from "
								   << old_count << " to " << (old_count+descendent_delta) << LL_ENDL;
			LLInventoryModel::LLCategoryUpdate up(cat_id, descendent_delta);
			gInventory.accountForUpdate(up);
		}
		else
		{
			LL_DEBUGS("Inventory") << "Skipping version accounting for unknown category " << cat_id << LL_ENDL;
		}
	}

	// CREATE CATEGORIES
	for (deferred_category_map_t::const_iterator create_it = mCategoriesCreated.begin();
		 create_it != mCategoriesCreated.end(); ++create_it)
	{
		LLUUID category_id(create_it->first);
		LLPointer<LLViewerInventoryCategory> new_category = create_it->second;

		gInventory.updateCategory(new_category, LLInventoryObserver::CREATE);
		LL_DEBUGS("Inventory") << "created category " << category_id << LL_ENDL;
	}

	// UPDATE CATEGORIES
	for (deferred_category_map_t::const_iterator update_it = mCategoriesUpdated.begin();
		 update_it != mCategoriesUpdated.end(); ++update_it)
	{
		LLUUID category_id(update_it->first);
		LLPointer<LLViewerInventoryCategory> new_category = update_it->second;
		// Since this is a copy of the category *before* the accounting update, above,
		// we need to transfer back the updated version/descendent count.
		LLViewerInventoryCategory* curr_cat = gInventory.getCategory(new_category->getUUID());
		if (!curr_cat)
		{
			LL_WARNS("Inventory") << "Failed to update unknown category " << new_category->getUUID() << LL_ENDL;
		}
		else
		{
			new_category->setVersion(curr_cat->getVersion());
			new_category->setDescendentCount(curr_cat->getDescendentCount());
			gInventory.updateCategory(new_category);
			LL_DEBUGS("Inventory") << "updated category " << new_category->getName() << " " << category_id << LL_ENDL;
		}
	}

	// CREATE ITEMS
	for (deferred_item_map_t::const_iterator create_it = mItemsCreated.begin();
		 create_it != mItemsCreated.end(); ++create_it)
	{
		LLUUID item_id(create_it->first);
		LLPointer<LLViewerInventoryItem> new_item = create_it->second;

		// FIXME risky function since it calls updateServer() in some
		// cases.  Maybe break out the update/create cases, in which
		// case this is create.
		LL_DEBUGS("Inventory") << "created item " << item_id << LL_ENDL;
		gInventory.updateItem(new_item, LLInventoryObserver::CREATE);
	}
	
	// UPDATE ITEMS
	for (deferred_item_map_t::const_iterator update_it = mItemsUpdated.begin();
		 update_it != mItemsUpdated.end(); ++update_it)
	{
		LLUUID item_id(update_it->first);
		LLPointer<LLViewerInventoryItem> new_item = update_it->second;
		// FIXME risky function since it calls updateServer() in some
		// cases.  Maybe break out the update/create cases, in which
		// case this is update.
		LL_DEBUGS("Inventory") << "updated item " << item_id << LL_ENDL;
		//LL_DEBUGS("Inventory") << ll_pretty_print_sd(new_item->asLLSD()) << LL_ENDL;
		gInventory.updateItem(new_item);
	}

	// DELETE OBJECTS
	for (uuid_list_t::const_iterator del_it = mObjectsDeletedIds.begin();
		 del_it != mObjectsDeletedIds.end(); ++del_it)
	{
		LL_DEBUGS("Inventory") << "deleted item " << *del_it << LL_ENDL;
		gInventory.onObjectDeletedFromServer(*del_it, false, false, false);
	}

	// TODO - how can we use this version info? Need to be sure all
	// changes are going through AIS first, or at least through
	// something with a reliable responder.
	for (uuid_int_map_t::iterator ucv_it = mCatVersionsUpdated.begin();
		 ucv_it != mCatVersionsUpdated.end(); ++ucv_it)
	{
		const LLUUID id = ucv_it->first;
		S32 version = ucv_it->second;
		LLViewerInventoryCategory *cat = gInventory.getCategory(id);
		LL_DEBUGS("Inventory") << "cat version update " << cat->getName() << " to version " << cat->getVersion() << LL_ENDL;
		if (cat->getVersion() != version)
		{
			LL_WARNS() << "Possible version mismatch for category " << cat->getName()
					<< ", viewer version " << cat->getVersion()
					<< " server version " << version << LL_ENDL;
		}
	}

	gInventory.notifyObservers();
}
bool LLInventoryPanel::beginIMSession()
{
	std::set<LLUUID> selected_items = mFolderRoot->getSelectionList();

	std::string name;
	static int session_num = 1;

//	LLDynamicArray<LLUUID> members;
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h
	uuid_vec_t members;
// [/RLVa:KB]
//	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 = mFolderRoot->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);
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h
							members.push_back(id);
// [/RLVa:KB]
						}
					}
				}
			}
			else
			{
				LLFolderViewItem* folder_item = mFolderRoot->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);
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h
							members.push_back(id);
// [/RLVa:KB]
						}
					}
				} //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);
//	}
// [RLVa:KB] - Checked: 2011-04-11 (RLVa-1.3.0h) | Added: RLVa-1.3.0h
	LLAvatarActions::startConference(members);
// [/RLVa:KB]
		
	return true;
}
void LLCOFWearables::refresh()
{
	const LLUUID cof_id = LLAppearanceMgr::instance().getCOF();
	if (cof_id.isNull())
	{
		llwarns << "COF ID cannot be NULL" << llendl;
		return;
	}

	LLViewerInventoryCategory* catp = gInventory.getCategory(cof_id);
	if (!catp)
	{
		llwarns << "COF category cannot be NULL" << llendl;
		return;
	}

	// BAP - this check has to be removed because an item name change does not
	// change cat version - ie, checking version is not a complete way
	// of finding out whether anything has changed in this category.
	//if (mCOFVersion == catp->getVersion()) return;

	mCOFVersion = catp->getVersion();

	// Save current scrollbar position.
	typedef std::map<LLFlatListView*, LLRect> scroll_pos_map_t;
	scroll_pos_map_t saved_scroll_pos;

	saved_scroll_pos[mAttachments] = mAttachments->getVisibleContentRect();
	saved_scroll_pos[mClothing] = mClothing->getVisibleContentRect();
	saved_scroll_pos[mBodyParts] = mBodyParts->getVisibleContentRect();

	// Save current selection.
	typedef std::vector<LLSD> values_vector_t;
	typedef std::map<LLFlatListView*, values_vector_t> selection_map_t;

	selection_map_t preserve_selection;

	mAttachments->getSelectedValues(preserve_selection[mAttachments]);
	mClothing->getSelectedValues(preserve_selection[mClothing]);
	mBodyParts->getSelectedValues(preserve_selection[mBodyParts]);

	clear();

	LLInventoryModel::cat_array_t cats;
	LLInventoryModel::item_array_t cof_items;

	gInventory.collectDescendents(cof_id, cats, cof_items, LLInventoryModel::EXCLUDE_TRASH);

	populateAttachmentsAndBodypartsLists(cof_items);


	LLAppearanceMgr::wearables_by_type_t clothing_by_type(LLWearableType::WT_COUNT);
	LLAppearanceMgr::getInstance()->divvyWearablesByType(cof_items, clothing_by_type);
	
	populateClothingList(clothing_by_type);

	// Restore previous selection
	for (selection_map_t::iterator
			 iter = preserve_selection.begin(),
			 iter_end = preserve_selection.end();
		 iter != iter_end; ++iter)
	{
		LLFlatListView* list = iter->first;
		if (!list) continue;

		//restoring selection should not fire commit callbacks
		list->setCommitOnSelectionChange(false);

		const values_vector_t& values = iter->second;
		for (values_vector_t::const_iterator
				 value_it = values.begin(),
				 value_it_end = values.end();
			 value_it != value_it_end; ++value_it)
		{
			// value_it may be null because of dummy items
			// Dummy items have no ID
			if(value_it->asUUID().notNull())
			{
				list->selectItemByValue(*value_it);
			}
		}

		list->setCommitOnSelectionChange(true);
	}

	// Restore previous scrollbar position.
	for (scroll_pos_map_t::const_iterator it = saved_scroll_pos.begin(); it != saved_scroll_pos.end(); ++it)
	{
		LLFlatListView* list = it->first;
		LLRect scroll_pos = it->second;

		list->scrollToShowRect(scroll_pos);
	}
}
void LLInventoryFetchComboObserver::fetch(
	const folder_ref_t& folder_ids,
	const item_ref_t& item_ids)
{
	lldebugs << "LLInventoryFetchComboObserver::fetch()" << llendl;
	for(folder_ref_t::const_iterator fit = folder_ids.begin(); fit != folder_ids.end(); ++fit)
	{
		LLViewerInventoryCategory* cat = gInventory.getCategory(*fit);
		if(!cat) continue;
		if(!gInventory.isCategoryComplete(*fit))
		{
			cat->fetchDescendents();
			lldebugs << "fetching folder " << *fit <<llendl;
			mIncompleteFolders.push_back(*fit);
		}
		else
		{
			mCompleteFolders.push_back(*fit);
			lldebugs << "completing folder " << *fit <<llendl;
		}
	}

	// Now for the items - we fetch everything which is not a direct
	// descendent of an incomplete folder because the item will show
	// up in an inventory descendents message soon enough so we do not
	// have to fetch it individually.
	LLSD items_llsd;
	LLUUID owner_id;
	for(item_ref_t::const_iterator iit = item_ids.begin(); iit != item_ids.end(); ++iit)
	{
		LLViewerInventoryItem* item = gInventory.getItem(*iit);
		if(!item)
		{
			lldebugs << "uanble to find item " << *iit << llendl;
			continue;
		}
		if(item->isComplete())
		{
			// It's complete, so put it on the complete container.
			mCompleteItems.push_back(*iit);
			lldebugs << "completing item " << *iit << llendl;
			continue;
		}
		else
		{
			mIncompleteItems.push_back(*iit);
			owner_id = item->getPermissions().getOwner();
		}
		if(std::find(mIncompleteFolders.begin(), mIncompleteFolders.end(), item->getParentUUID()) == mIncompleteFolders.end())
		{
			LLSD item_entry;
			item_entry["owner_id"] = owner_id;
			item_entry["item_id"] = (*iit);
			items_llsd.append(item_entry);
		}
		else
		{
			lldebugs << "not worrying about " << *iit << llendl;
		}
	}
	fetch_items_from_llsd(items_llsd);
}
Example #13
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();

		static LLXMLNodePtr accordionXmlNode = getAccordionTabXMLNode();
		LLAccordionCtrlTab* tab = LLUICtrlFactory::defaultBuilder<LLAccordionCtrlTab>(accordionXmlNode, NULL, NULL);

		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
			if (tab != NULL)
			{
				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();
}
Example #14
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();
}