diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index 466f2d499dd34646d095617adcbbfe47fcd036da..8a880e5acee19a09cb39485669fc4dd3a216af8c 100644
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -2031,6 +2031,39 @@ void LLAgentWearables::animateAllWearableParams(F32 delta, BOOL upload_bake)
 	}
 }
 
+bool LLAgentWearables::moveWearable(const LLViewerInventoryItem* item, bool closer_to_body)
+{
+	if (!item) return false;
+	if (!item->isWearableType()) return false;
+
+	wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(item->getWearableType());
+	if (wearable_iter == mWearableDatas.end()) return false;
+
+	wearableentry_vec_t& wearable_vec = wearable_iter->second;
+	if (wearable_vec.empty()) return false;
+
+	const LLUUID& asset_id = item->getAssetUUID();
+
+	//nowhere to move if the wearable is already on any boundary (closest to the body/furthest from the body)
+	if (closer_to_body && asset_id == wearable_vec.front()->getAssetID()) return false;
+	if (!closer_to_body && asset_id == wearable_vec.back()->getAssetID()) return false;
+
+	for (U32 i = 0; i < wearable_vec.size(); ++i)
+	{
+		LLWearable* wearable = wearable_vec[i];
+		if (!wearable) continue;
+		if (wearable->getAssetID() != asset_id) continue;
+		
+		//swapping wearables
+		U32 swap_i = closer_to_body ? i-1 : i+1;
+		wearable_vec[i] = wearable_vec[swap_i];
+		wearable_vec[swap_i] = wearable;
+		return true;
+	}
+
+	return false;
+}
+
 void LLAgentWearables::updateServer()
 {
 	sendAgentWearablesUpdate();
diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h
index 585fd3f8b3acb063a4095f885240ef72d94e4ff0..d3b18f68f1b0eaf278935fbf6d37fe684a2059e0 100644
--- a/indra/newview/llagentwearables.h
+++ b/indra/newview/llagentwearables.h
@@ -82,6 +82,8 @@ class LLAgentWearables
 
 	void			animateAllWearableParams(F32 delta, BOOL upload_bake);
 	
+	bool			moveWearable(const LLViewerInventoryItem* item, bool closer_to_body);
+
 	//--------------------------------------------------------------------
 	// Accessors
 	//--------------------------------------------------------------------
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 9e02886e4f44fa40470d11c27bd0051be5406331..a6a3aa28d634e65ac1a9a716dcbf96d259861034 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -122,6 +122,38 @@ class LLWearInventoryCategoryCallback : public LLInventoryCallback
 	bool mAppend;
 };
 
+
+//Inventory callback updating "dirty" state when destroyed
+class LLUpdateDirtyState: public LLInventoryCallback
+{
+public:
+	LLUpdateDirtyState() {}
+	virtual ~LLUpdateDirtyState(){ LLAppearanceMgr::getInstance()->updateIsDirty(); }
+	virtual void fire(const LLUUID&) {}
+};
+
+
+//Inventory collect functor collecting wearables of a specific wearable type
+class LLFindClothesOfType : public LLInventoryCollectFunctor
+{
+public:
+	LLFindClothesOfType(EWearableType type) : mWearableType(type) {}
+	virtual ~LLFindClothesOfType() {}
+	virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item)
+	{
+		if (!item) return false;
+		if (item->getType() != LLAssetType::AT_CLOTHING) return false;
+		
+		LLViewerInventoryItem *vitem = dynamic_cast<LLViewerInventoryItem*>(item);
+		if (!vitem || vitem->getWearableType() != mWearableType) return false;
+
+		return true;
+	}
+
+	const EWearableType mWearableType;
+};
+
+
 LLUpdateAppearanceOnDestroy::LLUpdateAppearanceOnDestroy():
 	mFireCount(0)
 {
@@ -1593,8 +1625,11 @@ bool LLAppearanceMgr::updateBaseOutfit()
 	// in a Base Outfit we do not remove items, only links
 	purgeCategory(base_outfit_id, false);
 
+
+	LLPointer<LLInventoryCallback> dirty_state_updater = new LLUpdateDirtyState();
+
 	//COF contains only links so we copy to the Base Outfit only links
-	shallowCopyCategoryContents(getCOF(), base_outfit_id, NULL);
+	shallowCopyCategoryContents(getCOF(), base_outfit_id, dirty_state_updater);
 
 	return true;
 }
@@ -1802,6 +1837,62 @@ void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
 	}
 }
 
