Commits

Anonymous committed b7e00a4 Merge

merge from PE's viewer-trunk

  • Participants
  • Parent commits 229a224, 7f7fe63

Comments (0)

Files changed (31)

indra/llui/llaccordionctrltab.cpp

 	addChild(panel,0);
 }
 
+void LLAccordionCtrlTab::setTitle(const std::string& title)
+{
+	LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
+	if (header)
+	{
+		header->setTitle(title);
+	}
+}
+
+boost::signals2::connection LLAccordionCtrlTab::setFocusReceivedCallback(const focus_signal_t::slot_type& cb)
+{
+	LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
+	if (header)
+	{
+		return header->setFocusReceivedCallback(cb);
+	}
+	return boost::signals2::connection();
+}
+
+boost::signals2::connection LLAccordionCtrlTab::setFocusLostCallback(const focus_signal_t::slot_type& cb)
+{
+	LLAccordionCtrlTabHeader* header = findChild<LLAccordionCtrlTabHeader>(DD_HEADER_NAME);
+	if (header)
+	{
+		return header->setFocusLostCallback(cb);
+	}
+	return boost::signals2::connection();
+}
 
 LLView*	LLAccordionCtrlTab::findContainerView()
 {

indra/llui/llaccordionctrltab.h

 	void		setAccordionView(LLView* panel);
 	LLView*		getAccordionView() { return mContainerPanel; };
 
+	// Set text in LLAccordionCtrlTabHeader
+	void setTitle(const std::string& title);
+
+	boost::signals2::connection setFocusReceivedCallback(const focus_signal_t::slot_type& cb);
+	boost::signals2::connection setFocusLostCallback(const focus_signal_t::slot_type& cb);
+
 	bool getCollapsible() {return mCollapsible;};
 
 	void setCollapsible(bool collapsible) {mCollapsible = collapsible;};

indra/newview/llchannelmanager.cpp

 	}
 }
 
+// static
+LLNotificationsUI::LLScreenChannel* LLChannelManager::getNotificationScreenChannel()
+{
+	LLNotificationsUI::LLScreenChannel* channel = static_cast<LLNotificationsUI::LLScreenChannel*>
+	(LLNotificationsUI::LLChannelManager::getInstance()->
+										findChannelByID(LLUUID(gSavedSettings.getString("NotificationChannelUUID"))));
+
+	if (channel == NULL)
+	{
+		llwarns << "Can't find screen channel by NotificationChannelUUID" << llendl;
+		llassert(!"Can't find screen channel by NotificationChannelUUID");
+	}
+
+	return channel;
+}
+

indra/newview/llchannelmanager.h

 	 */
 	void killToastsFromChannel(const LLUUID& channel_id, const LLScreenChannel::Matcher& matcher);
 
+	/**
+	 * Returns notification screen channel.
+	 */
+	static LLNotificationsUI::LLScreenChannel* getNotificationScreenChannel();
+
 private:
 
 	LLScreenChannel* createChannel(LLChannelManager::Params& p);

indra/newview/llcofwearables.cpp

 		U32 size = clothing_by_type[type].size();
 		if (size) continue;
 
-		//*TODO create dummy item panel
-		
-		//*TODO add dummy item panel -> mClothing->addItem(dummy_item_panel, item->getUUID(), ADD_BOTTOM, false);
-
+		EWearableType w_type = static_cast<EWearableType>(type);
+		LLPanelInventoryListItemBase* item_panel = LLPanelDummyClothingListItem::create(w_type);
+		if(!item_panel) continue;
+		mClothing->addItem(item_panel, LLUUID::null, ADD_BOTTOM, false);
 		addWearableTypeSeparator(mClothing);
 	}
 }

indra/newview/llimfloater.cpp

 #include "llsyswellwindow.h"
 #include "lltrans.h"
 #include "llchathistory.h"
+#include "llnotifications.h"
 #include "llviewerwindow.h"
 #include "llvoicechannel.h"
 #include "lltransientfloatermgr.h"
 //static
 LLIMFloater* LLIMFloater::show(const LLUUID& session_id)
 {
+	closeHiddenIMToasts();
+
 	if (!gIMMgr->hasSession(session_id)) return NULL;
 
 	if(!isChatMultiTab())
 }
 
 // static
+void LLIMFloater::closeHiddenIMToasts()
+{
+	class IMToastMatcher: public LLNotificationsUI::LLScreenChannel::Matcher
+	{
+	public:
+		bool matches(const LLNotificationPtr notification) const
+		{
+			// "notifytoast" type of notifications is reserved for IM notifications
+			return "notifytoast" == notification->getType();
+		}
+	};
+
+	LLNotificationsUI::LLScreenChannel* channel = LLNotificationsUI::LLChannelManager::getNotificationScreenChannel();
+	if (channel != NULL)
+	{
+		channel->closeHiddenToasts(IMToastMatcher());
+	}
+}
+
+// static
 bool LLIMFloater::isChatMultiTab()
 {
 	// Restart is required in order to change chat window type.

indra/newview/llimfloater.h

 	// Remove the "User is typing..." indicator.
 	void removeTypingIndicator(const LLIMInfo* im_info = NULL);
 
+	static void closeHiddenIMToasts();
+
 	LLPanelChatControlPanel* mControlPanel;
 	LLUUID mSessionID;
 	S32 mLastMessageIndex;

indra/newview/llinventorybridge.cpp

 									 const LLUUID& new_parent_id,
 									 BOOL restamp)
 {
-	if (item->getParentUUID() != new_parent_id)
-	{
-		LLInventoryModel::update_list_t update;
-		LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1);
-		update.push_back(old_folder);
-		LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
-		update.push_back(new_folder);
-		gInventory.accountForUpdate(update);
-
-		LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
-		new_item->setParent(new_parent_id);
-		new_item->updateParentOnServer(restamp);
-		model->updateItem(new_item);
-		model->notifyObservers();
-	}
+	change_item_parent(model, item, new_parent_id, restamp);
 }
 
 // static

