/*
* Copyright (c) 2011, 2012 Roberto Tyley
*
* This file is part of 'Agit' - an Android Git client.
*
* Agit is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Agit is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/ .
*/
package com.madgag.agit.filepath;
import static com.google.common.collect.Lists.newArrayList;
import static com.madgag.agit.R.layout.file_list_item;
import static com.madgag.android.listviews.ReflectiveHolderFactory.reflectiveFactoryFor;
import static com.madgag.android.listviews.ViewInflator.viewInflatorFor;
import static java.lang.System.currentTimeMillis;
import android.content.Context;
import android.os.Debug;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Filter;
import android.widget.Filterable;
import com.google.common.base.Stopwatch;
import com.madgag.agit.FileViewHolder;
import com.madgag.android.listviews.ViewHoldingListAdapter;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
public class FilterableFileListAdapter extends ViewHoldingListAdapter<FilePath> implements Filterable {
private static final String TAG = "FilterableFileListAdapter";
/**
* Lock used to modify the content of mObjects. Any write operation
* performed on the array should be synchronized on this lock. This lock is also
* used by the filter (see {@link #getFilter()} to make a synchronized copy of
* the original array of data.
*/
private final Object mLock = new Object();
// A copy of the original mObjects array, initialized from and then used instead as soon as
// the filter ArrayFilter is used. mObjects will then only contain the filtered values.
private List<FilePath> originalValues;
private final List<FilePath> items;
private final AtomicReference<FilePathMatcher> visibleFilePathMatcher;
private CachingFilePathListMatcher cachingFilePathListMatcher;
private Filter filter;
public FilterableFileListAdapter(final List<FilePath> items, Context context, AtomicReference<FilePathMatcher>
visibleFilePathMatcher) {
super(items, viewInflatorFor(context, file_list_item), reflectiveFactoryFor(FileViewHolder.class,
visibleFilePathMatcher));
this.items = items;
this.visibleFilePathMatcher = visibleFilePathMatcher;
cachingFilePathListMatcher = new CachingFilePathListMatcher(this.items);
}
public Filter getFilter() {
if (filter == null) {
filter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
if (originalValues == null) {
synchronized (mLock) {
originalValues = newArrayList(items);
}
}
List<FilePath> originalValuesCopy;
synchronized (mLock) {
originalValuesCopy = newArrayList(originalValues);
}
FilterResults results = new FilterResults();
if (TextUtils.isEmpty(constraint)) {
results.values = originalValuesCopy;
results.count = originalValuesCopy.size();
} else {
// String tn = "FLA." + originalValuesCopy.size() + "." + constraint + "." + currentTimeMillis();
// Debug.startMethodTracing(tn, 64 * 1024 * 1024);
Stopwatch stopwatch = new Stopwatch().start();
List<FilePath> matchingFiles = cachingFilePathListMatcher.get(constraint.toString());
Log.d(TAG, "Filtered with '" + constraint + "' to " + matchingFiles.size() + " files " +
stopwatch.stop());
// Debug.stopMethodTracing();
results.values = matchingFiles;
results.count = matchingFiles.size();
}
return results;
}
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
visibleFilePathMatcher.set(TextUtils.isEmpty(constraint) ? null : new FilePathMatcher(constraint
.toString()));
setList((List<FilePath>) results.values);
}
};
}
return filter;
}
}