+
+bool LLAppearanceMgr::moveWearable(LLViewerInventoryItem* item, bool closer_to_body)
+{
+	if (!item || !item->isWearableType()) return false;
+	if (item->getType() != LLAssetType::AT_CLOTHING) return false;
+	if (!gInventory.isObjectDescendentOf(item->getUUID(), getCOF())) return false;
+
+	LLInventoryModel::cat_array_t cats;
+	LLInventoryModel::item_array_t items;
+	gInventory.collectDescendentsIf(getCOF(), cats, items, true, LLFindClothesOfType(item->getWearableType()));
+	if (items.empty()) return false;
+
+	//*TODO all items are not guarantied to have valid descriptions (check?)
+	std::sort(items.begin(), items.end(), WearablesOrderComparator(item->getWearableType()));
+
+	if (closer_to_body && items.front() == item) return false;
+	if (!closer_to_body && items.back() == item) return false;
+	
+	LLInventoryModel::item_array_t::iterator it = std::find(items.begin(), items.end(), item);
+	if (items.end() == it) return false;
+
+
+	//swapping descriptions
+	closer_to_body ? --it : ++it;
+	LLViewerInventoryItem* swap_item = *it;
+	if (!swap_item) return false;
+	std::string tmp = swap_item->LLInventoryItem::getDescription();
+	swap_item->setDescription(item->LLInventoryItem::getDescription());
+	item->setDescription(tmp);
+
+
+	//items need to be updated on a dataserver
+	item->setComplete(TRUE);
+	item->updateServer(FALSE);
+	gInventory.updateItem(item);
+
+	swap_item->setComplete(TRUE);
+	swap_item->updateServer(FALSE);
+	gInventory.updateItem(swap_item);
+
+	//to cause appearance of the agent to be updated
+	bool result = false;
+	if (result = gAgentWearables.moveWearable(item, closer_to_body))
+	{
+		gAgentAvatarp->wearableUpdated(item->getWearableType(), TRUE);
+	}
+
+	setOutfitDirty(true);
+
+	//*TODO do we need to notify observers here in such a way?
+	gInventory.notifyObservers();
+
+	return result;
+}
+
+
 //#define DUMP_CAT_VERBOSE
 
 void LLAppearanceMgr::dumpCat(const LLUUID& cat_id, const std::string& msg)
diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h
index efb5274c5b6e9b512cc02879e099525396a3e1d0..a308a3efa947d343fb6a76a97196a3653834fdf6 100644
--- a/indra/newview/llappearancemgr.h
+++ b/indra/newview/llappearancemgr.h
@@ -141,6 +141,8 @@ class LLAppearanceMgr: public LLSingleton<LLAppearanceMgr>
 
 	LLUUID makeNewOutfitLinks(const std::string& new_folder_name);
 
+	bool moveWearable(LLViewerInventoryItem* item, bool closer_to_body);
+
 protected:
 	LLAppearanceMgr();
 	~LLAppearanceMgr();
diff --git a/indra/newview/llpaneloutfitedit.cpp b/indra/newview/llpaneloutfitedit.cpp
index e139cb31d65584a35e8646950332ffff38c7c1fb..ae181e2819b2ddbf6be687db639dfa388e14147f 100644
--- a/indra/newview/llpaneloutfitedit.cpp
+++ b/indra/newview/llpaneloutfitedit.cpp
@@ -73,6 +73,9 @@ const U64 WEARABLE_MASK = (1LL << LLInventoryType::IT_WEARABLE);
 const U64 ATTACHMENT_MASK = (1LL << LLInventoryType::IT_ATTACHMENT) | (1LL << LLInventoryType::IT_OBJECT);
 const U64 ALL_ITEMS_MASK = WEARABLE_MASK | ATTACHMENT_MASK;
 
+static const std::string SAVE_BTN("save_btn");
+static const std::string REVERT_BTN("revert_btn");
+
 class LLInventoryLookObserver : public LLInventoryObserver
 {
 public:
@@ -221,10 +224,9 @@ BOOL LLPanelOutfitEdit::postBuild()
 	mEditWearableBtn->setVisible(FALSE);
 	mEditWearableBtn->setCommitCallback(boost::bind(&LLPanelOutfitEdit::onEditWearableClicked, this));
 
-	childSetAction("revert_btn", boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance()));
+	childSetAction(REVERT_BTN, boost::bind(&LLAppearanceMgr::wearBaseOutfit, LLAppearanceMgr::getInstance()));
 
-	childSetAction("save_btn", boost::bind(&LLPanelOutfitEdit::saveOutfit, this, false));
-	childSetAction("save_as_btn", boost::bind(&LLPanelOutfitEdit::saveOutfit, this, true));
+	childSetAction(SAVE_BTN, boost::bind(&LLPanelOutfitEdit::saveOutfit, this, false));
 	childSetAction("save_flyout_btn", boost::bind(&LLPanelOutfitEdit::showSaveMenu, this));
 
 	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar save_registar;
@@ -234,10 +236,22 @@ BOOL LLPanelOutfitEdit::postBuild()
 
 	mWearableListManager = new LLFilteredWearableListManager(
 		getChild<LLInventoryItemsList>("filtered_wearables_list"), ALL_ITEMS_MASK);