indra/newview/llinventoryfunctions.cpp

 	}
 	return FALSE;
 }
+
+
+void change_item_parent(LLInventoryModel* model,
+									 LLViewerInventoryItem* item,
+									 const LLUUID& new_parent_id,
+									 BOOL restamp)
+{
+	if (item->getParentUUID() != new_parent_id)
+	{
+		LLInventoryModel::update_list_t update;
+		LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1);
+		update.push_back(old_folder);
+		LLInventoryModel::LLCategoryUpdate new_folder(new_parent_id, 1);
+		update.push_back(new_folder);
+		gInventory.accountForUpdate(update);
+
+		LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
+		new_item->setParent(new_parent_id);
+		new_item->updateParentOnServer(restamp);
+		model->updateItem(new_item);
+		model->notifyObservers();
+	}
+}

indra/newview/llinventoryfunctions.h

 // Is this item or its baseitem is worn, attached, etc...
 BOOL get_is_item_worn(const LLUUID& id);
 
+
+void change_item_parent(LLInventoryModel* model,
+									 LLViewerInventoryItem* item,
+									 const LLUUID& new_parent_id,
+									 BOOL restamp);
+
 #endif // LL_LLINVENTORYFUNCTIONS_H
 
 

indra/newview/llinventoryitemslist.cpp

 
 void LLPanelInventoryListItemBase::updateItem()
 {
-	if (mItemIcon.notNull())
-		mIcon->setImage(mItemIcon);
-
-	LLTextUtil::textboxSetHighlightedVal(
-		mTitle,
-		LLStyle::Params(),
-		mItem->getName(),
-		mHighlightedText);
+	setIconImage(mIconImage);
+	setTitle(mItem->getName(), mHighlightedText);
 }
 
 void LLPanelInventoryListItemBase::addWidgetToLeftSide(const std::string& name, bool show_widget/* = true*/)
 
 BOOL LLPanelInventoryListItemBase::postBuild()
 {
-	// Inheritors need to call base implementation
-	mIcon = getChild<LLIconCtrl>("item_icon");
-	mTitle = getChild<LLTextBox>("item_name");
+	setIconCtrl(getChild<LLIconCtrl>("item_icon"));
+	setTitleCtrl(getChild<LLTextBox>("item_name"));
+
+	mIconImage = get_item_icon(mItem->getType(), mItem->getInventoryType(), mItem->getFlags(), FALSE);
 
 	updateItem();
 
 LLPanelInventoryListItemBase::LLPanelInventoryListItemBase(LLViewerInventoryItem* item)
 : LLPanel()
 , mItem(item)
-, mIcon(NULL)
-, mTitle(NULL)
+, mIconCtrl(NULL)
+, mTitleCtrl(NULL)
 , mWidgetSpacing(WIDGET_SPACING)
 , mLeftWidgetsWidth(0)
 , mRightWidgetsWidth(0)
 {
-	mItemIcon = get_item_icon(mItem->getType(), mItem->getInventoryType(), mItem->getFlags(), FALSE);
 }
 
 void LLPanelInventoryListItemBase::init()
 	reshapeMiddleWidgets();
 }
 
