From cb865a7e1300d4ce0bedae7c856fb210b68a43f8 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Wed, 27 Jun 2012 18:56:10 -0700
Subject: [PATCH] CHUI-101 WIP Make LLFolderView general purpose moved
 filtering logic to viewmodel

---
 indra/llui/llnotifications.cpp           |  24 +-
 indra/newview/llfolderview.cpp           | 106 ++-
 indra/newview/llfolderview.h             |  12 +-
 indra/newview/llfolderviewitem.cpp       | 787 +++++------------------
 indra/newview/llfolderviewitem.h         |  82 +--
 indra/newview/llfolderviewmodel.h        | 194 +++---
 indra/newview/llinventorybridge.cpp      |  20 +-
 indra/newview/llinventorybridge.h        |   3 +
 indra/newview/llinventoryfilter.cpp      |  97 ++-
 indra/newview/llinventoryfilter.h        |  20 +-
 indra/newview/llinventoryfunctions.cpp   |  10 +-
 indra/newview/llinventorypanel.cpp       | 128 +++-
 indra/newview/llinventorypanel.h         |   6 +
 indra/newview/llpanellandmarks.cpp       |   2 +-
 indra/newview/llpanelmaininventory.cpp   |   2 +-
 indra/newview/llpanelobjectinventory.cpp |  11 +
 indra/newview/llsidepanelappearance.cpp  |   2 +-
 indra/newview/lltexturectrl.cpp          |  10 +-
 18 files changed, 557 insertions(+), 959 deletions(-)

diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 487a2e5fe7c..48128e0b409 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -1542,34 +1542,32 @@ void LLNotifications::addFromCallback(const LLSD& name)
 	add(name.asString(), LLSD(), LLSD());
 }
 
-LLNotificationPtr LLNotifications::add(const std::string& name, 
-									   const LLSD& substitutions, 
-									   const LLSD& payload)
+LLNotificationPtr LLNotifications::add(const std::string& name, const LLSD& substitutions, const LLSD& payload)
 {
 	LLNotification::Params::Functor functor_p;
 	functor_p.name = name;
 	return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));	
 }
 
-LLNotificationPtr LLNotifications::add(const std::string& name, 
-									   const LLSD& substitutions, 
-									   const LLSD& payload, 
-									   const std::string& functor_name)
+LLNotificationPtr LLNotifications::add(const std::string& name, const LLSD& substitutions, const LLSD& payload, const std::string& functor_name)
 {
 	LLNotification::Params::Functor functor_p;
 	functor_p.name = functor_name;
-	return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));	
+	return add(LLNotification::Params().name(name)
+										.substitutions(substitutions)
+										.payload(payload)
+										.functor(functor_p));	
 }
 							  
 //virtual
-LLNotificationPtr LLNotifications::add(const std::string& name, 
-										const LLSD& substitutions, 
-										const LLSD& payload, 
-										LLNotificationFunctorRegistry::ResponseFunctor functor)
+LLNotificationPtr LLNotifications::add(const std::string& name, const LLSD& substitutions, const LLSD& payload, LLNotificationFunctorRegistry::ResponseFunctor functor)
 {
 	LLNotification::Params::Functor functor_p;
 	functor_p.function = functor;
-	return add(LLNotification::Params().name(name).substitutions(substitutions).payload(payload).functor(functor_p));	
+	return add(LLNotification::Params().name(name)
+										.substitutions(substitutions)
+										.payload(payload)
+										.functor(functor_p));	
 }
 
 // generalized add function that takes a parameter block object for more complex instantiations
diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp
index ee8c94a2dd3..a37fc7714be 100644
--- a/indra/newview/llfolderview.cpp
+++ b/indra/newview/llfolderview.cpp
@@ -181,7 +181,6 @@ LLFolderView::LLFolderView(const Params& p)
 	mNeedsAutoSelect( FALSE ),
 	mAutoSelectOverride(FALSE),
 	mNeedsAutoRename(FALSE),
-	mDebugFilters(FALSE),
 	mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME),	// This gets overridden by a pref immediately
 	mFilter(new LLInventoryFilter(LLInventoryFilter::Params().name(p.title))),
 	mShowSelectionContext(FALSE),
@@ -316,7 +315,7 @@ BOOL LLFolderView::addFolder( LLFolderViewFolder* folder)
 	folder->reshape(getRect().getWidth(), 0);
 	folder->setVisible(FALSE);
 	addChild( folder );
-	folder->dirtyFilter();
+	folder->getViewModelItem()->dirtyFilter();
 	folder->requestArrange();
 	return TRUE;
 }
@@ -339,15 +338,14 @@ void LLFolderView::openTopLevelFolders()
 }
 
 // This view grows and shrinks to enclose all of its children items and folders.
-// mItemHeight = mDebugFilters ? LLFontGL::getFontMonospace()->getLineHeight() : 0;
 // *width should be 0
 // conform show folder state works
-S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_generation )
+S32 LLFolderView::arrange( S32* unused_width, S32* unused_height )
 {
 	mMinWidth = 0;
 	S32 target_height;
 
-	LLFolderViewFolder::arrange(&mMinWidth, &target_height, mFilter->getFirstSuccessGeneration());
+	LLFolderViewFolder::arrange(&mMinWidth, &target_height);
 
 	LLRect scroll_rect = mScrollContainer->getContentWindowRect();
 	reshape( llmax(scroll_rect.getWidth(), mMinWidth), llround(mCurHeight) );
@@ -371,15 +369,10 @@ void LLFolderView::filter( LLFolderViewFilter& filter )
 	LLFastTimer t2(FTM_FILTER);
 	filter.setFilterCount(llclamp(gSavedSettings.getS32("FilterItemsPerFrame"), 1, 5000));
 
-	if (getCompletedFilterGeneration() < filter.getCurrentGeneration())
+	if (getLastFilterGeneration() < filter.getCurrentGeneration())
 	{
-		mPassedFilter = FALSE;
 		mMinWidth = 0;
-		LLFolderViewFolder::filter(filter);
-	}
-	else
-	{
-		mPassedFilter = TRUE;
+		getViewModelItem()->filter(filter);
 	}
 }
 
@@ -548,15 +541,15 @@ void LLFolderView::sanitizeSelection()
 		LLFolderViewItem* item = *item_iter;
 
 		// ensure that each ancestor is open and potentially passes filtering
-		BOOL visible = item->potentiallyVisible(); // initialize from filter state for this item
+		BOOL visible = item->getViewModelItem()->potentiallyVisible(); // initialize from filter state for this item
 		// modify with parent open and filters states
 		LLFolderViewFolder* parent_folder = item->getParentFolder();
 		// Move up through parent folders and see what's visible
-				while(parent_folder)
-				{
-					visible = visible && parent_folder->isOpen() && parent_folder->potentiallyVisible();
-					parent_folder = parent_folder->getParentFolder();
-				}
+		while(parent_folder)
+		{
+			visible = visible && parent_folder->isOpen() && parent_folder->getViewModelItem()->potentiallyVisible();
+			parent_folder = parent_folder->getParentFolder();
+		}
 
 		//  deselect item if any ancestor is closed or didn't pass filter requirements.
 		if (!visible)
@@ -606,7 +599,7 @@ void LLFolderView::sanitizeSelection()
 				parent_folder;
 				parent_folder = parent_folder->getParentFolder())
 			{
-				if (parent_folder->potentiallyVisible())
+				if (parent_folder->getViewModelItem()->potentiallyVisible())
 				{
 					// give initial selection to first ancestor folder that potentially passes the filter
 					if (!new_selection)
@@ -684,16 +677,6 @@ void LLFolderView::commitRename( const LLSD& data )
 
 void LLFolderView::draw()
 {
-	static LLUIColor sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", LLColor4::white);
-	if (mDebugFilters)
-	{
-		std::string current_filter_string = llformat("Current Filter: %d, Least Filter: %d, Auto-accept Filter: %d",
-										mFilter->getCurrentGeneration(), mFilter->getFirstSuccessGeneration(), mFilter->getFirstRequiredGeneration());
-		LLFontGL::getFontMonospace()->renderUTF8(current_filter_string, 0, 2, 
-			getRect().getHeight() - LLFontGL::getFontMonospace()->getLineHeight(), LLColor4(0.5f, 0.5f, 0.8f, 1.f), 
-			LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE );
-	}
-
 	//LLFontGL* font = getLabelFontForStyle(mLabelStyle);
 
 	// if cursor has moved off of me during drag and drop
@@ -734,17 +717,14 @@ void LLFolderView::draw()
 	}
 	else if (mShowEmptyMessage)
 	{
-		if (!mViewModel->contentsReady() || mCompletedFilterGeneration < mFilter->getFirstSuccessGeneration())
+		if (!mViewModel->contentsReady() || getLastFilterGeneration() < mFilter->getFirstSuccessGeneration())
 		{
 			// TODO RN: Get this from filter
 			mStatusText = LLTrans::getString("Searching");
 		}
 		else
 		{
-			if (getFilter())
-			{
-				mStatusText = getFilter()->getEmptyLookupMessage();
-			}
+			mStatusText = getFolderViewModel()->getFilter()->getEmptyLookupMessage();
 		}
 		mStatusTextBox->setValue(mStatusText);
 		mStatusTextBox->setVisible( TRUE );
@@ -763,7 +743,11 @@ void LLFolderView::draw()
 			// This will indirectly call ::arrange and reshape of the status textbox.
 			// We should call this method to also notify parent about required rect.
 			// See EXT-7564, EXT-7047.
-			arrangeFromRoot();
+			S32 height = 0;
+			S32 width = 0;
+			S32 total_height = arrange( &width, &height );
+			notifyParent(LLSD().with("action", "size_changes").with("height", total_height));
+
 			LLUI::popMatrix();
 			LLUI::pushMatrix();
 			LLUI::translate((F32)getRect().mLeft, (F32)getRect().mBottom);
@@ -902,16 +886,16 @@ void LLFolderView::onItemsRemovalConfirmation(const LLSD& notification, const LL
 			}
 			if(parent)
 			{
-				if (parent->removeItem(item_to_delete))
+				if (item_to_delete->remove())
 				{
 					// change selection on successful delete
 					if (new_selection)
 					{
-						setSelectionFromRoot(new_selection, new_selection->isOpen(), mParentPanel->hasFocus());
+						getRoot()->setSelection(new_selection, new_selection->isOpen(), mParentPanel->hasFocus());
 					}
 					else
 					{
-						setSelectionFromRoot(NULL, mParentPanel->hasFocus());
+						getRoot()->setSelection(NULL, mParentPanel->hasFocus());
 					}
 				}
 			}
@@ -937,11 +921,11 @@ void LLFolderView::onItemsRemovalConfirmation(const LLSD& notification, const LL
 			}
 			if (new_selection)
 			{
-				setSelectionFromRoot(new_selection, new_selection->isOpen(), mParentPanel->hasFocus());
+				getRoot()->setSelection(new_selection, new_selection->isOpen(), mParentPanel->hasFocus());
 			}
 			else
 			{
-				setSelectionFromRoot(NULL, mParentPanel->hasFocus());
+				getRoot()->setSelection(NULL, mParentPanel->hasFocus());
 			}
 
 			for(S32 i = 0; i < count; ++i)
@@ -1386,12 +1370,12 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask )
 					if (next->isSelected())
 					{
 						// shrink selection
-						changeSelectionFromRoot(last_selected, FALSE);
+						getRoot()->changeSelection(last_selected, FALSE);
 					}
 					else if (last_selected->getParentFolder() == next->getParentFolder())
 					{
 						// grow selection
-						changeSelectionFromRoot(next, TRUE);
+						getRoot()->changeSelection(next, TRUE);
 					}
 				}
 			}
@@ -1450,12 +1434,12 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask )
 					if (prev->isSelected())
 					{
 						// shrink selection
-						changeSelectionFromRoot(last_selected, FALSE);
+						getRoot()->changeSelection(last_selected, FALSE);
 					}
 					else if (last_selected->getParentFolder() == prev->getParentFolder())
 					{
 						// grow selection
-						changeSelectionFromRoot(prev, TRUE);
+						getRoot()->changeSelection(prev, TRUE);
 					}
 				}
 			}
@@ -1649,7 +1633,7 @@ BOOL LLFolderView::search(LLFolderViewItem* first_item, const std::string &searc
 			}
 		}
 