+		
+	childSetAction("move_closer_btn", boost::bind(&LLPanelOutfitEdit::moveWearable, this, true));
+	childSetAction("move_further_btn", boost::bind(&LLPanelOutfitEdit::moveWearable, this, false));
 
 	return TRUE;
 }
 
+void LLPanelOutfitEdit::moveWearable(bool closer_to_body)
+{
+	LLViewerInventoryItem* wearable_to_move = gInventory.getItem(mLookContents->getSelectionInterface()->getCurrentID());
+	LLAppearanceMgr::getInstance()->moveWearable(wearable_to_move, closer_to_body);
+
+	//*TODO why not to listen to inventory?
+	updateLookInfo();
+}
+
 void LLPanelOutfitEdit::showAddWearablesPanel()
 {
 	childSetVisible("add_wearables_panel", childGetValue("add_btn"));
@@ -267,6 +281,8 @@ void LLPanelOutfitEdit::saveOutfit(bool as_new)
 	{
 		panel_outfits_inventory->onSave();
 	}
+
+	//*TODO how to get to know when base outfit is updated or new outfit is created?
 }
 
 void LLPanelOutfitEdit::showSaveMenu()
@@ -542,10 +558,12 @@ void LLPanelOutfitEdit::lookFetched(void)
 		columns[0]["value"] = item->getName();
 		columns[1]["column"] = "look_item_sort";
 		columns[1]["type"] = "text"; // TODO: multi-wearable sort "type" should go here.
-		columns[1]["value"] = "BAR"; // TODO: Multi-wearable sort index should go here
+		columns[1]["value"] = item->LLInventoryItem::getDescription();
 		
 		mLookContents->addElement(row);
 	}
+
+	updateVerbs();
 }
 
 void LLPanelOutfitEdit::updateLookInfo()
@@ -589,4 +607,15 @@ void LLPanelOutfitEdit::displayCurrentOutfit()
 	updateLookInfo();
 }
 
+//private
+void LLPanelOutfitEdit::updateVerbs()
+{
+	bool outfit_is_dirty = LLAppearanceMgr::getInstance()->isOutfitDirty();
+	
+	childSetEnabled(SAVE_BTN, outfit_is_dirty);
+	childSetEnabled(REVERT_BTN, outfit_is_dirty);
+
+	mSaveMenu->setItemEnabled("save_outfit", outfit_is_dirty);
+}
+
 // EOF
diff --git a/indra/newview/llpaneloutfitedit.h b/indra/newview/llpaneloutfitedit.h
index 308ee23115c4f5b7aec74e63623fb736233a8bd2..b6f121d4846874d5c8cf280ac3fe3c71b03e3955 100644
--- a/indra/newview/llpaneloutfitedit.h
+++ b/indra/newview/llpaneloutfitedit.h
@@ -87,6 +87,8 @@ class LLPanelOutfitEdit : public LLPanel
 		// Sends a request for data about the given parcel, which will
 		// only update the location if there is none already available.
 
+	void moveWearable(bool closer_to_body);
+
 	void showAddWearablesPanel();
 	void showWearablesFilter();
 	void showFilteredWearablesPanel();
@@ -110,6 +112,8 @@ class LLPanelOutfitEdit : public LLPanel
 
 private:
 
+	void updateVerbs();
+
 	//*TODO got rid of mCurrentOutfitID
 	LLUUID				mCurrentOutfitID;
 
diff --git a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
index b1f0ff15cb071bfd3c84230a605d33df9bdd132e..314d2389ae0fe3f35bba89f0708d12773414078a 100644
--- a/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
+++ b/indra/newview/skins/default/xui/en/panel_outfit_edit.xml
@@ -221,6 +221,30 @@
                  name="new_btn"
                  top="1"
                  width="31" />
+                <button
+                 follows="bottom|left"
+                 height="25"
+                 image_hover_unselected="Toolbar_Middle_Over"
+                 image_overlay="Movement_Forward_On"
+                 image_selected="Toolbar_Middle_Selected"
+                 image_unselected="Toolbar_Middle_Off"
+                 layout="topleft"
+                 left_pad="1"
+                 name="move_closer_btn"
+                 top="1"
+                 width="31" />
+                <button
+                 follows="bottom|left"
+                 height="25"
+                 image_hover_unselected="Toolbar_Middle_Over"
+                 image_overlay="Movement_Backward_On"
+                 image_selected="Toolbar_Middle_Selected"
+                 image_unselected="Toolbar_Middle_Off"
+                 layout="topleft"
+                 left_pad="1"
+                 name="move_further_btn"
+                 top="1"
+                 width="31" />
                 <button
                  follows="bottom|right"
                  height="25"