+void LLPanelInventoryListItemBase::setIconImage(const LLUIImagePtr& image)
+{
+	if(image)
+	{
+		mIconImage = image; 
+		mIconCtrl->setImage(mIconImage);
+	}
+}
+
+void LLPanelInventoryListItemBase::setTitle(const std::string& title, const std::string& highlit_text)
+{
+	LLTextUtil::textboxSetHighlightedVal(
+		mTitleCtrl,
+		LLStyle::Params(),
+		title,
+		highlit_text);
+}
+
 void LLPanelInventoryListItemBase::reshapeLeftWidgets()
 {
 	S32 widget_left = 0;
 
 void LLPanelInventoryListItemBase::reshapeMiddleWidgets()
 {
-	LLRect icon_rect(mIcon->getRect());
+	LLRect icon_rect(mIconCtrl->getRect());
 	icon_rect.setLeftTopAndSize(mLeftWidgetsWidth + getWidgetSpacing(), icon_rect.mTop, 
 		icon_rect.getWidth(), icon_rect.getHeight());
-	mIcon->setShape(icon_rect);
+	mIconCtrl->setShape(icon_rect);
 
 	S32 name_left = icon_rect.mRight + getWidgetSpacing();
 	S32 name_right = getLocalRect().getWidth() - mRightWidgetsWidth - getWidgetSpacing();
-	LLRect name_rect(mTitle->getRect());
+	LLRect name_rect(mTitleCtrl->getRect());
 	name_rect.set(name_left, name_rect.mTop, name_right, name_rect.mBottom);
-	mTitle->setShape(name_rect);
+	mTitleCtrl->setShape(name_rect);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 	if (!item)
 	{
 		llwarns << "No inventory item. Couldn't create flat list item." << llendl;
-		llassert(!"No inventory item. Couldn't create flat list item.");
+		llassert(item != NULL);
 	}
 
 	LLPanelInventoryListItemBase *list_item = LLPanelInventoryListItemBase::create(item);
 	if (!list_item)
 		return;
 
-	if (!addItem(list_item, item->getUUID()))
+	bool is_item_added = addItem(list_item, item->getUUID());
+	if (!is_item_added)
 	{
 		llwarns << "Couldn't add flat list item." << llendl;
-		llassert(!"Couldn't add flat list item.");
+		llassert(is_item_added);
 	}
 }
 

indra/newview/llinventoryitemslist.h

 	 */
 	virtual void init();
 
+	/** setter for mIconCtrl */
+	void setIconCtrl(LLIconCtrl* icon) { mIconCtrl = icon; }
+	/** setter for MTitleCtrl */
+	void setTitleCtrl(LLTextBox* tb) { mTitleCtrl = tb; }
+
 	void setLeftWidgetsWidth(S32 width) { mLeftWidgetsWidth = width; }
 	void setRightWidgetsWidth(S32 width) { mRightWidgetsWidth = width; }
 
 	 */
 	virtual void reshapeWidgets();
 
+	/** set wearable type icon image */
+	void setIconImage(const LLUIImagePtr& image);
+
+	/** Set item title - inventory item name usually */
+	void setTitle(const std::string& title, const std::string& highlit_text);
+
 private:
 
 	/** reshape left side widgets
 
 	LLViewerInventoryItem* mItem;
 
-	LLIconCtrl*		mIcon;
-	LLTextBox*		mTitle;
+	LLIconCtrl*		mIconCtrl;
+	LLTextBox*		mTitleCtrl;
 
-	LLUIImagePtr	mItemIcon;
+	LLUIImagePtr	mIconImage;
 	std::string		mHighlightedText;
 
 	widget_array_t	mLeftSideWidgets;

indra/newview/llinventoryobserver.cpp

 
 void fetch_items_from_llsd(const LLSD& items_llsd)
 {
-	if (!items_llsd.size()) return;
+	if (!items_llsd.size() || gDisconnected) return;
 	LLSD body;
 	body[0]["cap_name"] = "FetchInventory";
 	body[1]["cap_name"] = "FetchLib";
 		
 	for (S32 i=0; i<body.size(); i++)
 	{
+		if(!gAgent.getRegion())
+		{
+			llwarns<<"Agent's region is null"<<llendl;
+			break;
+		}
 		if (0 >= body[i].size()) continue;
 		std::string url = gAgent.getRegion()->getCapability(body[i]["cap_name"].asString());
 
 		if (!category)
 			continue;
 
-		S32 version = category->getVersion();
-		if (version != (*iter).second.mVersion)
+		const S32 version = category->getVersion();
+		const S32 expected_num_descendents = category->getDescendentCount();
+		if ((version == LLViewerInventoryCategory::VERSION_UNKNOWN) ||
+			(expected_num_descendents == LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN))
 		{
-			// Update category version in map.
-			(*iter).second.mVersion = version;
-			(*iter).second.mCallback();
+			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((*iter).first, cats, items);
+		if (!cats || !items)
+		{
+			llwarns << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << llendl;
+			// 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);
+		}
+		const S32 current_num_known_descendents = cats->count() + items->count();
+
+		LLCategoryData cat_data = (*iter).second;
+
+		// If category version or descendents count has changed
+		// update category data in mCategoryMap and fire a callback.
+		if (version != cat_data.mVersion || current_num_known_descendents != cat_data.mDescendentsCount)
+		{
+			cat_data.mVersion = version;
+			cat_data.mDescendentsCount = current_num_known_descendents;
+
+			cat_data.mCallback();
 		}
 	}
 }
 
-void LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t cb)
+bool LLInventoryCategoriesObserver::addCategory(const LLUUID& cat_id, callback_t cb)
 {
 	S32 version;
+	S32 current_num_known_descendents;
+	bool can_be_added = true;
+
 	LLViewerInventoryCategory* category = gInventory.getCategory(cat_id);
 	if (category)
 	{
 		// Inventory category version is used to find out if some changes
 		// to a category have been made.
 		version = category->getVersion();
+
+		LLInventoryModel::cat_array_t* cats;
+		LLInventoryModel::item_array_t* items;
+		gInventory.getDirectDescendentsOf(cat_id, cats, items);
+		if (!cats || !items)
+		{
+			llwarns << "Category '" << category->getName() << "' descendents corrupted, fetch failed." << llendl;
+			// 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 return "false" meaning that the category can't be observed.
+			can_be_added = false;
+
+			llassert(cats != NULL && items != NULL);
+		}
+		current_num_known_descendents = cats->count() + items->count();
 	}
 	else
 	{
 		// If category could not be retrieved it might mean that
 		// inventory is unusable at the moment so the category is
-		// stored with VERSION_UNKNOWN and it may be updated later.
+		// stored with VERSION_UNKNOWN and DESCENDENT_COUNT_UNKNOWN,
+		// it may be updated later.
 		version = LLViewerInventoryCategory::VERSION_UNKNOWN;
+		current_num_known_descendents = LLViewerInventoryCategory::DESCENDENT_COUNT_UNKNOWN;
 	}
 
-	version = category->getVersion();
-	mCategoryMap.insert(category_map_value_t(cat_id, LLCategoryData(cb, version)));
+	if (can_be_added)
+	{
+		mCategoryMap.insert(category_map_value_t(cat_id, LLCategoryData(cb, version, current_num_known_descendents)));
+	}
+
+	return can_be_added;
 }
 
 void LLInventoryCategoriesObserver::removeCategory(const LLUUID& cat_id)

indra/newview/llinventoryobserver.h

 	LLInventoryCategoriesObserver() {};
 	virtual void changed(U32 mask);
 
-	void addCategory(const LLUUID& cat_id, callback_t cb);
+	/**
+	 * Add cat_id to the list of observed categories with a
+	 * callback fired on category being changed.
+	 *
+	 * @return "true" if category was added, "false" if it could
+	 * not be found.
+	 */
+	bool addCategory(const LLUUID& cat_id, callback_t cb);
 	void removeCategory(const LLUUID& cat_id);
 
 protected:
 	struct LLCategoryData
 	{
-		LLCategoryData(callback_t cb, S32 version)
+		LLCategoryData(callback_t cb, S32 version, S32 num_descendents)
 		: mCallback(cb)
 		, mVersion(version)
+		, mDescendentsCount(num_descendents)
 		{}
 
 		callback_t	mCallback;
 		S32			mVersion;
+		S32			mDescendentsCount;
 	};
 
 	typedef	std::map<LLUUID, LLCategoryData>	category_map_t;

indra/newview/lloutfitslist.cpp

 
 #include "llaccordionctrl.h"
 #include "llaccordionctrltab.h"
+#include "llappearancemgr.h"
 #include "llinventoryfunctions.h"
 #include "llinventorymodel.h"
 #include "llwearableitemslist.h"
 	:	LLPanel()
 	,	mAccordion(NULL)
 	,	mListCommands(NULL)
+	,	mSelectedList(NULL)
 {
 	mCategoriesObserver = new LLInventoryCategoriesObserver();
 	gInventory.addObserver(mCategoriesObserver);
 	{
 		const LLUUID cat_id = (*iter);
 		LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
-		if (!cat)
-			continue;
+		if (!cat) continue;
 
 		std::string name = cat->getName();
 
 		static LLXMLNodePtr accordionXmlNode = getAccordionTabXMLNode();
+		LLAccordionCtrlTab* tab = LLUICtrlFactory::defaultBuilder<LLAccordionCtrlTab>(accordionXmlNode, NULL, NULL);
 
-		accordionXmlNode->setAttributeString("name", name);
-		accordionXmlNode->setAttributeString("title", name);
-		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);
+			continue;
+		}
+
 		// Map the new tab with outfit category UUID.
 		mOutfitsMap.insert(LLOutfitsList::outfits_map_value_t(cat_id, tab));
 
-		// Start observing the new outfit category.
-		LLWearableItemsList* list  = tab->getChild<LLWearableItemsList>("wearable_items_list");
-		mCategoriesObserver->addCategory(cat_id, boost::bind(&LLWearableItemsList::updateList, list, cat_id));
+		// Setting tab focus callback to monitor currently selected outfit.
+		tab->setFocusReceivedCallback(boost::bind(&LLOutfitsList::changeOutfitSelection, this, list, cat_id));
 
-		// Setting drop down callback to monitor currently selected outfit.
-		tab->setDropDownStateChangedCallback(boost::bind(&LLOutfitsList::onTabExpandedCollapsed, this, list));
+		// Setting list commit callback to monitor currently selected wearable item.
+		list->setCommitCallback(boost::bind(&LLOutfitsList::onSelectionChange, this, _1));
 
 		// Fetch the new outfit contents.
 		cat->fetch();
 			// 1. Remove outfit accordion tab from accordion.
 			mAccordion->removeCollapsibleCtrl(outfits_iter->second);
 
+			const LLUUID& outfit_id = outfits_iter->first;
+
 			// 2. Remove outfit category from observer to stop monitoring its changes.
-			mCategoriesObserver->removeCategory(outfits_iter->first);
+			mCategoriesObserver->removeCategory(outfit_id);
 
-			// 3. Remove category UUID to accordion tab mapping.
+			// 3. Reset selection if selected outfit is being removed.
+			if (mSelectedOutfitUUID == outfit_id)
+			{
+				changeOutfitSelection(NULL, LLUUID());
+			}
+
+			// 4. Remove category UUID to accordion tab mapping.
 			mOutfitsMap.erase(outfits_iter);
 		}
 	}
 	mAccordion->arrange();
 }
 