-		const std::string current_item_label(search_item->getSearchableLabel());
+		const std::string current_item_label(search_item->getViewModelItem()->getSearchableName());
 		S32 search_string_length = llmin(upper_case_string.size(), current_item_label.size());
 		if (!current_item_label.compare(0, search_string_length, upper_case_string))
 		{
@@ -1959,13 +1943,6 @@ void LLFolderView::doIdle()
 	
 	LLFastTimer t2(FTM_INVENTORY);
 
-	BOOL debug_filters = gSavedSettings.getBOOL("DebugInventoryFilters");
-	if (debug_filters != getDebugFilters())
-	{
-		mDebugFilters = debug_filters;
-		arrangeAll();
-	}
-
 	if (mFilter->isModified() && mFilter->isNotDefault())
 	{
 		mNeedsAutoSelect = TRUE;
@@ -1973,7 +1950,7 @@ void LLFolderView::doIdle()
 	mFilter->clearModified();
 
 	// filter to determine visibility before arranging
-	filterFromRoot();
+	filter(*(getFolderViewModel()->getFilter()));
 
 	// automatically show matching items, and select first one if we had a selection
 	if (mNeedsAutoSelect)
@@ -1981,7 +1958,7 @@ void LLFolderView::doIdle()
 		LLFastTimer t3(FTM_AUTO_SELECT);
 		// select new item only if a filtered item not currently selected
 		LLFolderViewItem* selected_itemp = mSelectedItems.empty() ? NULL : mSelectedItems.back();
-		if (!mAutoSelectOverride && (!selected_itemp || !selected_itemp->potentiallyHidden()))
+		if (!mAutoSelectOverride && (!selected_itemp || selected_itemp->passedFilter()))
 		{
 			// these are named variables to get around gcc not binding non-const references to rvalues
 			// and functor application is inherently non-const to allow for stateful functors
@@ -1991,7 +1968,7 @@ void LLFolderView::doIdle()
 
 		// Open filtered folders for folder views with mAutoSelectOverride=TRUE.
 		// Used by LLPlacesFolderView.
-		if (mAutoSelectOverride && mFilter->showAllResults())
+		if (mFilter->showAllResults())
 		{
 			// these are named variables to get around gcc not binding non-const references to rvalues
 			// and functor application is inherently non-const to allow for stateful functors
@@ -2002,7 +1979,7 @@ void LLFolderView::doIdle()
 		scrollToShowSelection();
 	}
 
-	BOOL filter_finished = mCompletedFilterGeneration >= mFilter->getCurrentGeneration() 
+	BOOL filter_finished = getLastFilterGeneration() >= mFilter->getCurrentGeneration() 
 						&& mViewModel->contentsReady();
 	if (filter_finished 
 		|| gFocusMgr.childHasKeyboardFocus(inventory_panel) 
@@ -2073,7 +2050,10 @@ void LLFolderView::doIdle()
 		sanitizeSelection();
 		if( needsArrange() )
 		{
-			arrangeFromRoot();
+			S32 height = 0;
+			S32 width = 0;
+			S32 total_height = arrange( &width, &height );
+			notifyParent(LLSD().with("action", "size_changes").with("height", total_height));
 		}
 	}
 
@@ -2278,25 +2258,19 @@ void LLFolderView::onRenamerLost()
 
 	if( mRenameItem )
 	{
-		setSelectionFromRoot( mRenameItem, TRUE );
+		setSelection( mRenameItem, TRUE );
 		mRenameItem = NULL;
 	}
 }
 
-LLFolderViewFilter* LLFolderView::getFilter()
-{
-	return mFilter;
-}
-
 S32 LLFolderView::getItemHeight()
 {
-	S32 debug_height = mDebugFilters ? LLFontGL::getFontMonospace()->getLineHeight() : 0;
 	if(!hasVisibleChildren())
 	{
 		//We need to display status textbox, let's reserve some place for it
-		return llmax(debug_height, mStatusTextBox->getTextPixelHeight());
+		return llmax(0, mStatusTextBox->getTextPixelHeight());
 	}
-	return debug_height;
+	return 0;
 }
 
 //TODO RN: move to llfolderviewmodel.cpp file
diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h
index 8b58da9f450..d261a5967d0 100644
--- a/indra/newview/llfolderview.h
+++ b/indra/newview/llfolderview.h
@@ -110,9 +110,11 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 
 	virtual BOOL canFocusChildren() const;
 
+	virtual const LLFolderView*	getRoot() const { return this; }
 	virtual LLFolderView*	getRoot() { return this; }
 
 	LLFolderViewModelInterface* getFolderViewModel() { return mViewModel; }
+	const LLFolderViewModelInterface* getFolderViewModel() const { return mViewModel; }
 
 	void setFilterPermMask(PermissionMask filter_perm_mask);
 	
@@ -120,9 +122,6 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 	void setSelectCallback(const signal_t::slot_type& cb) { mSelectSignal.connect(cb); }
 	void setReshapeCallback(const signal_t::slot_type& cb) { mReshapeSignal.connect(cb); }
 	
-	// filter is never null
-	LLFolderViewFilter* getFilter();
-
 	bool getAllowMultiSelect() { return mAllowMultiSelect; }
 
 	// Close all folders in the view
@@ -133,7 +132,7 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 
 	// Find width and height of this object and its children. Also
 	// makes sure that this view and its children are the right size.
-	virtual S32 arrange( S32* width, S32* height, S32 filter_generation );
+	virtual S32 arrange( S32* width, S32* height );
 	virtual S32 getItemHeight();
 
 	void arrangeAll() { mArrangeGeneration++; }
@@ -147,7 +146,7 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 
 	// Record the selected item and pass it down the hierarchy.
 	virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem,
-		BOOL take_keyboard_focus);
+		BOOL take_keyboard_focus = TRUE);
 
 	// This method is used to toggle the selection of an item. Walks
 	// children, and keeps track of selected objects.
@@ -244,8 +243,6 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 
 	void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; }
 
-	BOOL getDebugFilters() { return mDebugFilters; }
-
 	LLPanel* getParentPanel() { return mParentPanel; }
 	// DEBUG only
 	void dumpSelectionInformation();
@@ -299,7 +296,6 @@ class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler
 	bool							mUseLabelSuffix;
 	bool							mShowItemLinkOverlays;
 	
-	BOOL							mDebugFilters;
 	U32								mSortOrder;
 	LLDepthStack<LLFolderViewFolder>	mAutoOpenItems;
 	LLFolderViewFolder*				mAutoOpenCandidate;
diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp
index 3f0b4939866..f65a13be1e4 100644
--- a/indra/newview/llfolderviewitem.cpp
+++ b/indra/newview/llfolderviewitem.cpp
@@ -114,8 +114,6 @@ LLFolderViewItem::LLFolderViewItem(const LLFolderViewItem::Params& p)
 	mHasVisibleChildren(FALSE),
 	mIndentation(0),
 	mItemHeight(p.item_height),
-	mPassedFilter(FALSE),
-	mLastFilterGeneration(-1),
 	//TODO RN: create interface for string highlighting
 	//mStringMatchOffset(std::string::npos),
 	mControlLabelRotation(0.f),
@@ -146,6 +144,10 @@ LLFolderView* LLFolderViewItem::getRoot()
 	return mRoot;
 }
 
+const LLFolderView* LLFolderViewItem::getRoot() const
+{
+	return mRoot;
+}
 // Returns true if this object is a child (or grandchild, etc.) of potential_ancestor.
 BOOL LLFolderViewItem::isDescendantOf( const LLFolderViewFolder* potential_ancestor )
 {
@@ -207,99 +209,47 @@ LLFolderViewItem* LLFolderViewItem::getPreviousOpenNode(BOOL include_children)
 	return itemp;
 }
 
-// is this item something we think we should be showing?
-// for example, if we haven't gotten around to filtering it yet, then the answer is yes
-// until we find out otherwise
-BOOL LLFolderViewItem::potentiallyVisible()
-{
-	return getFiltered() // we've passed the filter
-		||	getLastFilterGeneration() < getRoot()->getFilter()->getFirstSuccessGeneration(); // or we don't know yet
-}
-
-BOOL LLFolderViewItem::potentiallyHidden()
+BOOL LLFolderViewItem::passedFilter(S32 filter_generation) 
 {
-	return !mPassedFilter // didn't pass the filter
-		|| getLastFilterGeneration() < getRoot()->getFilter()->getFirstSuccessGeneration(); // or we don't know yet
-}
-
-BOOL LLFolderViewItem::getFiltered() 
-{ 
-	return mPassedFilter && mLastFilterGeneration >= getRoot()->getFilter()->getFirstSuccessGeneration();
-}
-
-BOOL LLFolderViewItem::getFiltered(S32 filter_generation) 
-{
-	return mPassedFilter && mLastFilterGeneration >= filter_generation;
-}
-
-void LLFolderViewItem::setFiltered(BOOL filtered, S32 filter_generation)
-{
-	mPassedFilter = filtered;
-	mLastFilterGeneration = filter_generation;
+	return getViewModelItem()->passedFilter(filter_generation);
 }
 
 void LLFolderViewItem::refresh()
 {
-	if(!getViewModelItem()) return;
+	LLFolderViewModelItem& vmi = *getViewModelItem();
 
-	mLabel = getViewModelItem()->getDisplayName();
+	mLabel = vmi.getDisplayName();
 
 	setToolTip(mLabel);
-	mIcon = getViewModelItem()->getIcon();
-	mIconOpen = getViewModelItem()->getIconOpen();
-	mIconOverlay = getViewModelItem()->getIconOverlay();
+	mIcon = vmi.getIcon();
+	mIconOpen = vmi.getIconOpen();
+	mIconOverlay = vmi.getIconOverlay();
 
 	if (mRoot->useLabelSuffix())
 	{
-		mLabelStyle = getViewModelItem()->getLabelStyle();
-		mLabelSuffix = getViewModelItem()->getLabelSuffix();
+		mLabelStyle = vmi.getLabelStyle();
+		mLabelSuffix = vmi.getLabelSuffix();
 	}
 
-	std::string searchable_label(mLabel);
-	searchable_label.append(mLabelSuffix);
-	LLStringUtil::toUpper(searchable_label);
+	//TODO RN: make sure this logic still fires
+	//std::string searchable_label(mLabel);
+	//searchable_label.append(mLabelSuffix);
+	//LLStringUtil::toUpper(searchable_label);
 
-	if (mSearchableLabel.compare(searchable_label))
-	{
-		mSearchableLabel.assign(searchable_label);
-		dirtyFilter();
-		// some part of label has changed, so overall width has potentially changed, and sort order too
-		if (mParentFolder)
-		{
-			mParentFolder->requestSort();
-			mParentFolder->requestArrange();
-		}
-	}
+	//if (mSearchableLabel.compare(searchable_label))
+	//{
+	//	mSearchableLabel.assign(searchable_label);
+	//	vmi.dirtyFilter();
+	//	// some part of label has changed, so overall width has potentially changed, and sort order too
+	//	if (mParentFolder)
+	//	{
+	//		mParentFolder->requestSort();
+	//		mParentFolder->requestArrange();
+	//	}
+	//}
 
 	mLabelWidthDirty = true;
-	dirtyFilter();
-}
-
-// This function is called when items are added or view filters change. It's
-// implemented here but called by derived classes when folding the
-// views.
-void LLFolderViewItem::filterFromRoot( void )
-{
-	LLFolderViewItem* root = getRoot();
-
-	root->filter(*((LLFolderView*)root)->getFilter());
-}
-
-// This function is called when the folder view is dirty. It's
-// implemented here but called by derived classes when folding the
-// views.
-void LLFolderViewItem::arrangeFromRoot()
-{
-	LLFolderViewItem* root = getRoot();
-
-	S32 height = 0;
-	S32 width = 0;
-	S32 total_height = root->arrange( &width, &height, 0 );
-
-	LLSD params;
-	params["action"] = "size_changes";
-	params["height"] = total_height;
-	getParent()->notifyParent(params);
+	vmi.dirtyFilter();
 }
 
 // Utility function for LLFolderView
