⛏️ index : haiku.git

#include "FilteredQuery.h"

#include <Debug.h>
#include <Entry.h>
#include <String.h>
#include <Volume.h>

// Helper function to copy a query.
// Used to avoid code duplication in
// TFilteredQuery(const BQuery &) and TFilteredQuery(const TFilteredQuery &)
static void
CopyQuery(const BQuery &query, BQuery *dest)
{
	ASSERT(dest);
	
	BQuery &nonConst = const_cast<BQuery &>(query);
	
	// BQuery doesn't have a copy constructor,
	// so we have to do the work ourselves... 
	// Copy the predicate
	BString buffer;
	nonConst.GetPredicate(&buffer);
	dest->SetPredicate(buffer.String());
	
	// Copy the targetted volume
	BVolume volume(nonConst.TargetDevice());
	dest->SetVolume(&volume);
}


TFilteredQuery::TFilteredQuery()
{
}


TFilteredQuery::TFilteredQuery(const BQuery &query)
	:
	BQuery()
{
	CopyQuery(query, this);	
}


TFilteredQuery::TFilteredQuery(const TFilteredQuery &query)
	:
	BQuery()
{
	CopyQuery(query, this);
	
	// copy filters
	fFilters = query.fFilters;
}


TFilteredQuery::~TFilteredQuery()
{
	Clear();
}


bool
TFilteredQuery::AddFilter(filter_function filter, void *arg)
{
	filter_pair *filterPair = new filter_pair(filter, arg);
	
	return fFilters.AddItem(filterPair);
}


void
TFilteredQuery::RemoveFilter(filter_function function)
{
	int32 count = fFilters.CountItems();
	for (int32 i = 0; i < count; i++) {
		filter_pair *pair = fFilters.ItemAt(i);
		if (pair->filter == function) {
			delete fFilters.RemoveItemAt(i);
			break;
		}
	}
}


status_t
TFilteredQuery::GetNextRef(entry_ref *ref)
{
	entry_ref tmpRef;
	status_t result;
	
	int32 filterCount = fFilters.CountItems();		
	while ((result = BQuery::GetNextRef(&tmpRef)) == B_OK) {
		bool accepted = true;
		// We have a match, so let the entry_ref go through the filters
		// and see if it passes all the requirements
		for (int32 i = 0; i < filterCount; i++) {
			filter_pair *pair = fFilters.ItemAt(i);
			filter_function filter = pair->filter;
			accepted = (*filter)(&tmpRef, pair->args);
			if (!accepted)
				break;
		}
				
		if (accepted) {
			// Ok, this entry_ref passed all tests
			*ref = tmpRef;
			break;
		}
	}
		 
	return result;
}


status_t
TFilteredQuery::GetNextEntry(BEntry *entry, bool traverse)
{
	// This code is almost a full copy/paste from Haiku's
	// BQuery::GetNextEntry(BEntry *entry, bool traverse)
	
	entry_ref ref;
	status_t error = GetNextRef(&ref);
	if (error == B_OK)
		error = entry->SetTo(&ref, traverse);
	
	return error;
}


int32
TFilteredQuery::GetNextDirents(dirent *buf, size_t length, int32 count)
{
	// TODO: Implement ?
	return 0;
}


status_t
TFilteredQuery::Clear()
{
	int32 filtersCount = fFilters.CountItems();
	for (int32 i = 0; i < filtersCount; i++)
		delete fFilters.RemoveItemAt(i);
	
	return BQuery::Clear();
}