-void LLOutfitsList::updateOutfitTab(const LLUUID& category_id)
+void LLOutfitsList::onSelectionChange(LLUICtrl* ctrl)
 {
-	outfits_map_t::iterator outfits_iter = mOutfitsMap.find(category_id);
-	if (outfits_iter != mOutfitsMap.end())
-	{
-		LLViewerInventoryCategory *cat = gInventory.getCategory(category_id);
-		if (!cat)
-			return;
+	LLWearableItemsList* list = dynamic_cast<LLWearableItemsList*>(ctrl);
+	if (!list) return;
 
-		std::string name = cat->getName();
+	LLViewerInventoryItem *item = gInventory.getItem(list->getSelectedUUID());
+	if (!item) return;
 
-		// Update tab name with the new category name.
-		LLAccordionCtrlTab* tab = outfits_iter->second;
-		if (tab)
-		{
-			tab->setName(name);
-		}
-
-		// Update tab title with the new category name using textbox
-		// in accordion tab header.
-		LLTextBox* tab_title = tab->findChild<LLTextBox>("dd_textbox");
-		if (tab_title)
-		{
-			tab_title->setText(name);
-		}
-	}
+	changeOutfitSelection(list, item->getParentUUID());
 }
 
-void LLOutfitsList::onTabExpandedCollapsed(LLWearableItemsList* list)
+void LLOutfitsList::performAction(std::string action)
 {
-	if (!list)
-		return;
+	LLViewerInventoryCategory* cat = gInventory.getCategory(mSelectedOutfitUUID);
+	if (!cat) return;
 
-	// TODO: Add outfit selection handling.
+	if ("replaceoutfit" == action)
+	{
+		LLAppearanceMgr::instance().wearInventoryCategory( cat, FALSE, FALSE );
+	}
+	else if ("addtooutfit" == action)
+	{
+		LLAppearanceMgr::instance().wearInventoryCategory( cat, FALSE, TRUE );
+	}
 }
 
 void LLOutfitsList::setFilterSubString(const std::string& string)
 	mFilterSubString = string;
 }
 