@@ -313,7 +263,7 @@ void LLFolderViewItem::arrangeAndSet(BOOL set_selection,
 	}
 	if(set_selection)
 	{
-		setSelectionFromRoot(this, TRUE, take_keyboard_focus);
+		getRoot()->setSelection(this, TRUE, take_keyboard_focus);
 		if(root)
 		{
 			root->scrollToShowSelection();
@@ -321,22 +271,6 @@ void LLFolderViewItem::arrangeAndSet(BOOL set_selection,
 	}		
 }
 
-// This function clears the currently selected item, and records the
-// specified selected item appropriately for display and use in the
-// UI. If open is TRUE, then folders are opened up along the way to
-// the selection.
-void LLFolderViewItem::setSelectionFromRoot(LLFolderViewItem* selection,
-											BOOL openitem,
-											BOOL take_keyboard_focus)
-{
-	getRoot()->setSelection(selection, openitem, take_keyboard_focus);
-}
-
-// helper function to change the selection from the root.
-void LLFolderViewItem::changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected)
-{
-	getRoot()->changeSelection(selection, selected);
-}
 
 std::set<LLFolderViewItem*> LLFolderViewItem::getSelectionList() const
 {
@@ -347,18 +281,13 @@ std::set<LLFolderViewItem*> LLFolderViewItem::getSelectionList() const
 // addToFolder() returns TRUE if it succeeds. FALSE otherwise
 BOOL LLFolderViewItem::addToFolder(LLFolderViewFolder* folder)
 {
-	if (!folder)
-	{
-		return FALSE;
-	}
-	mParentFolder = folder;
 	return folder->addItem(this);
 }
 
 
 // Finds width and height of this object and its children.  Also
 // makes sure that this view and its children are the right size.
-S32 LLFolderViewItem::arrange( S32* width, S32* height, S32 filter_generation)
+S32 LLFolderViewItem::arrange( S32* width, S32* height )
 {
 	const Params& p = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
 	S32 indentation = p.folder_indentation();
@@ -390,41 +319,6 @@ S32 LLFolderViewItem::getItemHeight()
 	return mItemHeight;
 }
 
-void LLFolderViewItem::filter( LLFolderViewFilter& filter)
-{
-	const BOOL previous_passed_filter = mPassedFilter;
-	const BOOL passed_filter = filter.check(this);
-
-	// If our visibility will change as a result of this filter, then
-	// we need to be rearranged in our parent folder
-	if (mParentFolder)
-	{
-		if (getVisible() != passed_filter
-			||	previous_passed_filter != passed_filter )
-			mParentFolder->requestArrange();
-	}
-
-	setFiltered(passed_filter, filter.getCurrentGeneration());
-	//TODO RN: create interface for string highlighting
-	//mStringMatchOffset = filter.getStringMatchOffset(this);
-	filter.decrementFilterCount();
-
-	if (getRoot()->getDebugFilters())
-	{
-		mStatusText = llformat("%d", mLastFilterGeneration);
-	}
-}
-
-void LLFolderViewItem::dirtyFilter()
-{
-	mLastFilterGeneration = -1;
-	// bubble up dirty flag all the way to root
-	if (getParentFolder())
-	{
-		getParentFolder()->setCompletedFilterGeneration(-1, TRUE);
-	}
-}
-
 // *TODO: This can be optimized a lot by simply recording that it is
 // selected in the appropriate places, and assuming that set selection
 // means 'deselect' for a leaf item. Do this optimization after
@@ -469,45 +363,31 @@ void LLFolderViewItem::selectItem(void)
 {
 	if (mIsSelected == FALSE)
 	{
-		if (getViewModelItem())
-		{
-			getViewModelItem()->selectItem();
-		}
+		getViewModelItem()->selectItem();
 		mIsSelected = TRUE;
 	}
 }
 
 BOOL LLFolderViewItem::isMovable()
 {
-	if( getViewModelItem() )
-	{
-		return getViewModelItem()->isItemMovable();
-	}
-	else
-	{
-		return TRUE;
-	}
+	return getViewModelItem()->isItemMovable();
 }
 
 BOOL LLFolderViewItem::isRemovable()
 {
-	if( getViewModelItem() )
-	{
-		return getViewModelItem()->isItemRemovable();
-	}
-	else
-	{
-		return TRUE;
-	}
+	return getViewModelItem()->isItemRemovable();
 }
 
 void LLFolderViewItem::destroyView()
 {
+	getRoot()->removeFromSelectionList(this);
+
 	if (mParentFolder)
 	{
 		// removeView deletes me
-		mParentFolder->removeView(this);
+		mParentFolder->extractItem(this);
 	}
+	delete this;
 }
 
 // Call through to the viewed object and return true if it can be
@@ -519,58 +399,36 @@ BOOL LLFolderViewItem::remove()
 	{
 		return FALSE;
 	}
-	if(getViewModelItem())
-	{
-		return getViewModelItem()->removeItem();
-	}
-	return TRUE;
+	return getViewModelItem()->removeItem();
 }
 
 // Build an appropriate context menu for the item.
 void LLFolderViewItem::buildContextMenu(LLMenuGL& menu, U32 flags)
 {
-	if(getViewModelItem())
-	{
-		getViewModelItem()->buildContextMenu(menu, flags);
-	}
+	getViewModelItem()->buildContextMenu(menu, flags);
 }
 
 void LLFolderViewItem::openItem( void )
 {
-	if( getViewModelItem() )
-	{
-		getViewModelItem()->openItem();
-	}
+	getViewModelItem()->openItem();
 }
 
 void LLFolderViewItem::rename(const std::string& new_name)
 {
 	if( !new_name.empty() )
 	{
-		if( getViewModelItem() )
-		{
-			getViewModelItem()->renameItem(new_name);
+		getViewModelItem()->renameItem(new_name);
 
-			if(mParentFolder)
-			{
-				mParentFolder->requestSort();
-			}
+		if(mParentFolder)
+		{
+			mParentFolder->requestSort();
 		}
 	}
 }
 
-const std::string& LLFolderViewItem::getSearchableLabel() const
-{
-	return mSearchableLabel;
-}
-
 const std::string& LLFolderViewItem::getName( void ) const
 {
-	if(getViewModelItem())
-	{
-		return getViewModelItem()->getName();
-	}
-	return LLStringUtil::null;
+	return getViewModelItem()->getName();
 }
 
 // LLView functionality
@@ -578,7 +436,7 @@ BOOL LLFolderViewItem::handleRightMouseDown( S32 x, S32 y, MASK mask )
 {
 	if(!mIsSelected)
 	{
-		setSelectionFromRoot(this, FALSE);
+		getRoot()->setSelection(this, FALSE);
 	}
 	make_ui_sound("UISndClick");
 	return TRUE;
@@ -599,7 +457,7 @@ BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask )
 	{
 		if(mask & MASK_CONTROL)
 		{
-			changeSelectionFromRoot(this, !mIsSelected);
+			getRoot()->changeSelection(this, !mIsSelected);
 		}
 		else if (mask & MASK_SHIFT)
 		{
@@ -607,7 +465,7 @@ BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask )
 		}
 		else
 		{
-			setSelectionFromRoot(this, FALSE);
+			getRoot()->setSelection(this, FALSE);
 		}
 		make_ui_sound("UISndClick");
 	}
@@ -646,14 +504,7 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
 
 				// *TODO: push this into listener and remove
 				// dependency on llagent
-				if (getViewModelItem())
-				{
-					src = getViewModelItem()->getDragSource();
-				}
-				else
-				{
-					src = LLToolDragAndDrop::SOURCE_VIEWER;
-				}
+				src = getViewModelItem()->getDragSource();
 
 				can_drag = root->startDrag(src);
 				if (can_drag)
@@ -695,10 +546,7 @@ BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask )
 
 BOOL LLFolderViewItem::handleDoubleClick( S32 x, S32 y, MASK mask )
 {
-	if (getViewModelItem())
-	{
-		getViewModelItem()->openItem();
-	}
+	getViewModelItem()->openItem();
 	return TRUE;
 }
 
@@ -715,7 +563,7 @@ BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask )
 		//...then select
 		if(mask & MASK_CONTROL)
 		{
-			changeSelectionFromRoot(this, !mIsSelected);
+			getRoot()->changeSelection(this, !mIsSelected);
 		}
 		else if (mask & MASK_SHIFT)
 		{
@@ -723,7 +571,7 @@ BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask )
 		}
 		else
 		{
-			setSelectionFromRoot(this, FALSE);
+			getRoot()->setSelection(this, FALSE);
 		}
 	}
 
@@ -748,21 +596,17 @@ BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 										 EAcceptance* accept,
 										 std::string& tooltip_msg)
 {
-	BOOL accepted = FALSE;
 	BOOL handled = FALSE;
-	if(getViewModelItem())
+	BOOL accepted = getViewModelItem()->dragOrDrop(mask,drop,cargo_type,cargo_data, tooltip_msg);
+	handled = accepted;
+	if (accepted)
 	{
-		accepted = getViewModelItem()->dragOrDrop(mask,drop,cargo_type,cargo_data, tooltip_msg);
-		handled = accepted;
-		if (accepted)
-		{
-			mDragAndDropTarget = TRUE;
-			*accept = ACCEPT_YES_MULTI;
-		}
-		else
-		{
-			*accept = ACCEPT_NO;
-		}
+		mDragAndDropTarget = TRUE;
+		*accept = ACCEPT_YES_MULTI;
+	}
+	else
+	{
+		*accept = ACCEPT_NO;
 	}
 	if(mParentFolder && !handled)
 	{
@@ -781,17 +625,17 @@ BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 
 void LLFolderViewItem::draw()
 {
-	static LLUIColor sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
-	static LLUIColor sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
-	static LLUIColor sHighlightFgColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
+	static LLUIColor sFgColor 			= LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE);
+	static LLUIColor sHighlightBgColor 	= LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE);
+	static LLUIColor sHighlightFgColor 	= LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE);
 	static LLUIColor sFocusOutlineColor = LLUIColorTable::instance().getColor("InventoryFocusOutlineColor", DEFAULT_WHITE);
-	static LLUIColor sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
-	static LLUIColor sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
-	static LLUIColor sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
-	static LLUIColor sLibraryColor = LLUIColorTable::instance().getColor("InventoryItemLibraryColor", DEFAULT_WHITE);
-	static LLUIColor sLinkColor = LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
+	static LLUIColor sFilterBGColor 	= LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE);
+	static LLUIColor sFilterTextColor 	= LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE);
+	static LLUIColor sSuffixColor 		= LLUIColorTable::instance().getColor("InventoryItemColor", DEFAULT_WHITE);
+	static LLUIColor sLibraryColor 		= LLUIColorTable::instance().getColor("InventoryItemLibraryColor", DEFAULT_WHITE);
+	static LLUIColor sLinkColor 		= LLUIColorTable::instance().getColor("InventoryItemLinkColor", DEFAULT_WHITE);
 	static LLUIColor sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE);
-	static LLUIColor sMouseOverColor = LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
+	static LLUIColor sMouseOverColor 	= LLUIColorTable::instance().getColor("InventoryMouseOverColor", DEFAULT_WHITE);
 
 	const Params& default_params = LLUICtrlFactory::getDefaultParams<LLFolderViewItem>();
 	const S32 TOP_PAD = default_params.item_top_pad;
@@ -929,29 +773,12 @@ void LLFolderViewItem::draw()
 	LLColor4 color = (mIsSelected && filled) ? sHighlightFgColor : sFgColor;
 	//TODO RN: implement this in terms of getColor()
 	//if (highlight_link) color = sLinkColor;
-	//if (getViewModelItem() && gInventory.isObjectDescendentOf(getViewModelItem()->getUUID(), gInventory.getLibraryRootFolderID())) color = sLibraryColor;
+	//if (gInventory.isObjectDescendentOf(getViewModelItem()->getUUID(), gInventory.getLibraryRootFolderID())) color = sLibraryColor;
 
 	F32 right_x  = 0;
 	F32 y = (F32)getRect().getHeight() - font->getLineHeight() - (F32)TEXT_PAD - (F32)TOP_PAD;
 	F32 text_left = (F32)(ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mIndentation);
 
-	//--------------------------------------------------------------------------------//
-	// Highlight filtered text
-	//
-	if (getRoot()->getDebugFilters())
-	{
-		if (!getFiltered() && !getViewModelItem()->hasChildren())
-		{
-			color.mV[VALPHA] *= 0.5f;
-		}
-		LLColor4 filter_color = mLastFilterGeneration >= getRoot()->getFilter()->getCurrentGeneration() ? 
-			LLColor4(0.5f, 0.8f, 0.5f, 1.f) : 
-			LLColor4(0.8f, 0.5f, 0.5f, 1.f);
-		LLFontGL::getFontMonospace()->renderUTF8(mStatusText, 0, text_left, y, filter_color,
-												 LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW,
-												 S32_MAX, S32_MAX, &right_x, FALSE );
-		text_left = right_x;
-	}
 	//--------------------------------------------------------------------------------//
 	// Draw the actual label text
 	//
@@ -997,6 +824,22 @@ void LLFolderViewItem::draw()
 	//}
 }
 
+const LLFolderViewModelInterface* LLFolderViewItem::getFolderViewModel( void ) const
+{
+	return getRoot()->getFolderViewModel();
+}
+
+LLFolderViewModelInterface* LLFolderViewItem::getFolderViewModel( void )
+{
+	return getRoot()->getFolderViewModel();
+}
+
+S32 LLFolderViewItem::getLastFilterGeneration() const
+{
+	return getViewModelItem()->getLastFilterGeneration();
+}
+
+
 
 ///----------------------------------------------------------------------------
 /// Class LLFolderViewFolder
@@ -1010,10 +853,7 @@ LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ):
 	mTargetHeight(0.f),
 	mAutoOpenCountdown(0.f),
 	mLastArrangeGeneration( -1 ),
-	mLastCalculatedWidth(0),
-	mCompletedFilterGeneration(-1),
-	mMostFilteredDescendantGeneration(-1),
-	mPassedFolderFilter(FALSE)
+	mLastCalculatedWidth(0)
 {
 }
 
@@ -1025,25 +865,9 @@ LLFolderViewFolder::~LLFolderViewFolder( void )
 	gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit()
 }
 
-void LLFolderViewFolder::setFilteredFolder(bool filtered, S32 filter_generation)
-{
-	mPassedFolderFilter = filtered;
-	mLastFilterGeneration = filter_generation;
-}
-
-bool LLFolderViewFolder::getFilteredFolder(S32 filter_generation)
-{
-	return mPassedFolderFilter && mLastFilterGeneration >= getRoot()->getFilter()->getFirstSuccessGeneration();
-}
-
 // addToFolder() returns TRUE if it succeeds. FALSE otherwise
 BOOL LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder)
 {
-	if (!folder)
-	{
-		return FALSE;
-	}
-	mParentFolder = folder;
 	return folder->addFolder(this);
 }
 
@@ -1051,7 +875,7 @@ static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange");
 
 // Finds width and height of this object and its children. Also
 // makes sure that this view and its children are the right size.
-S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation)
+S32 LLFolderViewFolder::arrange( S32* width, S32* height )
 {
 	// sort before laying out contents
 	getRoot()->getFolderViewModel()->sort(this);
@@ -1060,7 +884,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation)
 
 	// evaluate mHasVisibleChildren
 	mHasVisibleChildren = false;
-	if (hasFilteredDescendants(filter_generation))
+	if (getViewModelItem()->descendantsPassedFilter())
 	{
 		// We have to verify that there's at least one child that's not filtered out
 		bool found = false;
@@ -1068,7 +892,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation)
 		for (items_t::iterator iit = mItems.begin(); iit != mItems.end(); ++iit)
 		{
 			LLFolderViewItem* itemp = (*iit);
-			found = (itemp->getFiltered(filter_generation));
+			found = itemp->passedFilter();
 			if (found)
 				break;
 		}
@@ -1078,9 +902,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation)
 			for (folders_t::iterator fit = mFolders.begin(); fit != mFolders.end(); ++fit)
 			{
 				LLFolderViewFolder* folderp = (*fit);
-				found = ( (folderp->getFiltered(filter_generation)
-									 ||	(folderp->getFilteredFolder(filter_generation) 
-										 && folderp->hasFilteredDescendants(filter_generation))));
+				found = folderp->passedFilter();
 				if (found)
 					break;
 			}
@@ -1090,7 +912,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation)
 	}
 
 	// calculate height as a single item (without any children), and reshapes rectangle to match
-	LLFolderViewItem::arrange( width, height, filter_generation );
+	LLFolderViewItem::arrange( width, height );
 
 	// clamp existing animated height so as to never get smaller than a single item
 	mCurHeight = llmax((F32)*height, mCurHeight);
@@ -1113,16 +935,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation)
 			for(folders_t::iterator fit = mFolders.begin(); fit != mFolders.end(); ++fit)
 			{
 				LLFolderViewFolder* folderp = (*fit);
-				if (getRoot()->getDebugFilters())
-				{
-					folderp->setVisible(TRUE);
-				}
-				else
-				{
-					folderp->setVisible( folderp->getFiltered(filter_generation)
-											||	(folderp->getFilteredFolder(filter_generation) 
-												&& folderp->hasFilteredDescendants(filter_generation))); // passed filter or has descendants that passed filter
-				}
+				folderp->setVisible(folderp->passedFilter()); // passed filter or has descendants that passed filter
 
 				if (folderp->getVisible())
 				{
@@ -1130,7 +943,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation)
 					S32 child_height = 0;
 					S32 child_top = parent_item_height - llround(running_height);
 
-					target_height += folderp->arrange( &child_width, &child_height, filter_generation );
+					target_height += folderp->arrange( &child_width, &child_height );
 
 					running_height += (F32)child_height;
 					*width = llmax(*width, child_width);
@@ -1141,14 +954,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation)
 				iit != mItems.end(); ++iit)
 			{
 				LLFolderViewItem* itemp = (*iit);
-				if (getRoot()->getDebugFilters())
-				{
-					itemp->setVisible(TRUE);
-				}
-				else
-				{
-					itemp->setVisible(itemp->getFiltered(filter_generation));
-				}
+				itemp->setVisible(itemp->passedFilter());
 
 				if (itemp->getVisible())
 				{
@@ -1156,7 +962,7 @@ S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation)
 					S32 child_height = 0;
 					S32 child_top = parent_item_height - llround(running_height);
 
-					target_height += itemp->arrange( &child_width, &child_height, filter_generation );
+					target_height += itemp->arrange( &child_width, &child_height );
 					// don't change width, as this item is as wide as its parent folder by construction
 					itemp->reshape( itemp->getRect().getWidth(), child_height);
 
@@ -1234,234 +1040,21 @@ void LLFolderViewFolder::requestSort()
 	getViewModelItem()->requestSort();
 }
 
-void LLFolderViewFolder::setCompletedFilterGeneration(S32 generation, BOOL recurse_up)
-{
-	//mMostFilteredDescendantGeneration = llmin(mMostFilteredDescendantGeneration, generation);
-	mCompletedFilterGeneration = generation;
-	// only aggregate up if we are a lower (older) value
-	if (recurse_up
-		&& mParentFolder
-		&& generation < mParentFolder->getCompletedFilterGeneration())
-	{
-		mParentFolder->setCompletedFilterGeneration(generation, TRUE);
-	}
-}
+//TODO RN: get height resetting working
+//void LLFolderViewFolder::setPassedFilter(BOOL passed, BOOL passed_folder, S32 filter_generation)
+//{
+//	// if this folder is now filtered, but wasn't before
+//	// (it just passed)
+//	if (passed && !passedFilter(filter_generation))
+//	{
+//		// reset current height, because last time we drew it
+//		// it might have had more visible items than now
+//		mCurHeight = 0.f;
+//	}
+//
+//	LLFolderViewItem::setPassedFilter(passed, passed_folder, filter_generation);
+//}
 
-void LLFolderViewFolder::filter( LLFolderViewFilter& filter)
-{
-	S32 filter_generation = filter.getCurrentGeneration();
-	// if failed to pass filter newer than must_pass_generation
-	// you will automatically fail this time, so we only
-	// check against items that have passed the filter
-	S32 must_pass_generation = filter.getFirstRequiredGeneration();
-	
-	bool autoopen_folders = filter.showAllResults();
-
-	// if we have already been filtered against this generation, skip out
-	if (getCompletedFilterGeneration() >= filter_generation)
-	{
-		return;
-	}
-
-	// filter folder itself
-	if (getLastFilterGeneration() < filter_generation)
-	{
-		if (getLastFilterGeneration() >= must_pass_generation	// folder has been compared to a valid precursor filter
-			&& !mPassedFilter)									// and did not pass the filter
-		{
-			// go ahead and flag this folder as done
-			mLastFilterGeneration = filter_generation;			
-			//TODO RN: create interface for string highlighting
-			//mStringMatchOffset = std::string::npos;
-		}
-		else // filter self only on first pass through
-		{
-			// filter against folder rules
-			filterFolder(filter);
-			// and then item rules
-			LLFolderViewItem::filter( filter );
-		}
-	}
-
-	if (getRoot()->getDebugFilters())
-	{
-		mStatusText = llformat("%d", mLastFilterGeneration);
-		mStatusText += llformat("(%d)", mCompletedFilterGeneration);
-		mStatusText += llformat("+%d", mMostFilteredDescendantGeneration);
-	}
-
-	// all descendants have been filtered later than must pass generation
-	// but none passed
-	if(getCompletedFilterGeneration() >= must_pass_generation && !hasFilteredDescendants(must_pass_generation))
-	{
-		// don't traverse children if we've already filtered them since must_pass_generation
-		// and came back with nothing
-		return;
-	}
-
-	// we entered here with at least one filter iteration left
-	// check to see if we have any more before continuing on to children
-	if (filter.getFilterCount() < 0)
-	{
-		return;
-	}
-
-	// now query children
-	for (folders_t::iterator iter = mFolders.begin();
-		 iter != mFolders.end();
-		 ++iter)
-	{
-		LLFolderViewFolder* folder = (*iter);
-		// have we run out of iterations this frame?
-		if (filter.getFilterCount() < 0)
-		{
-			break;
-		}
-
-		// mMostFilteredDescendantGeneration might have been reset
-		// in which case we need to update it even for folders that
-		// don't need to be filtered anymore
-		if (folder->getCompletedFilterGeneration() >= filter_generation)
-		{
-			// track latest generation to pass any child items
-			if (folder->getFiltered() || folder->hasFilteredDescendants(filter.getFirstSuccessGeneration()))
-			{
-				mMostFilteredDescendantGeneration = filter_generation;
-				requestArrange();
-			}
-			// just skip it, it has already been filtered
-			continue;
-		}
-
-		// update this folders filter status (and children)
-		folder->filter( filter );
-
-		// track latest generation to pass any child items
-		if (folder->getFiltered() || folder->hasFilteredDescendants(filter_generation))
-		{
-			mMostFilteredDescendantGeneration = filter_generation;
-			requestArrange();
-			if (getRoot()->needsAutoSelect() && autoopen_folders)
-			{
-				folder->setOpenArrangeRecursively(TRUE);
-			}
-		}
-	}
-
-	for (items_t::iterator iter = mItems.begin();
-		 iter != mItems.end();
-		 ++iter)
-	{
-		LLFolderViewItem* item = (*iter);
-		if (filter.getFilterCount() < 0)
-		{
-			break;
-		}
-		if (item->getLastFilterGeneration() >= filter_generation)
-		{
-			if (item->getFiltered())
-			{
-				mMostFilteredDescendantGeneration = filter_generation;
-				requestArrange();
-			}
-			continue;
-		}
-
-		if (item->getLastFilterGeneration() >= must_pass_generation && 
-			!item->getFiltered(must_pass_generation))
-		{
-			// failed to pass an earlier filter that was a subset of the current one
-			// go ahead and flag this item as done
-			item->setFiltered(FALSE, filter_generation);
-			continue;
-		}
-
-		item->filter( filter );
-
-		if (item->getFiltered(filter.getFirstSuccessGeneration()))
-		{
-			mMostFilteredDescendantGeneration = filter_generation;
-			requestArrange();
-		}
-	}
-
-	// if we didn't use all filter iterations
-	// that means we filtered all of our descendants
-	// instead of exhausting the filter count for this frame
-	if (filter.getFilterCount() > 0)
-	{
-		// flag this folder as having completed filter pass for all descendants
-		setCompletedFilterGeneration(filter_generation, FALSE/*dont recurse up to root*/);
-	}
-}
-
-void LLFolderViewFolder::filterFolder(LLFolderViewFilter& filter)
-{
-	const BOOL previous_passed_filter = mPassedFolderFilter;
-	const BOOL passed_filter = filter.checkFolder(this);
-
-	// If our visibility will change as a result of this filter, then
-	// we need to be rearranged in our parent folder
-	if (mParentFolder)
-	{
-		if (getVisible() != passed_filter
-			|| previous_passed_filter != passed_filter )
-		{
-			mParentFolder->requestArrange();
-		}
-	}
-
-	setFilteredFolder(passed_filter, filter.getCurrentGeneration());
-	filter.decrementFilterCount();
-
-	if (getRoot()->getDebugFilters())
-	{
-		mStatusText = llformat("%d", mLastFilterGeneration);
-	}
-}
-
-void LLFolderViewFolder::setFiltered(BOOL filtered, S32 filter_generation)
-{
-	// if this folder is now filtered, but wasn't before
-	// (it just passed)
-	if (filtered && !mPassedFilter)
-	{
-		// reset current height, because last time we drew it
-		// it might have had more visible items than now
-		mCurHeight = 0.f;
-	}
-
-	LLFolderViewItem::setFiltered(filtered, filter_generation);
-}
-
-void LLFolderViewFolder::dirtyFilter()
-{
-	// we're a folder, so invalidate our completed generation
-	setCompletedFilterGeneration(-1, FALSE);
-	LLFolderViewItem::dirtyFilter();
-}
-
-BOOL LLFolderViewFolder::getFiltered() 
-{ 
-	return getFilteredFolder(getRoot()->getFilter()->getFirstSuccessGeneration())
-		&& LLFolderViewItem::getFiltered(); 
-}
-
-BOOL LLFolderViewFolder::getFiltered(S32 filter_generation) 
-{
-	return getFilteredFolder(filter_generation) && LLFolderViewItem::getFiltered(filter_generation);
-}
-
-BOOL LLFolderViewFolder::hasFilteredDescendants(S32 filter_generation)
-{ 
-	return mMostFilteredDescendantGeneration >= filter_generation; 
-}
-
-
-BOOL LLFolderViewFolder::hasFilteredDescendants()
-{
-	return mMostFilteredDescendantGeneration >= getRoot()->getFilter()->getFirstSuccessGeneration();
-}
 
 // Passes selection information on to children and record selection
 // information if necessary.
@@ -1824,39 +1417,7 @@ void LLFolderViewFolder::destroyView()
 		folderp->destroyView(); // removes entry from mFolders
 	}
 
-	if (mParentFolder)
-	{
-		mParentFolder->removeView(this);
-	}
-}
-
-// remove the specified item (and any children) if possible. Return
-// TRUE if the item was deleted.
-BOOL LLFolderViewFolder::removeItem(LLFolderViewItem* item)
-{
-	if(item->remove())
-	{
-		return TRUE;
-	}
-	return FALSE;
-}
-
-// simply remove the view (and any children) Don't bother telling the
-// listeners.
-void LLFolderViewFolder::removeView(LLFolderViewItem* item)
-{
-	if (!item || item->getParentFolder() != this)
-	{
-		return;
-	}
-	// deselect without traversing hierarchy
-	if (item->isSelected())
-	{
-		item->deselectItem();
-	}
-	getRoot()->removeFromSelectionList(item);
-	extractItem(item);
-	delete item;
+	LLFolderViewItem::destroyView();
 }
 
 // extractItem() removes the specified item from the folder, but
@@ -1882,7 +1443,7 @@ void LLFolderViewFolder::extractItem( LLFolderViewItem* item )
 		mItems.erase(it);
 	}
 	//item has been removed, need to update filter
-	dirtyFilter();
+	getViewModelItem()->dirtyFilter();
 	//because an item is going away regardless of filter status, force rearrange
 	requestArrange();
 	removeChild(item);