-
 //////////////////////////////////////////////////////////////////////////
 // Private methods
 //////////////////////////////////////////////////////////////////////////
 	LLCommonUtils::computeDifference(vnew, vcur, vadded, vremoved);
 }
 
+void LLOutfitsList::updateOutfitTab(const LLUUID& category_id)
+{
+	outfits_map_t::iterator outfits_iter = mOutfitsMap.find(category_id);
+	if (outfits_iter != mOutfitsMap.end())
+	{
+		LLViewerInventoryCategory *cat = gInventory.getCategory(category_id);
+		if (!cat) return;
+
+		std::string name = cat->getName();
+
+		// Update tab name with the new category name.
+		LLAccordionCtrlTab* tab = outfits_iter->second;
+		if (tab)
+		{
+			tab->setName(name);
+			tab->setTitle(name);
+		}
+	}
+}
+
+void LLOutfitsList::changeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id)
+{
+	// Reset selection in previously selected tab
+	// if a new one is selected.
+	if (list && mSelectedList && mSelectedList != list)
+	{
+		mSelectedList->resetSelection();
+	}
+
+	mSelectedList = list;
+	mSelectedOutfitUUID = category_id;
+}
+
 // EOF

indra/newview/lloutfitslist.h

 
 	void refreshList(const LLUUID& category_id);
 
-	// Update tab displaying outfit identified by category_id.
-	void updateOutfitTab(const LLUUID& category_id);
+	void onSelectionChange(LLUICtrl* ctrl);
 
-	void onTabExpandedCollapsed(LLWearableItemsList* list);
+	void performAction(std::string action);
 
 	void setFilterSubString(const std::string& string);
 
 	 */
 	void computeDifference(const LLInventoryModel::cat_array_t& vcats, uuid_vec_t& vadded, uuid_vec_t& vremoved);
 
+	/**
+	 * Updates tab displaying outfit identified by category_id.
+	 */
+	void updateOutfitTab(const LLUUID& category_id);
+
+	/**
+	 * Resets previous selection and stores newly selected list and outfit id.
+	 */
+	void changeOutfitSelection(LLWearableItemsList* list, const LLUUID& category_id);
 
 	LLInventoryCategoriesObserver* 	mCategoriesObserver;
 
 	LLAccordionCtrl*				mAccordion;
 	LLPanel*						mListCommands;
 
+	LLWearableItemsList*			mSelectedList;
+	LLUUID							mSelectedOutfitUUID;
+
 	std::string 					mFilterSubString;
 
 	typedef	std::map<LLUUID, LLAccordionCtrlTab*>		outfits_map_t;