@@ -1890,31 +1451,28 @@ void LLFolderViewFolder::extractItem( LLFolderViewItem* item )
 
 BOOL LLFolderViewFolder::isMovable()
 {
-	if( getViewModelItem() )
+	if( !(getViewModelItem()->isItemMovable()) )
 	{
-		if( !(getViewModelItem()->isItemMovable()) )
-		{
-			return FALSE;
-		}
+		return FALSE;
+	}
 
-		for (items_t::iterator iter = mItems.begin();
-			iter != mItems.end();)
+	for (items_t::iterator iter = mItems.begin();
+		iter != mItems.end();)
+	{
+		items_t::iterator iit = iter++;
+		if(!(*iit)->isMovable())
 		{
-			items_t::iterator iit = iter++;
-			if(!(*iit)->isMovable())
-			{
-				return FALSE;
-			}
+			return FALSE;
 		}
+	}
 
-		for (folders_t::iterator iter = mFolders.begin();
-			iter != mFolders.end();)
+	for (folders_t::iterator iter = mFolders.begin();
+		iter != mFolders.end();)
+	{
+		folders_t::iterator fit = iter++;
+		if(!(*fit)->isMovable())
 		{
-			folders_t::iterator fit = iter++;
-			if(!(*fit)->isMovable())
-			{
-				return FALSE;
-			}
+			return FALSE;
 		}
 	}
 	return TRUE;
@@ -1923,31 +1481,28 @@ BOOL LLFolderViewFolder::isMovable()
 
 BOOL LLFolderViewFolder::isRemovable()
 {
-	if( getViewModelItem() )
+	if( !(getViewModelItem()->isItemRemovable()) )
 	{
-		if( !(getViewModelItem()->isItemRemovable()) )
-		{
-			return FALSE;
-		}
+		return FALSE;
+	}
 
-		for (items_t::iterator iter = mItems.begin();
-			iter != mItems.end();)
+	for (items_t::iterator iter = mItems.begin();
+		iter != mItems.end();)
+	{
+		items_t::iterator iit = iter++;
+		if(!(*iit)->isRemovable())
 		{
-			items_t::iterator iit = iter++;
-			if(!(*iit)->isRemovable())
-			{
-				return FALSE;
-			}
+			return FALSE;
 		}
+	}
 
-		for (folders_t::iterator iter = mFolders.begin();
-			iter != mFolders.end();)
+	for (folders_t::iterator iter = mFolders.begin();
+		iter != mFolders.end();)
+	{
+		folders_t::iterator fit = iter++;
+		if(!(*fit)->isRemovable())
 		{
-			folders_t::iterator fit = iter++;
-			if(!(*fit)->isRemovable())
-			{
-				return FALSE;
-			}
+			return FALSE;
 		}
 	}
 	return TRUE;
@@ -1956,6 +1511,12 @@ BOOL LLFolderViewFolder::isRemovable()
 // this is an internal method used for adding items to folders. 
 BOOL LLFolderViewFolder::addItem(LLFolderViewItem* item)
 {
+	if (item->getParentFolder())
+	{
+		item->getParentFolder()->extractItem(item);
+	}
+	item->setParentFolder(this);
+
 	mItems.push_back(item);
 	
 	item->setRect(LLRect(0, 0, getRect().getWidth(), 0));
@@ -1963,12 +1524,14 @@ BOOL LLFolderViewFolder::addItem(LLFolderViewItem* item)
 	
 	addChild(item);
 	
-	item->dirtyFilter();
+	item->getViewModelItem()->dirtyFilter();
 
 	// Handle sorting
 	requestArrange();
 	requestSort();
 
+	getViewModelItem()->addChild(item->getViewModelItem());
+
 	//TODO RN - make sort bubble up as long as parent Folder doesn't have anything matching sort criteria
 	//// Traverse parent folders and update creation date and resort, if necessary
 	//LLFolderViewFolder* parentp = this;
@@ -1989,16 +1552,23 @@ BOOL LLFolderViewFolder::addItem(LLFolderViewItem* item)
 // this is an internal method used for adding items to folders. 
 BOOL LLFolderViewFolder::addFolder(LLFolderViewFolder* folder)
 {
+	if (folder->mParentFolder)
+	{
+		folder->mParentFolder->extractItem(folder);
+	}
+	folder->mParentFolder = this;
 	mFolders.push_back(folder);
 	folder->setOrigin(0, 0);
 	folder->reshape(getRect().getWidth(), 0);
 	folder->setVisible(FALSE);
 	addChild( folder );
-	folder->dirtyFilter();
+	folder->getViewModelItem()->dirtyFilter();
 	// rearrange all descendants too, as our indentation level might have changed
 	folder->requestArrange();
 	requestSort();
 
+	getViewModelItem()->addChild(folder->getViewModelItem());
+
 	return TRUE;
 }
 
@@ -2027,16 +1597,13 @@ void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType r
 {
 	BOOL was_open = isOpen();
 	mIsOpen = openitem;
-	if (getViewModelItem())
+	if(!was_open && openitem)
 	{
-		if(!was_open && openitem)
-		{
-			getViewModelItem()->openItem();
-		}
-		else if(was_open && !openitem)
-		{
-			getViewModelItem()->closeItem();
-		}
+		getViewModelItem()->openItem();
+	}
+	else if(was_open && !openitem)
+	{
+		getViewModelItem()->closeItem();
 	}
 
 	if (recurse == RECURSE_DOWN || recurse == RECURSE_UP_DOWN)
@@ -2068,7 +1635,7 @@ BOOL LLFolderViewFolder::handleDragAndDropFromChild(MASK mask,
 													EAcceptance* accept,
 													std::string& tooltip_msg)
 {
-	BOOL accepted = mListener && mListener->dragOrDrop(mask,drop,c_type,cargo_data, tooltip_msg);
+	BOOL accepted = mListener->dragOrDrop(mask,drop,c_type,cargo_data, tooltip_msg);
 	if (accepted) 
 	{
 		mDragAndDropTarget = TRUE;
@@ -2156,7 +1723,7 @@ BOOL LLFolderViewFolder::handleDragAndDropToThisFolder(MASK mask,
 													   EAcceptance* accept,
 													   std::string& tooltip_msg)
 {
-	BOOL accepted = getViewModelItem() && getViewModelItem()->dragOrDrop(mask,drop,cargo_type,cargo_data, tooltip_msg);
+	BOOL accepted = getViewModelItem()->dragOrDrop(mask,drop,cargo_type,cargo_data, tooltip_msg);
 	
 	if (accepted) 
 	{
@@ -2259,7 +1826,7 @@ BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask )
 		}
 		else
 		{
-			setSelectionFromRoot(this, FALSE);
+			getRoot()->setSelection(this, FALSE);
 			toggleOpen();
 		}
 		handled = TRUE;
@@ -2293,16 +1860,6 @@ void LLFolderViewFolder::draw()
 	mExpanderHighlighted = FALSE;
 }
 
-BOOL	LLFolderViewFolder::potentiallyVisible()
-{
-	// folder should be visible by it's own filter status
-	return LLFolderViewItem::potentiallyVisible() 	
-		// or one or more of its descendants have passed the minimum filter requirement
-		|| hasFilteredDescendants()
-		// or not all of its descendants have been checked against minimum filter requirement
-		|| getCompletedFilterGeneration() < getRoot()->getFilter()->getFirstSuccessGeneration();
-}
-
 // this does prefix traversal, as folders are listed above their contents
 LLFolderViewItem* LLFolderViewFolder::getNextFromChild( LLFolderViewItem* item, BOOL include_children )
 {
diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h
index fd2948f34ee..7e489698267 100644
--- a/indra/newview/llfolderviewitem.h
+++ b/indra/newview/llfolderviewitem.h
@@ -35,6 +35,7 @@ class LLFolderViewModelItem;
 class LLFolderViewFolder;
 class LLFolderViewFunctor;
 class LLFolderViewFilter;
+class LLFolderViewModelInterface;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLFolderViewItem
@@ -78,8 +79,6 @@ class LLFolderViewItem : public LLView
 	static const F32 FOLDER_CLOSE_TIME_CONSTANT;
 	static const F32 FOLDER_OPEN_TIME_CONSTANT;
 
-	const std::string& getSearchableLabel() { return mSearchableLabel; }
-	
 private:
 	BOOL						mIsSelected;
 
@@ -90,7 +89,6 @@ class LLFolderViewItem : public LLView
 	LLFolderViewItem(const Params& p);
 
 	std::string					mLabel;
-	std::string					mSearchableLabel;
 	S32							mLabelWidth;
 	bool						mLabelWidthDirty;
 	LLFolderViewFolder*			mParentFolder;
@@ -106,8 +104,7 @@ class LLFolderViewItem : public LLView
 	BOOL						mHasVisibleChildren;
 	S32							mIndentation;
 	S32							mItemHeight;
-	BOOL						mPassedFilter;
-	S32							mLastFilterGeneration;
+
 	//TODO RN: create interface for string highlighting
 	//std::string::size_type		mStringMatchOffset;
 	F32							mControlLabelRotation;
@@ -115,9 +112,6 @@ class LLFolderViewItem : public LLView
 	BOOL						mDragAndDropTarget;
 	bool						mIsMouseOverTitle;
 
-	// helper function to change the selection from the root.
-	void changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected);
-
 	// this is an internal method used for adding items to folders. A
 	// no-op at this level, but reimplemented in derived classes.
 	virtual BOOL addItem(LLFolderViewItem*) { return FALSE; }
@@ -130,39 +124,20 @@ class LLFolderViewItem : public LLView
 
 	virtual void openItem( void );
 
-	// This function clears the currently selected item, and records
-	// the specified selected item appropriately for display and use
-	// in the UI. If open is TRUE, then folders are opened up along
-	// the way to the selection.
-	void setSelectionFromRoot(LLFolderViewItem* selection, BOOL openitem,
-		BOOL take_keyboard_focus = TRUE);
-
-	// This function is called when the folder view is dirty. It's
-	// implemented here but called by derived classes when folding the
-	// views.
-	void arrangeFromRoot();
-	void filterFromRoot( void );
-	
 	void arrangeAndSet(BOOL set_selection, BOOL take_keyboard_focus);
 
 	virtual ~LLFolderViewItem( void );
 
 	// addToFolder() returns TRUE if it succeeds. FALSE otherwise
-	enum { ARRANGE = TRUE, DO_NOT_ARRANGE = FALSE };
 	virtual BOOL addToFolder(LLFolderViewFolder* folder);
 
 	// Finds width and height of this object and it's children.  Also
 	// makes sure that this view and it's children are the right size.
-	virtual S32 arrange( S32* width, S32* height, S32 filter_generation );
+	virtual S32 arrange( S32* width, S32* height );
 	virtual S32 getItemHeight();
 
-	// applies filters to control visibility of items
-	virtual void filter( LLFolderViewFilter& filter);
-
 	// updates filter serial number and optionally propagated value up to root
-	S32		getLastFilterGeneration() { return mLastFilterGeneration; }
-
-	virtual void	dirtyFilter();
+	S32		getLastFilterGeneration() const;
 
 	// If 'selection' is 'this' then note that otherwise ignore.
 	// Returns TRUE if this item ends up being selected.
@@ -213,8 +188,6 @@ class LLFolderViewItem : public LLView
 	// viewed. This method will ask the viewed object itself.
 	const std::string& getName( void ) const;
 
-	const std::string& getSearchableLabel( void ) const;
-
 	// This method returns the label displayed on the view. This
 	// method was primarily added to allow sorting on the folder
 	// contents possible before the entire view has been constructed.
@@ -224,12 +197,17 @@ class LLFolderViewItem : public LLView
 	LLFolderViewFolder* getParentFolder( void ) { return mParentFolder; }
 	const LLFolderViewFolder* getParentFolder( void ) const { return mParentFolder; }
 
+	void setParentFolder(LLFolderViewFolder* parent) { mParentFolder = parent; }
+
 	LLFolderViewItem* getNextOpenNode( BOOL include_children = TRUE );
 	LLFolderViewItem* getPreviousOpenNode( BOOL include_children = TRUE );
 
 	const LLFolderViewModelItem* getViewModelItem( void ) const { return mListener; }
 	LLFolderViewModelItem* getViewModelItem( void ) { return mListener; }
 
+	const LLFolderViewModelInterface* getFolderViewModel( void ) const;
+	LLFolderViewModelInterface* getFolderViewModel( void );
+
 	// just rename the object.
 	void rename(const std::string& new_name);
 
@@ -239,15 +217,11 @@ class LLFolderViewItem : public LLView
 	virtual BOOL isOpen() const { return FALSE; }
 
 	virtual LLFolderView*	getRoot();
+	virtual const LLFolderView*	getRoot() const;
 	BOOL			isDescendantOf( const LLFolderViewFolder* potential_ancestor );
 	S32				getIndentation() { return mIndentation; }
 
-	virtual BOOL	potentiallyVisible(); // is the item definitely visible or we haven't made up our minds yet?
-	virtual BOOL	potentiallyHidden(); // did this item not pass the filter or do we not know yet?
-
-	virtual BOOL	getFiltered();
-	virtual BOOL	getFiltered(S32 filter_generation);
-	virtual void	setFiltered(BOOL filtered, S32 filter_generation);
+	virtual BOOL	passedFilter(S32 filter_generation = -1);
 
 	// refresh information from the object being viewed.
 	virtual void refresh();
@@ -305,7 +279,6 @@ class LLFolderViewFolder : public LLFolderViewItem
 	F32			mAutoOpenCountdown;
 	S32			mLastArrangeGeneration;
 	S32			mLastCalculatedWidth;
-	S32			mCompletedFilterGeneration;
 	S32			mMostFilteredDescendantGeneration;
 	bool		mNeedsSort;
 	bool		mPassedFolderFilter;
@@ -322,8 +295,6 @@ class LLFolderViewFolder : public LLFolderViewItem
 
 	virtual ~LLFolderViewFolder( void );
 
-	virtual BOOL	potentiallyVisible();
-
 	LLFolderViewItem* getNextFromChild( LLFolderViewItem*, BOOL include_children = TRUE );
 	LLFolderViewItem* getPreviousFromChild( LLFolderViewItem*, BOOL include_children = TRUE  );
 
@@ -332,34 +303,17 @@ class LLFolderViewFolder : public LLFolderViewItem
 
 	// Finds width and height of this object and it's children.  Also
 	// makes sure that this view and it's children are the right size.
-	virtual S32 arrange( S32* width, S32* height, S32 filter_generation );
+	virtual S32 arrange( S32* width, S32* height );
 
 	BOOL needsArrange();
 
-	virtual void	setCompletedFilterGeneration(S32 generation, BOOL recurse_up);
-	virtual S32		getCompletedFilterGeneration() { return mCompletedFilterGeneration; }
-
-	BOOL hasFilteredDescendants(S32 filter_generation);
-	BOOL hasFilteredDescendants();
-
-	// applies filters to control visibility of items
-	virtual void filter( LLFolderViewFilter& filter);
-	virtual void setFiltered(BOOL filtered, S32 filter_generation);
-	virtual BOOL getFiltered();
-	virtual BOOL getFiltered(S32 filter_generation);
-
-	virtual void dirtyFilter();
-	
-	// folder-specific filtering (filter status propagates top down instead of bottom up)
-	void filterFolder(LLFolderViewFilter& filter);
-	void setFilteredFolder(bool filtered, S32 filter_generation);
-	bool getFilteredFolder(S32 filter_generation);
+	bool descendantsPassedFilter(S32 filter_generation = -1);
 
 	// Passes selection information on to children and record
 	// selection information if necessary.
 	// Returns TRUE if this object (or a child) ends up being selected.
 	// If 'openitem' is TRUE then folders are opened up along the way to the selection.
-	virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus);
+	virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus = TRUE);
 
 	// This method is used to change the selection of an item.
 	// Recursively traverse all children; if 'selection' is 'this' then change
@@ -385,14 +339,6 @@ class LLFolderViewFolder : public LLFolderViewItem
 	//virtual BOOL removeRecursively(BOOL single_item);
 	//virtual BOOL remove();
 
-	// remove the specified item (and any children) if
-	// possible. Return TRUE if the item was deleted.
-	BOOL removeItem(LLFolderViewItem* item);
-
-	// simply remove the view (and any children) Don't bother telling
-	// the listeners.
-	void removeView(LLFolderViewItem* item);
-
 	// extractItem() removes the specified item from the folder, but
 	// doesn't delete it.
 	virtual void extractItem( LLFolderViewItem* item );
diff --git a/indra/newview/llfolderviewmodel.h b/indra/newview/llfolderviewmodel.h
index 74c8bb92efe..0216ba2a07e 100644
--- a/indra/newview/llfolderviewmodel.h
+++ b/indra/newview/llfolderviewmodel.h
@@ -72,9 +72,9 @@ class LLFolderViewFilter
 	// +-------------------------------------------------------------------+
 	// + Execution And Results
 	// +-------------------------------------------------------------------+
-	virtual bool 				check(const LLFolderViewItem* item) = 0;
+	virtual bool 				check(const LLFolderViewModelItem* item) = 0;
 	virtual bool				check(const LLInventoryItem* item) = 0;
-	virtual bool				checkFolder(const LLFolderViewFolder* folder) const = 0;
+	virtual bool				checkFolder(const LLFolderViewModelItem* folder) const = 0;
 	virtual bool				checkFolder(const LLUUID& folder_id) const = 0;
 
 	virtual void 				setEmptyLookupMessage(const std::string& message) = 0;
@@ -126,6 +126,8 @@ class LLFolderViewModelInterface
 
 	virtual bool contentsReady() = 0;
 	virtual void setFolderView(LLFolderView* folder_view) = 0;
+	virtual LLFolderViewFilter* getFilter() = 0;
+	virtual const LLFolderViewFilter* getFilter() const = 0;
 };
 
 class LLFolderViewModelCommon : public LLFolderViewModelInterface
@@ -152,20 +154,82 @@ class LLFolderViewModelCommon : public LLFolderViewModelInterface
 
 };
 
+template <typename SORT_TYPE, typename ITEM_TYPE, typename FOLDER_TYPE, typename FILTER_TYPE>
+class LLFolderViewModel : public LLFolderViewModelCommon
+{
+public:
+	LLFolderViewModel(){}
+	virtual ~LLFolderViewModel() {}
+	
+	typedef SORT_TYPE		SortType;
+	typedef ITEM_TYPE		ItemType;
+	typedef FOLDER_TYPE		FolderType;
+	typedef FILTER_TYPE		FilterType;
+	
+	virtual SortType& getSorter()					 { return mSorter; }
+	virtual const SortType& getSorter() const 		 { return mSorter; }
+	virtual void setSorter(const SortType& sorter) 	 { mSorter = sorter; requestSortAll(); }
+
+	virtual FilterType* getFilter() 				 { return &mFilter; }
+	virtual const FilterType* getFilter() const		 { return &mFilter; }
+	virtual void setFilter(const FilterType& filter) { mFilter = filter; }
+
+	// TODO RN: remove this and put all filtering logic in view model
+	// add getStatusText and isFiltering()
+	virtual bool contentsReady()					{ return true; }
+
+	struct ViewModelCompare
+	{
+		ViewModelCompare(const SortType& sorter)
+		:	mSorter(sorter)
+		{}
+		
+		bool operator () (const LLFolderViewItem* a, const LLFolderViewItem* b) const
+		{
+			return mSorter(static_cast<const ItemType*>(a->getViewModelItem()), static_cast<const ItemType*>(b->getViewModelItem()));
+		}
+
+		bool operator () (const LLFolderViewFolder* a, const LLFolderViewFolder* b) const
+		{
+			return mSorter(static_cast<const ItemType*>(a->getViewModelItem()), static_cast<const ItemType*>(b->getViewModelItem()));
+		}
+
+		const SortType& mSorter;
+	};
+
+	void sort(LLFolderViewFolder* folder)
+	{
+		if (needsSort(folder->getViewModelItem()))
+		{
+			folder->sortFolders(ViewModelCompare(getSorter()));
+			folder->sortItems(ViewModelCompare(getSorter()));
+			folder->getViewModelItem()->setSortVersion(mTargetSortVersion);
+			folder->requestArrange();
+		}
+	}
+
+	//TODO RN: fix this
+	void filter(LLFolderViewFolder* folder)
+	{
+		
+	}
+
+protected:
+	SortType		mSorter;
+	FilterType		mFilter;
+};
+
 // This is am abstract base class that users of the folderview classes
 // would use to bridge the folder view with the underlying data
 class LLFolderViewModelItem
 {
 public:
-	LLFolderViewModelItem()
-	:	mFolderViewItem(NULL)
-	{}
-
 	virtual ~LLFolderViewModelItem( void ) {};
 
 	virtual void update() {}	//called when drawing
 	virtual const std::string& getName() const = 0;
 	virtual const std::string& getDisplayName() const = 0;
+	virtual const std::string& getSearchableName() const = 0;
 
 	virtual LLPointer<LLUIImage> getIcon() const = 0;
 	virtual LLPointer<LLUIImage> getIconOpen() const { return getIcon(); }
@@ -198,12 +262,23 @@ class LLFolderViewModelItem
 
 	virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0;
 	
+	virtual bool potentiallyVisible() = 0; // is the item definitely visible or we haven't made up our minds yet?
+
+	virtual void filter( LLFolderViewFilter& filter) = 0;
+	virtual bool passedFilter(S32 filter_generation = -1) = 0;
+	virtual bool descendantsPassedFilter(S32 filter_generation = -1) = 0;
+	virtual void setPassedFilter(bool passed, bool passed_folder, S32 filter_generation) = 0;
+	virtual void dirtyFilter() = 0;
+
+	virtual S32	getLastFilterGeneration() const = 0;
+
 	// This method should be called when a drag begins. returns TRUE
 	// if the drag can begin, otherwise FALSE.
 	virtual LLToolDragAndDrop::ESource getDragSource() const = 0;
 	virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const = 0;
 	
 	virtual bool hasChildren() const = 0;
+	virtual void addChild(LLFolderViewModelItem* child) = 0;
 
 	// This method will be called to determine if a drop can be
 	// performed, and will set drop to TRUE if a drop is
@@ -217,10 +292,12 @@ class LLFolderViewModelItem
 	virtual void requestSort() = 0;
 	virtual S32 getSortVersion() = 0;
 	virtual void setSortVersion(S32 version) = 0;
+	virtual void setParent(LLFolderViewModelItem* parent) = 0;
+
 protected:
+
 	friend class LLFolderViewItem;
-	void setFolderViewItem(LLFolderViewItem* folder_view_item) { mFolderViewItem = folder_view_item;}
-	LLFolderViewItem*	mFolderViewItem;
+	virtual void setFolderViewItem(LLFolderViewItem* folder_view_item) = 0;
 
 };
 
@@ -228,95 +305,48 @@ class LLFolderViewModelItemCommon : public LLFolderViewModelItem
 {
 public:
 	LLFolderViewModelItemCommon()
-	:	mSortVersion(-1)
+	:	mSortVersion(-1),
+		mPassedFilter(false),
+		mPassedFolderFilter(false),
+		mFolderViewItem(NULL),
+		mLastFilterGeneration(-1),
+		mMostFilteredDescendantGeneration(-1)
 	{}
 
 	void requestSort() { mSortVersion = -1; }
 	S32 getSortVersion() { return mSortVersion; }
 	void setSortVersion(S32 version) { mSortVersion = version;}
 
-protected:
-
-	S32 mSortVersion;
-};
-
-template <typename SORT_TYPE, typename ITEM_TYPE, typename FOLDER_TYPE, typename FILTER_TYPE>
-class LLFolderViewModel : public LLFolderViewModelCommon
-{
-public:
-	LLFolderViewModel(){}
-	virtual ~LLFolderViewModel() {}
-	
-	typedef SORT_TYPE		SortType;
-	typedef ITEM_TYPE		ItemType;
-	typedef FOLDER_TYPE		FolderType;
-	typedef FILTER_TYPE		FilterType;
-	
-	virtual SortType& getSorter()					 { return mSorter; }
-	virtual const SortType& getSorter() const 		 { return mSorter; }
-	virtual void setSorter(const SortType& sorter) 	 { mSorter = sorter; requestSortAll(); }
-	virtual FilterType& getFilter() 				 { return mFilter; }
-	virtual const FilterType& getFilter() const		 { return mFilter; }
-	virtual void setFilter(const FilterType& filter) { mFilter = filter; }
-
-	// TODO RN: remove this and put all filtering logic in view model
-	// add getStatusText and isFiltering()
-	virtual bool contentsReady()					{ return true; }
-
-	struct ViewModelCompare
+	S32	getLastFilterGeneration() const { return mLastFilterGeneration; }
+	void dirtyFilter()
 	{
-		ViewModelCompare(const SortType& sorter)
-		:	mSorter(sorter)
-		{}
-		
-		bool operator () (const LLFolderViewItem* a, const LLFolderViewItem* b) const
+		mLastFilterGeneration = -1;
+		// bubble up dirty flag all the way to root
+		if (mParent)
 		{
-			return mSorter(static_cast<const ItemType*>(a->getViewModelItem()), static_cast<const ItemType*>(b->getViewModelItem()));
+			mParent->dirtyFilter();
 		}
+	}
+	virtual void addChild(LLFolderViewModelItem* child) { mChildren.push_back(child); child->setParent(this); }
 
-		bool operator () (const LLFolderViewFolder* a, const LLFolderViewFolder* b) const
-		{
-			return mSorter(static_cast<const ItemType*>(a->getViewModelItem()), static_cast<const ItemType*>(b->getViewModelItem()));
-		}
+protected:
+	virtual void setParent(LLFolderViewModelItem* parent) { mParent = parent; }
 
-		const SortType& mSorter;
-	};
+	S32						mSortVersion;
+	bool					mPassedFilter;
+	bool					mPassedFolderFilter;
 
-	void sort(LLFolderViewFolder* folder)
-	{
-		if (needsSort(folder->getViewModelItem()))
-		{
-			folder->sortFolders(ViewModelCompare(getSorter()));
-			folder->sortItems(ViewModelCompare(getSorter()));
-			folder->getViewModelItem()->setSortVersion(mTargetSortVersion);
-			folder->requestArrange();
-		}
-	}
+	S32						mLastFilterGeneration;
+	S32						mMostFilteredDescendantGeneration;
 
-	//TODO RN: fix this
-	void filter(LLFolderViewFolder* folder)
-	{
-		/*FilterType& filter = getFilter();
-		for (std::list<LLFolderViewItem*>::const_iterator it = folder->getItemsBegin(), end_it = folder->getItemsEnd();
-			it != end_it;
-			++it)
-		{
-			LLFolderViewItem* child_item = *it;
-			child_item->setFiltered(filter.checkFolder(static_cast<ItemType*>(child_item->getViewModelItem())), filter.getCurrentGeneration());
-		}
 
-		for (std::list<LLFolderViewFolder*>::const_iterator it = folder->getFoldersBegin(), end_it = folder->getFoldersEnd();
-			it != end_it;
-			++it)
-		{
-			LLFolderViewItem* child_folder = *it;
-			child_folder->setFiltered(filter.check(static_cast<ItemType*>(child_folder->getViewModelItem())), filter.getCurrentGeneration());
-		}*/
-	}
+	typedef std::list<LLFolderViewModelItem*> child_list_t;
+	child_list_t			mChildren;
+	LLFolderViewModelItem*	mParent;
 
-protected:
-	SortType		mSorter;
-	FilterType		mFilter;
+	void setFolderViewItem(LLFolderViewItem* folder_view_item) { mFolderViewItem = folder_view_item;}
+	LLFolderViewItem*		mFolderViewItem;
 };
 