indra/newview/llpaneloutfitsinventory.cpp

 
 void LLPanelOutfitsInventory::onWearButtonClick()
 {
-	LLFolderViewEventListener* listenerp = getCorrectListenerForAction();
-	if (listenerp)
+	// TODO: Remove if/else, add common interface
+	// for "My Outfits" and "Wearing" tabs.
+	if (!isCOFPanelActive())
 	{
-		listenerp->performAction(NULL, "replaceoutfit");
+		mMyOutfitsPanel->performAction("replaceoutfit");
+	}
+	else
+	{
+		LLFolderViewEventListener* listenerp = getCorrectListenerForAction();
+		if (listenerp)
+		{
+			listenerp->performAction(NULL, "replaceoutfit");
+		}
 	}
 }
 
 void LLPanelOutfitsInventory::onAdd()
 {
-	LLFolderViewEventListener* listenerp = getCorrectListenerForAction();
-	if (listenerp)
+	// TODO: Remove if/else, add common interface
+	// for "My Outfits" and "Wearing" tabs.
+	if (!isCOFPanelActive())
 	{
-		listenerp->performAction(NULL, "addtooutfit");
+		mMyOutfitsPanel->performAction("addtooutfit");
+	}
+	else
+	{
+		LLFolderViewEventListener* listenerp = getCorrectListenerForAction();
+		if (listenerp)
+		{
+			listenerp->performAction(NULL, "addtooutfit");
+		}
 	}
 }
 

indra/newview/llpreviewnotecard.cpp

 #include "llpreviewnotecard.h"
 
 #include "llinventory.h"
+#include "llinventoryfunctions.h" // for change_item_parent()
 
 #include "llagent.h"
 #include "llassetuploadresponders.h"
 	childSetAction("Save", onClickSave, this);
 	childSetVisible("lock", FALSE);	
 
+	childSetAction("Delete", onClickDelete, this);
+	childSetEnabled("Delete", false);
+
 	const LLInventoryItem* item = getItem();
 
 	childSetCommitCallback("desc", LLPreview::onText, this);
 	if (item)
+	{
 		childSetText("desc", item->getDescription());
+		childSetEnabled("Delete", true);
+	}
 	childSetPrevalidate("desc", &LLTextValidate::validateASCIIPrintableNoPipe);
 
 	return LLPreview::postBuild();
 	}
 }
 
+
+// static
+void LLPreviewNotecard::onClickDelete(void* user_data)
+{
+	LLPreviewNotecard* preview = (LLPreviewNotecard*)user_data;
+	if(preview)
+	{
+		preview->deleteNotecard();
+	}
+}
+
 struct LLSaveNotecardInfo
 {
 	LLPreviewNotecard* mSelf;
 	return true;
 }
 
+void LLPreviewNotecard::deleteNotecard()
+{
+	LLViewerInventoryItem* item = gInventory.getItem(mItemUUID);
+	if (item != NULL)
+	{
+		const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+		change_item_parent(&gInventory, item, trash_id, FALSE);
+	}
+
+	closeFloater();
+}
+
 // static
 void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed)
 {

indra/newview/llpreviewnotecard.h

 	virtual void loadAsset();
 	bool saveIfNeeded(LLInventoryItem* copyitem = NULL);
 
+	void deleteNotecard();
+
 	static void onLoadComplete(LLVFS *vfs,
 							   const LLUUID& asset_uuid,
 							   LLAssetType::EType type,
 
 	static void onClickSave(void* data);
 
+	static void onClickDelete(void* data);
+
 	static void onSaveComplete(const LLUUID& asset_uuid,
 							   void* user_data,
 							   S32 status, LLExtStat ext_status);

indra/newview/llscreenchannel.cpp

 	}
 }
 