+
 #endif
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 70a174a1400..45a2bffa6b4 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -1545,6 +1545,10 @@ void LLItemBridge::buildDisplayName() const
 	{
 		mDisplayName.assign(LLStringUtil::null);
 	}
+
+	mSearchableName.assign(mDisplayName);
+	mSearchableName.append(getLabelSuffix());
+	LLStringUtil::toUpper(mSearchableName);
 }
 
 LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const
@@ -1850,11 +1854,9 @@ void LLFolderBridge::buildDisplayName() const
 		LLTrans::findString(mDisplayName, std::string("InvFolder ") + getName(), LLSD());
 	}
 
-	//if (mDisplayName.empty())
-	//{
-	//	S32 foo;
-	//	foo = 0;
-	//}
+	mSearchableName.assign(mDisplayName);
+	mSearchableName.append(getLabelSuffix());
+	LLStringUtil::toUpper(mSearchableName);
 }
 
 
@@ -4000,7 +4002,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 			LLFolderViewItem* fv_item =   active_panel->getItemByID(inv_item->getUUID());
 			if (!fv_item) return false;
 
-			accept = filter->check(fv_item);
+			accept = filter->check(fv_item->getViewModelItem());
 		}
 
 		if (accept && drop)
@@ -4222,7 +4224,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,
 				LLFolderViewItem* fv_item =   active_panel->getItemByID(inv_item->getUUID());
 				if (!fv_item) return false;
 