+void LLScreenChannel::closeHiddenToasts(const Matcher& matcher)
+{
+	// since we can't guarantee that close toast operation doesn't change mToastList
+	// we collect matched toasts that should be closed into separate list
+	std::list<ToastElem> toasts;
+	for (std::vector<ToastElem>::iterator it = mToastList.begin(); it
+			!= mToastList.end(); it++)
+	{
+		LLToast * toast = it->toast;
+		// add to list valid toast that match to provided matcher criteria
+		if (toast != NULL && !toast->isDead() && toast->getNotification() != NULL
+				&& !toast->getVisible() && matcher.matches(toast->getNotification()))
+		{
+			toasts.push_back(*it);
+		}
+	}
+
+	// close collected toasts
+	for (std::list<ToastElem>::iterator it = toasts.begin(); it
+			!= toasts.end(); it++)
+	{
+		it->toast->closeFloater();
+	}
+}
+
 //--------------------------------------------------------------------------
 void LLScreenChannel::removeToastsFromChannel()
 {

indra/newview/llscreenchannel.h

 	void		hideToastsFromScreen();
 	// hide toast by notification id
 	void		hideToast(const LLUUID& notification_id);
+
+	/**
+	 * Closes hidden matched toasts from channel.
+	 */
+	void closeHiddenToasts(const Matcher& matcher);
+
 	// removes all toasts from a channel
 	void		removeToastsFromChannel();
 	// show all toasts in a channel

indra/newview/llwearableitemslist.cpp

 
 #include "llwearableitemslist.h"
 
+#include "lliconctrl.h"
+
 #include "llinventoryfunctions.h"
 #include "llinventorymodel.h"
+#include "lltransutil.h"
 
 class LLFindOutfitItems : public LLInventoryCollectFunctor
 {
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 
+LLPanelDummyClothingListItem* LLPanelDummyClothingListItem::create(EWearableType w_type)
+{
+	LLPanelDummyClothingListItem* list_item = new LLPanelDummyClothingListItem(w_type);
+	list_item->init();
+	return list_item;
+}
+
+void LLPanelDummyClothingListItem::updateItem()
+{
+	std::string title = wearableTypeToString(mWearableType);
+	setTitle(title, LLStringUtil::null);
+}
+
+BOOL LLPanelDummyClothingListItem::postBuild()
+{
+	LLIconCtrl* icon = getChild<LLIconCtrl>("item_icon");
+	setIconCtrl(icon);
+	setTitleCtrl(getChild<LLTextBox>("item_name"));
+
+	addWidgetToRightSide("btn_add");
+
+	setIconImage(get_item_icon(LLAssetType::AT_CLOTHING, LLInventoryType::IT_NONE, mWearableType, FALSE));
+	updateItem();
+
+	// Make it look loke clothing item - reserve space for 'delete' button
+	setLeftWidgetsWidth(icon->getRect().mLeft);
+
+	setWidgetsVisible(false);
+	reshapeWidgets();
+
+	return TRUE;
+}
+
+LLPanelDummyClothingListItem::LLPanelDummyClothingListItem(EWearableType w_type)
+ : LLPanelWearableListItem(NULL)
+ , mWearableType(w_type)
+{
+}
+
+void LLPanelDummyClothingListItem::init()
+{
+	LLUICtrlFactory::getInstance()->buildPanel(this, "panel_dummy_clothing_list_item.xml");
+}
+
+typedef std::map<EWearableType, std::string> clothing_to_string_map_t;
+
+clothing_to_string_map_t init_clothing_string_map()
+{
+	clothing_to_string_map_t w_map;
+	w_map.insert(std::make_pair(WT_SHIRT, "shirt_not_worn"));
+	w_map.insert(std::make_pair(WT_PANTS, "pants_not_worn"));
+	w_map.insert(std::make_pair(WT_SHOES, "shoes_not_worn"));
+	w_map.insert(std::make_pair(WT_SOCKS, "socks_not_worn"));
+	w_map.insert(std::make_pair(WT_JACKET, "jacket_not_worn"));
+	w_map.insert(std::make_pair(WT_GLOVES, "gloves_not_worn"));
+	w_map.insert(std::make_pair(WT_UNDERSHIRT, "undershirt_not_worn"));
+	w_map.insert(std::make_pair(WT_UNDERPANTS, "underpants_not_worn"));
+	w_map.insert(std::make_pair(WT_SKIRT, "skirt_not_worn"));
+	w_map.insert(std::make_pair(WT_ALPHA, "alpha_not_worn"));
+	w_map.insert(std::make_pair(WT_TATTOO, "tattoo_not_worn"));
+	return w_map;
+}
+
+std::string LLPanelDummyClothingListItem::wearableTypeToString(EWearableType w_type)
+{
+	static const clothing_to_string_map_t w_map = init_clothing_string_map();
+	static const std::string invalid_str = LLTrans::getString("invalid_not_worn");
+	
+	std::string type_str = invalid_str;
+	clothing_to_string_map_t::const_iterator it = w_map.find(w_type);
+	if(w_map.end() != it)
+	{
+		type_str = LLTrans::getString(it->second);
+	}
+	return type_str;
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
 static const LLDefaultChildRegistry::Register<LLWearableItemsList> r("wearable_items_list");
 
 LLWearableItemsList::Params::Params()

indra/newview/llwearableitemslist.h

 
 	virtual ~LLPanelClothingListItem();
 
-	/*virtual*/ void init();
 	/*virtual*/ BOOL postBuild();
 
 	/**
 protected:
 
 	LLPanelClothingListItem(LLViewerInventoryItem* item);
+	
+	/*virtual*/ void init();
 };
 
 class LLPanelBodyPartsListItem : public LLPanelWearableListItem
 
 	virtual ~LLPanelBodyPartsListItem();
 
-	/*virtual*/ void init();
 	/*virtual*/ BOOL postBuild();
 
 	/**
 
 protected:
 	LLPanelBodyPartsListItem(LLViewerInventoryItem* item);
+
+	/*virtual*/ void init();
+};
+
+/**
+ * @class LLPanelDummyClothingListItem
+ *
+ * A dummy item panel - displays grayed clothing icon, grayed title '<clothing> not worn' and 'add' button
+ */
+class LLPanelDummyClothingListItem : public LLPanelWearableListItem
+{
+public:
+	static LLPanelDummyClothingListItem* create(EWearableType w_type);
+
+	/*virtual*/ void updateItem();
+	/*virtual*/ BOOL postBuild();
+
+protected:
+	LLPanelDummyClothingListItem(EWearableType w_type);
+
+	/*virtual*/ void init();
+
+	static std::string wearableTypeToString(EWearableType w_type);
+
+private:
+	EWearableType mWearableType;
 };
 
 /**

indra/newview/skins/default/xui/en/floater_preview_notecard.xml

      label="Save"
      label_selected="Save"
      layout="topleft"
-     left="288"
+     left="178"
      name="Save"
      top="332"
      width="100" />
+    <button
+     follows="right|bottom"
+     height="22"
+     label="Delete"
+     label_selected="Delete"
+     layout="topleft"
+     left="288"
+     name="Delete"
+     top="332"
+     width="100" />
 </floater>

indra/newview/skins/default/xui/en/panel_body_parts_list_item.xml

      top="4"
      value="..."
      width="359" />
-    <button 
+    <icon 
      name="btn_lock"
      layout="topleft"
      follows="top|right"
-     image_unselected="Lock2"
-     image_selected="Lock2"
+     image_name="Lock2"
      top="0"
-     left_pad="3"
+     left="0"
      height="20"
      width="20"
      tab_stop="false" />

indra/newview/skins/default/xui/en/panel_clothing_list_item.xml

      height="20"
      width="20"
      tab_stop="false" />
-    <button 
+    <icon
      name="btn_lock"
      layout="topleft"
      follows="top|right"
-     image_unselected="Lock2"
-     image_selected="Lock2"
+     image_name="Lock2"
      top="0"
      left_pad="3"
      height="20"
-     width="20"
-     tab_stop="false" />
+     width="20" />
     <button 
      name="btn_edit"
      layout="topleft"

indra/newview/skins/default/xui/en/panel_dummy_clothing_list_item.xml

+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="top|right|left"
+ height="20"
+ layout="topleft"
+ left="0"
+ name="dummy_clothing_item"
+ top="0"
+ width="380">
+    <icon
+     follows="top|right|left"
+     height="20"
+     image_name="ListItem_Over"
+     layout="topleft"
+     left="0"
+     name="hovered_icon"
+     top="0"
+     visible="false"
+     width="380" />
+    <icon
+     height="20"
+     follows="top|right|left"
+     image_name="ListItem_Select"
+     layout="topleft"
+     left="0"
+     name="selected_icon"
+     top="0"
+     visible="false"
+     width="380" />
+    <icon
+     height="16"
+     color="0.75 0.75 0.75 1"
+     follows="top|left"
+     image_name="Inv_Object"
+     layout="topleft"
+     left="20"
+     name="item_icon"
+     top="2"
+     width="16" />
+    <text
+     follows="left|right"
+     height="16"
+     layout="topleft"
+     left_pad="5"
+     allow_html="false"
+     use_ellipses="true"
+     name="item_name"
+     text_color="LtGray_50"
+     top="4"
+     value="..."
+     width="359" />
+    <button 
+     name="btn_add"
+     layout="topleft"
+     follows="top|right"
+     label="+"
+     top="0"
+     left="0"
+     height="20"
+     width="20"
+     tab_stop="false" />
+</panel>

indra/newview/skins/default/xui/en/panel_outfit_edit.xml

                  name="move_further_btn"
                  top="1"
                  width="31" />
+                <icon
+                 follows="bottom|left"
+                 height="25"
+                 image_name="Toolbar_Middle_Off"
+                 layout="topleft"
+                 left_pad="1"
+                 name="dummy_icon"
+                 width="105" />
                 <button
                  follows="bottom|right"
                  height="25"
                  name="add_to_outfit_btn"
                  top="1"
                  width="31" />
+                <icon
+                 follows="bottom|left"
+                 height="25"
+                 image_name="Toolbar_Middle_Off"
+                 layout="topleft"
+                 left_pad="1"
+                 name="dummy_middle_icon"
+                 width="140" />
+                <icon
+                 follows="bottom|left"
+                 height="25"
+                 image_name="Toolbar_Right_Off"
+                 layout="topleft"
+                 left_pad="1"
+                 name="dummy_right_icon"
+                 width="31" />
             </panel>
         </layout_panel>
     </layout_stack>

indra/newview/skins/default/xui/en/panel_people.xml

          label="Share"
          layout="topleft"
          name="share_btn"
+         tool_tip="Share an inventory item"
          width="62" />
         <button
          follows="bottom|left"

indra/newview/skins/default/xui/en/panel_preferences_chat.xml

     <check_box
      enabled="false"
      height="16"
-     label="Enable plain text chat history"
+     label="Enable plain text IM and chat history"
      layout="topleft"
      left_delta="0"
      name="plain_text_chat_history"

indra/newview/skins/default/xui/en/strings.xml

 	<string name="alpha">Alpha</string>
 	<string name="tattoo">Tattoo</string>
 	<string name="invalid">invalid</string>
+  
+  <!-- Not Worn Wearable Types -->
+	<string name="shirt_not_worn">Shirt not worn</string>
+	<string name="pants_not_worn">Pants not worn</string>
+	<string name="shoes_not_worn">Shoes not worn</string>
+	<string name="socks_not_worn">Socks not worn</string>
+	<string name="jacket_not_worn">Jacket not worn</string>
+	<string name="gloves_not_worn">Gloves not worn</string>
+	<string name="undershirt_not_worn">Undershirt not worn</string>
+	<string name="underpants_not_worn">Underpants not worn</string>
+	<string name="skirt_not_worn">Skirt not worn</string>
+	<string name="alpha_not_worn">Alpha not worn</string>
+	<string name="tattoo_not_worn">Tattoo not worn</string>
+	<string name="invalid_not_worn">invalid</string>
 
   <!-- Wearable List-->
   <string name="NewWearable">New [WEARABLE_ITEM]</string>