-				accept = filter->check(fv_item);
+				accept = filter->check(fv_item->getViewModelItem());
 			}
 
 			if (accept && drop)
@@ -4319,7 +4321,7 @@ bool check_item(const LLUUID& item_id,
 	LLFolderViewItem* fv_item = active_panel->getItemByID(item_id);
 	if (!fv_item) return false;
 
-	return filter->check(fv_item);
+	return filter->check(fv_item->getViewModelItem());
 }
 
 // +=================================================+
@@ -6126,7 +6128,7 @@ void LLLinkFolderBridge::gotoItem()
 				model->fetchDescendentsOf(cat_uuid);
 			}
 			base_folder->setOpen(TRUE);
-			mRoot->setSelectionFromRoot(base_folder,TRUE);
+			mRoot->setSelection(base_folder,TRUE);
 			mRoot->scrollToShowSelection();
 		}
 	}
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 26789627f7a..b0582d003d1 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -88,6 +88,8 @@ class LLInvFVBridge : public LLFolderViewModelItemInventory
 	//--------------------------------------------------------------------
 	virtual const std::string& getName() const;
 	virtual const std::string& getDisplayName() const;
+	const std::string& getSearchableName() const { return mSearchableName; }
+
 	virtual PermissionMask getPermissionMask() const;
 	virtual LLFolderType::EType getPreferredType() const;
 	virtual time_t getCreationDate() const;
@@ -174,6 +176,7 @@ class LLInvFVBridge : public LLFolderViewModelItemInventory
 	bool						mIsLink;
 	LLTimer						mTimeSinceRequestStart;
 	mutable std::string			mDisplayName;
+	mutable std::string			mSearchableName;
 
 	void purgeItem(LLInventoryModel *model, const LLUUID &uuid);
 	virtual void buildDisplayName() const {}
diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index c13bb5123e9..c7e0136368e 100644
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -71,35 +71,35 @@ LLInventoryFilter::LLInventoryFilter(const Params& p)
     mFilterOps(p.filter_ops),
 	mOrder(p.sort_order),
 	mFilterSubString(p.substring),
-	mLastSuccessGeneration(0),
-	mLastFailGeneration(S32_MAX),
+	mCurrentGeneration(0),
+	mFirstRequiredGeneration(0),
 	mFirstSuccessGeneration(0),
 	mFilterCount(0)
 {
-	mNextFilterGeneration = mLastSuccessGeneration + 1;
+	mNextFilterGeneration = mCurrentGeneration + 1;
 
 	// copy mFilterOps into mDefaultFilterOps
 	markDefault();
 }
 
-bool LLInventoryFilter::check(const LLFolderViewItem* item) 
+bool LLInventoryFilter::check(const LLFolderViewModelItem* item) 
 {
+	const LLFolderViewModelItemInventory* listener = static_cast<const LLFolderViewModelItemInventory*>(item);
 	// Clipboard cut items are *always* filtered so we need this value upfront
-	const LLFolderViewModelItemInventory* listener = static_cast<const LLFolderViewModelItemInventory*>(item->getViewModelItem());
 	const BOOL passed_clipboard = (listener ? checkAgainstClipboard(listener->getUUID()) : TRUE);
 
 	// If it's a folder and we're showing all folders, return automatically.
-	const BOOL is_folder = (dynamic_cast<const LLFolderViewFolder*>(item) != NULL);
+	const BOOL is_folder = listener->getInventoryType() == LLInventoryType::IT_CATEGORY;;
 	if (is_folder && (mFilterOps.mShowFolderState == LLInventoryFilter::SHOW_ALL_FOLDERS))
 	{
 		return passed_clipboard;
 	}
 
-	std::string::size_type string_offset = mFilterSubString.size() ?   item->getSearchableLabel().find(mFilterSubString) : std::string::npos;
+	std::string::size_type string_offset = mFilterSubString.size() ? listener->getSearchableName().find(mFilterSubString) : std::string::npos;
 
-	const BOOL passed_filtertype = checkAgainstFilterType(item);
-	const BOOL passed_permissions = checkAgainstPermissions(item);
-	const BOOL passed_filterlink = checkAgainstFilterLinks(item);
+	const BOOL passed_filtertype = checkAgainstFilterType(listener);
+	const BOOL passed_permissions = checkAgainstPermissions(listener);
+	const BOOL passed_filterlink = checkAgainstFilterLinks(listener);
 	const BOOL passed = (passed_filtertype &&
 						 passed_permissions &&
 						 passed_filterlink &&
@@ -117,27 +117,19 @@ bool LLInventoryFilter::check(const LLInventoryItem* item)
 	const bool passed_permissions = checkAgainstPermissions(item);
 	const BOOL passed_clipboard = checkAgainstClipboard(item->getUUID());
 	const bool passed = (passed_filtertype 
-						&& passed_permissions
-						&& passed_clipboard 
-						&&	(mFilterSubString.size() == 0 || string_offset !=  std::string::npos));
+		&& passed_permissions
+		&& passed_clipboard 
+		&&	(mFilterSubString.size() == 0 || string_offset !=  std::string::npos));
 
 	return passed;
 }
 
-bool LLInventoryFilter::checkFolder(const LLFolderViewFolder* folder) const
+bool LLInventoryFilter::checkFolder(const LLFolderViewModelItem* item) const
 {
-	if (!folder)
-	{
-		llwarns << "The filter can not be checked on an invalid folder." << llendl;
-		llassert(false); // crash in development builds
-		return false;
-	}
-
-	const LLFolderViewModelItemInventory* listener = static_cast<const LLFolderViewModelItemInventory*>(folder->getViewModelItem());
+	const LLFolderViewModelItemInventory* listener = static_cast<const LLFolderViewModelItemInventory*>(item);
 	if (!listener)
 	{
-		llwarns << "Folder view event listener not found." << llendl;
-		llassert(false); // crash in development builds
+		llerrs << "Folder view event listener not found." << llendl;
 		return false;
 	}
 
@@ -179,9 +171,8 @@ bool LLInventoryFilter::checkFolder(const LLUUID& folder_id) const
 	return passed_clipboard;
 }
 
-bool LLInventoryFilter::checkAgainstFilterType(const LLFolderViewItem* item) const
+bool LLInventoryFilter::checkAgainstFilterType(const LLFolderViewModelItemInventory* listener) const
 {
-	const LLFolderViewModelItemInventory* listener = static_cast<const LLFolderViewModelItemInventory*>(item->getViewModelItem());
 	if (!listener) return FALSE;
 
 	LLInventoryType::EType object_type = listener->getInventoryType();
@@ -347,13 +338,12 @@ bool LLInventoryFilter::checkAgainstClipboard(const LLUUID& object_id) const
 	return true;
 }
 
-bool LLInventoryFilter::checkAgainstPermissions(const LLFolderViewItem* item) const
+bool LLInventoryFilter::checkAgainstPermissions(const LLFolderViewModelItemInventory* listener) const
 {
-	const LLFolderViewModelItemInventory* listener = static_cast<const LLFolderViewModelItemInventory*>(item->getViewModelItem());
 	if (!listener) return FALSE;
 
 	PermissionMask perm = listener->getPermissionMask();
-	const LLInvFVBridge *bridge = dynamic_cast<const LLInvFVBridge *>(item->getViewModelItem());
+	const LLInvFVBridge *bridge = dynamic_cast<const LLInvFVBridge *>(listener);
 	if (bridge && bridge->isLink())
 	{
 		const LLUUID& linked_uuid = gInventory.getLinkedItemID(bridge->getUUID());
@@ -375,9 +365,8 @@ bool LLInventoryFilter::checkAgainstPermissions(const LLInventoryItem* item) con
 	return (perm & mFilterOps.mPermissions) == mFilterOps.mPermissions;
 }
 
-bool LLInventoryFilter::checkAgainstFilterLinks(const LLFolderViewItem* item) const
+bool LLInventoryFilter::checkAgainstFilterLinks(const LLFolderViewModelItemInventory* listener) const
 {
-	const LLFolderViewModelItemInventory* listener = static_cast<const LLFolderViewModelItemInventory*>(item->getViewModelItem());
 	if (!listener) return TRUE;
 
 	const LLUUID object_id = listener->getUUID();
@@ -740,7 +729,7 @@ void LLInventoryFilter::resetDefault()
 void LLInventoryFilter::setModified(EFilterModified behavior)
 {
 	mFilterText.clear();
-	mLastSuccessGeneration = mNextFilterGeneration++;
+	mCurrentGeneration = mNextFilterGeneration++;
 
 	if (mFilterModified == FILTER_NONE)
 	{
@@ -753,33 +742,21 @@ void LLInventoryFilter::setModified(EFilterModified behavior)
 		mFilterModified = FILTER_RESTART;
 	}
 
-	if (isNotDefault())
-	{
-		// if not keeping current filter results, update last valid as well
-		switch(mFilterModified)
-		{
-			case FILTER_RESTART:
-				mLastFailGeneration = mLastSuccessGeneration;
-				mFirstSuccessGeneration = mLastSuccessGeneration;
-				break;
-			case FILTER_LESS_RESTRICTIVE:
-				mLastFailGeneration = mLastSuccessGeneration;
-				break;
-			case FILTER_MORE_RESTRICTIVE:
-				mFirstSuccessGeneration = mLastSuccessGeneration;
-				// must have passed either current filter generation (meaningless, as it hasn't been run yet)
-				// or some older generation, so keep the value
-				mLastFailGeneration = llmin(mLastFailGeneration,  mLastSuccessGeneration);
-				break;
-			default:
-				llerrs << "Bad filter behavior specified" << llendl;
-		}
-	}
-	else
+	// if not keeping current filter results, update last valid as well
+	switch(mFilterModified)
 	{
-		// shortcut disabled filters to show everything immediately
-		mLastFailGeneration = 0;
-		mFirstSuccessGeneration = S32_MAX;
+		case FILTER_RESTART:
+			mFirstRequiredGeneration = mCurrentGeneration;
+			mFirstSuccessGeneration = mCurrentGeneration;
+			break;
+		case FILTER_LESS_RESTRICTIVE:
+			mFirstRequiredGeneration = mCurrentGeneration;
+			break;
+		case FILTER_MORE_RESTRICTIVE:
+			mFirstSuccessGeneration = mCurrentGeneration;
+			break;
+		default:
+			llerrs << "Bad filter behavior specified" << llendl;
 	}
 }
 
@@ -1101,7 +1078,7 @@ void LLInventoryFilter::decrementFilterCount()
 
 S32 LLInventoryFilter::getCurrentGeneration() const 
 { 
-	return mLastSuccessGeneration;
+	return mCurrentGeneration;
 }
 S32 LLInventoryFilter::getFirstSuccessGeneration() const
 { 
@@ -1109,7 +1086,7 @@ S32 LLInventoryFilter::getFirstSuccessGeneration() const
 }
 S32 LLInventoryFilter::getFirstRequiredGeneration() const
 { 
-	return mLastFailGeneration; 
+	return mFirstRequiredGeneration; 
 }
 
 void LLInventoryFilter::setEmptyLookupMessage(const std::string& message)
diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h
index 5b92c21a855..af245a9c3bc 100644
--- a/indra/newview/llinventoryfilter.h
+++ b/indra/newview/llinventoryfilter.h
@@ -186,16 +186,10 @@ class LLInventoryFilter : public LLFolderViewFilter
 	// +-------------------------------------------------------------------+
 	// + Execution And Results
 	// +-------------------------------------------------------------------+
-	bool 				check(const LLFolderViewItem* item);
+	bool				check(const LLFolderViewModelItem* listener);
 	bool				check(const LLInventoryItem* item);
-	bool				checkFolder(const LLFolderViewFolder* folder) const;
+	bool				checkFolder(const LLFolderViewModelItem* listener) const;
 	bool				checkFolder(const LLUUID& folder_id) const;
-	bool 				checkAgainstFilterType(const LLFolderViewItem* item) const;
-	bool 				checkAgainstFilterType(const LLInventoryItem* item) const;
-	bool 				checkAgainstPermissions(const LLFolderViewItem* item) const;
-	bool 				checkAgainstPermissions(const LLInventoryItem* item) const;
-	bool 				checkAgainstFilterLinks(const LLFolderViewItem* item) const;
-	bool				checkAgainstClipboard(const LLUUID& object_id) const;
 
 	bool				showAllResults() const;
 
@@ -260,6 +254,12 @@ class LLInventoryFilter : public LLFolderViewFilter
 
 private:
 	bool				areDateLimitsSet();
+	bool 				checkAgainstFilterType(const class LLFolderViewModelItemInventory* listener) const;
+	bool 				checkAgainstFilterType(const LLInventoryItem* item) const;
+	bool 				checkAgainstPermissions(const class LLFolderViewModelItemInventory* listener) const;
+	bool 				checkAgainstPermissions(const LLInventoryItem* item) const;
+	bool 				checkAgainstFilterLinks(const class LLFolderViewModelItemInventory* listener) const;
+	bool				checkAgainstClipboard(const LLUUID& object_id) const;
 
 	U32						mOrder;
 
@@ -270,8 +270,8 @@ class LLInventoryFilter : public LLFolderViewFilter
 	std::string				mFilterSubStringOrig;
 	const std::string		mName;
 
-	S32						mLastSuccessGeneration;
-	S32						mLastFailGeneration;
+	S32						mCurrentGeneration;
+	S32						mFirstRequiredGeneration;
 	S32						mFirstSuccessGeneration;
 	S32						mNextFilterGeneration;
 
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 1e494c3ef1c..ff461236a20 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -983,7 +983,7 @@ void LLSaveFolderState::doFolder(LLFolderViewFolder* folder)
 
 void LLOpenFilteredFolders::doItem(LLFolderViewItem *item)
 {
-	if (item->getFiltered())
+	if (item->passedFilter())
 	{
 		item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
 	}
@@ -991,12 +991,12 @@ void LLOpenFilteredFolders::doItem(LLFolderViewItem *item)
 
 void LLOpenFilteredFolders::doFolder(LLFolderViewFolder* folder)
 {
-	if (folder->getFiltered() && folder->getParentFolder())
+	if (folder->LLFolderViewItem::passedFilter() && folder->getParentFolder())
 	{
 		folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
 	}
 	// if this folder didn't pass the filter, and none of its descendants did
-	else if (!folder->getFiltered() && !folder->hasFilteredDescendants())
+	else if (!folder->getViewModelItem()->passedFilter() && !folder->getViewModelItem()->descendantsPassedFilter())
 	{
 		folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO);
 	}
@@ -1004,7 +1004,7 @@ void LLOpenFilteredFolders::doFolder(LLFolderViewFolder* folder)
 
 void LLSelectFirstFilteredItem::doItem(LLFolderViewItem *item)
 {
-	if (item->getFiltered() && !mItemSelected)
+	if (item->passedFilter() && !mItemSelected)
 	{
 		item->getRoot()->setSelection(item, FALSE, FALSE);
 		if (item->getParentFolder())
@@ -1017,7 +1017,7 @@ void LLSelectFirstFilteredItem::doItem(LLFolderViewItem *item)
 
 void LLSelectFirstFilteredItem::doFolder(LLFolderViewFolder* folder)
 {
-	if (folder->getFiltered() && !mItemSelected)
+	if (folder->LLFolderViewItem::passedFilter() && !mItemSelected)
 	{
 		folder->getRoot()->setSelection(folder, FALSE, FALSE);
 		if (folder->getParentFolder())
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 74492e0005b..aba4c088ab9 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -254,18 +254,16 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)
 	mFolderRoot->setCallbackRegistrar(&mCommitCallbackRegistrar);
 	
 	// Scroller
-	{
-		LLRect scroller_view_rect = getRect();
-		scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
-		LLScrollContainer::Params scroller_params(params.scroll());
-		scroller_params.rect(scroller_view_rect);
-		mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
-		addChild(mScroller);
-		mScroller->addChild(mFolderRoot);
-		mFolderRoot->setScrollContainer(mScroller);
-		mFolderRoot->setFollowsAll();
-		mFolderRoot->addChild(mFolderRoot->mStatusTextBox);
-	}
+	LLRect scroller_view_rect = getRect();
+	scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom);
+	LLScrollContainer::Params scroller_params(params.scroll());
+	scroller_params.rect(scroller_view_rect);
+	mScroller = LLUICtrlFactory::create<LLFolderViewScrollContainer>(scroller_params);
+	addChild(mScroller);
+	mScroller->addChild(mFolderRoot);
+	mFolderRoot->setScrollContainer(mScroller);
+	mFolderRoot->setFollowsAll();
+	mFolderRoot->addChild(mFolderRoot->mStatusTextBox);
 
 	// Set up the callbacks from the inventory we're viewing, and then build everything.
 	mInventoryObserver = new LLInventoryPanelObserver(this);
@@ -344,12 +342,12 @@ void LLInventoryPanel::draw()
 
 const LLInventoryFilter* LLInventoryPanel::getFilter() const
 {
-	return &getFolderViewModel()->getFilter();
+	return getFolderViewModel()->getFilter();
 }
 
 LLInventoryFilter* LLInventoryPanel::getFilter()
 {
-	return &getFolderViewModel()->getFilter();
+	return getFolderViewModel()->getFilter();
 }
 
 void LLInventoryPanel::setFilterTypes(U64 types, LLInventoryFilter::EFilterType filter_type)
@@ -561,7 +559,6 @@ void LLInventoryPanel::modelChanged(U32 mask)
 						if (new_parent != NULL)
 						{
 							// Item is to be moved and we found its new parent in the panel's directory, so move the item's UI.
-							view_item->getParentFolder()->extractItem(view_item);
 							view_item->addToFolder(new_parent);
 							addItemID(viewmodel_item->getUUID(), view_item);
 						}
@@ -1358,3 +1355,104 @@ void LLFolderViewModelItemInventory::requestSort()
 		mFolderViewItem->getParentFolder()->getViewModelItem()->requestSort();
 	}
 }
+
+bool LLFolderViewModelItemInventory::potentiallyVisible()
+{
+	return passedFilter() // we've passed the filter
+		|| getLastFilterGeneration() < mFolderViewItem->getRoot()->getFolderViewModel()->getFilter()->getFirstSuccessGeneration() // or we don't know yet
+		|| descendantsPassedFilter();
+}
+
+bool LLFolderViewModelItemInventory::passedFilter(S32 filter_generation) 
+{ 
+	if (filter_generation < 0) filter_generation = mFolderViewItem->getRoot()->getFolderViewModel()->getFilter()->getFirstSuccessGeneration();
+	return mPassedFolderFilter 
+		&& mLastFilterGeneration >= filter_generation
+		&& (mPassedFilter || descendantsPassedFilter(filter_generation));
+}
+
+bool LLFolderViewModelItemInventory::descendantsPassedFilter(S32 filter_generation)
+{ 
+	if (filter_generation < 0) filter_generation = mFolderViewItem->getRoot()->getFolderViewModel()->getFilter()->getFirstSuccessGeneration();
+	return mMostFilteredDescendantGeneration >= filter_generation; 
+}
+
+void LLFolderViewModelItemInventory::setPassedFilter(bool passed, bool passed_folder, S32 filter_generation)
+{
+	mPassedFilter = passed;
+	mPassedFolderFilter = passed_folder;
+	mLastFilterGeneration = filter_generation;
+}
+
+void LLFolderViewModelItemInventory::filterChildItem( LLFolderViewModelItem* item, LLFolderViewFilter& filter )
+{
+	S32 filter_generation = filter.getCurrentGeneration();
+	S32 must_pass_generation = filter.getFirstRequiredGeneration();
+
+	// mMostFilteredDescendantGeneration might have been reset
+	// in which case we need to update it even for folders that
+	// don't need to be filtered anymore
+	if (item->getLastFilterGeneration() < filter_generation)
+	{
+		if (item->getLastFilterGeneration() >= must_pass_generation && 
+			!item->passedFilter(must_pass_generation))
+		{
+			// failed to pass an earlier filter that was a subset of the current one
+			// go ahead and flag this item as done
+			item->setPassedFilter(false, false, filter_generation);
+		}
+		else
+		{
+			//TODO RN:
+			item->filter( filter );
+		}
+	}
+
+	// track latest generation to pass any child items
+	if (item->passedFilter())
+	{
+		mMostFilteredDescendantGeneration = filter_generation;
+		//TODO RN: ensure this still happens
+		//requestArrange();
+	}
+}
+
+void LLFolderViewModelItemInventory::filter( LLFolderViewFilter& filter)
+{
+	if(getLastFilterGeneration() < filter.getFirstRequiredGeneration() // haven't checked descendants against minimum required generation to pass
+		|| descendantsPassedFilter(filter.getFirstRequiredGeneration())) // or at least one descendant has passed the minimum requirement
+	{
+		// now query children
+		for (child_list_t::iterator iter = mChildren.begin();
+			iter != mChildren.end() && filter.getFilterCount() > 0;
+			++iter)
+		{
+			filterChildItem((*iter), filter);
+		}
+	}
+
+	// if we didn't use all filter iterations
+	// that means we filtered all of our descendants
+	// so filter ourselves now
+	if (filter.getFilterCount() > 0)
+	{
+		const BOOL previous_passed_filter = mPassedFilter;
+		const BOOL passed_filter = filter.check(this);
+		const BOOL passed_filter_folder = (getInventoryType() == LLInventoryType::IT_CATEGORY) 
+								? filter.checkFolder(this)
+								: true;
+
+		// If our visibility will change as a result of this filter, then
+		// we need to be rearranged in our parent folder
+		LLFolderViewFolder* parent_folder = mFolderViewItem->getParentFolder();
+		if (parent_folder && passed_filter != previous_passed_filter)
+		{
+			parent_folder->requestArrange();
+		}
+	
+		setPassedFilter(passed_filter, passed_filter_folder, filter.getCurrentGeneration());
+		//TODO RN: create interface for string highlighting
+		//mStringMatchOffset = filter.getStringMatchOffset(this);
+		filter.decrementFilterCount();
+	}
+}
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index 645e2f6d76b..35a3f9b5e12 100644
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -62,6 +62,12 @@ class LLFolderViewModelItemInventory
 	virtual EInventorySortGroup getSortGroup() const = 0;
 	virtual LLInventoryObject* getInventoryObject() const = 0;
 	virtual void requestSort();
+	virtual bool potentiallyVisible();
+	virtual bool passedFilter(S32 filter_generation = -1);
+	virtual bool descendantsPassedFilter(S32 filter_generation = -1);
+	virtual void setPassedFilter(bool filtered, bool filtered_folder, S32 filter_generation);
+	virtual void filter( LLFolderViewFilter& filter);
+	virtual void filterChildItem( LLFolderViewModelItem* item, LLFolderViewFilter& filter);
 };
 
 class LLInventorySort
diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp
index 901c6379de3..0b899d34f48 100644
--- a/indra/newview/llpanellandmarks.cpp
+++ b/indra/newview/llpanellandmarks.cpp
@@ -102,7 +102,7 @@ void LLCheckFolderState::doFolder(LLFolderViewFolder* folder)
 	// Counting only folders that pass the filter.
 	// The listener check allow us to avoid counting the folder view
 	// object itself because it has no listener assigned.
-	if (folder->hasFilteredDescendants() && folder->getViewModelItem())
+	if (folder->getViewModelItem()->descendantsPassedFilter())
 	{
 		if (folder->isOpen())
 		{
diff --git a/indra/newview/llpanelmaininventory.cpp b/indra/newview/llpanelmaininventory.cpp
index e3446fdb3ab..33581160fd1 100644
--- a/indra/newview/llpanelmaininventory.cpp
+++ b/indra/newview/llpanelmaininventory.cpp
@@ -227,7 +227,7 @@ LLPanelMainInventory::~LLPanelMainInventory( void )
 	}
 	}
 
-        LLInventoryFilter* filter = getChild<LLInventoryPanel>("Recent   Items")->getFilter();
+        LLInventoryFilter* filter = findChild<LLInventoryPanel>("Recent   Items")->getFilter();
 		if (filter)
 		{
 			LLSD filterState;
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index da82d70f221..6a232a26f7a 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -77,6 +77,7 @@ class LLTaskInvFVBridge : public LLFolderViewModelItemInventory
 	LLUUID mUUID;
 	std::string mName;
 	mutable std::string mDisplayName;
+	mutable std::string mSearchableName;
 	LLPanelObjectInventory* mPanel;
 	U32 mFlags;
 	LLAssetType::EType mAssetType;	
@@ -105,6 +106,8 @@ class LLTaskInvFVBridge : public LLFolderViewModelItemInventory
 	// LLFolderViewModelItemInventory functionality
 	virtual const std::string& getName() const;
 	virtual const std::string& getDisplayName() const;
+	virtual const std::string& getSearchableName() const;
+
 	virtual PermissionMask getPermissionMask() const { return PERM_NONE; }
 	/*virtual*/ LLFolderType::EType getPreferredType() const { return LLFolderType::FT_NONE; }
 	virtual const LLUUID& getUUID() const { return mUUID; }
@@ -335,9 +338,17 @@ const std::string& LLTaskInvFVBridge::getDisplayName() const
 		}
 	}
 
+	mSearchableName.assign(mDisplayName + getLabelSuffix());
+
 	return mDisplayName;
 }
 
+const std::string& LLTaskInvFVBridge::getSearchableName() const
+{
+	return mSearchableName;
+}
+
+
 // BUG: No creation dates for task inventory
 time_t LLTaskInvFVBridge::getCreationDate() const
 {
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index 194aa7f71b9..b1432401870 100644
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -271,7 +271,7 @@ void LLSidepanelAppearance::onOpenOutfitButtonClicked()
 			if (outfit_folder)
 			{
 				outfit_folder->setOpen(!outfit_folder->isOpen());
-				root->setSelectionFromRoot(outfit_folder,TRUE);
+				root->setSelection(outfit_folder,TRUE);
 				root->scrollToShowSelection();
 			}
 		}
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 50d63911add..654b18614ad 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -623,10 +623,9 @@ void LLFloaterTexturePicker::draw()
 		LLFolderView* folder_view = mInventoryPanel->getRootFolder();
 		if (!folder_view) return;
 
-		LLInventoryFilter* filter = static_cast<LLInventoryFilter*>(folder_view->getFilter());
-		if (!filter) return;
+		LLInventoryFilter* filter = static_cast<LLFolderViewModelInventory*>(folder_view->getFolderViewModel())->getFilter();
 
-		bool is_filter_active = folder_view->getCompletedFilterGeneration() < filter->getCurrentGeneration() &&
+		bool is_filter_active = folder_view->getLastFilterGeneration() < filter->getCurrentGeneration() &&
 				filter->isNotDefault();
 
 		// After inventory panel filter is applied we have to update
@@ -637,8 +636,9 @@ void LLFloaterTexturePicker::draw()
 		if (!is_filter_active && !mSelectedItemPinned)
 		{
 			folder_view->setPinningSelectedItem(mSelectedItemPinned);
-			folder_view->dirtyFilter();
-			folder_view->arrangeFromRoot();
+			folder_view->getViewModelItem()->dirtyFilter();
+			//TODO RN: test
+			//folder_view->arrangeFromRoot();
 
 			mSelectedItemPinned = TRUE;
 		}
-- 
GitLab