package com.limegroup.gnutella.gui.search;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.limegroup.gnutella.URN;
import com.limegroup.gnutella.gui.tables.DataLine;
import com.limegroup.gnutella.search.QueryHandler;
import com.limegroup.gnutella.settings.SearchSettings;
/**
* Filters out certain rows from the data model.
*
* @author Sumeet Thadani, Sam Berlin
*/
public final class TableRowFilter extends ResultPanelModel {
/**
* The filter to use in this row filter.
*/
private final TableLineFilter FILTER;
/**
* The Junk Filter
*/
private TableLineFilter junkFilter = AllowFilter.instance();
/**
* A list of all filtered results.
*/
private final List HIDDEN;
/**
* The number of sources in the hidden list.
*/
private int _numSources;
/**
* Constructs a TableRowFilter with the specified TableLineFilter.
*/
public TableRowFilter(TableLineFilter f) {
super();
if(f == null)
throw new NullPointerException("null filter");
FILTER = f;
HIDDEN = new ArrayList(QueryHandler.ULTRAPEER_RESULTS);
_numSources = 0;
}
/**
* Returns true if Table is sorted which means either
* it is really sorted OR 'move junk to bottom' is
* selected which is also some kind of sorting!
*/
public boolean isSorted() {
return super.isSorted() || SearchSettings.moveJunkToBottom();
}
/**
* Gets the amount of filtered sources.
*/
public int getFilteredSources() {
return super.getTotalSources();
}
/**
* Gets the total amount of sources.
*/
public int getTotalSources() {
return getFilteredSources() + _numSources;
}
public int addNewResult(TableLine tl, SearchResult sr) {
// If we're hiding junk check if TableLine's rating turns into
// junk when a new SearchResult is added...
if (SearchSettings.hideJunk()) {
int added = super.addNewResult(tl, sr);
// If so, remove the row from the Table...!
if (!junkFilter.allow(tl)) {
int row = getRow(tl);
remove(row);
METADATA.remove(tl);
_numSources += tl.getLocationCount();
return 0;
} else {
return added;
}
// If we're moving junk results to the bottom check if the
// TableLine rating changes from NOT junk to junk then remove
// it from the current position in the Table and move it to
// the bottom
} else if (SearchSettings.moveJunkToBottom()) {
boolean wasNotJunk = junkFilter.allow(tl);
int added = super.addNewResult(tl, sr);
if (wasNotJunk && !junkFilter.allow(tl)) {
int row = getRow(tl);
remove(row);
return super.add(tl, getSortedPosition(tl)); // re-add
} else {
return added;
}
// Standard add...
} else {
return super.addNewResult(tl, sr);
}
}
/**
* Determines whether or not this line should be added.
*/
public int add(DataLine line, int row) {
TableLine tl = (TableLine)line;
boolean isNotJunk = junkFilter.allow(tl);
boolean allow = allow(tl);
if(isNotJunk || !SearchSettings.hideJunk()) {
if (allow) {
return super.add(line, row);
} else {
HIDDEN.add(tl);
if(_useMetadata) {
METADATA.addNew(tl);
}
_numSources += tl.getLocationCount();
}
} else {
_numSources += tl.getLocationCount();
}
return -1;
}
/**
* Intercepts to clear the hidden map.
*/
protected void simpleClear() {
_numSources = 0;
HIDDEN.clear();
super.simpleClear();
}
/**
* Notification that the filters have changed.
*/
void filtersChanged() {
rebuild();
fireTableDataChanged();
}
/**
* Sets the Junk Filter. Pass null as argument to disable the filter
*/
void setJunkFilter(TableLineFilter junkFilter) {
if (junkFilter != null) {
this.junkFilter = junkFilter;
} else {
this.junkFilter = AllowFilter.instance();
}
}
/**
* Determines whether or not the specified line is allowed by the filter.
*/
private boolean allow(TableLine line) {
return FILTER.allow(line);
}
/**
* Rebuilds the internal map to denote a new filter.
*/
private void rebuild(){
List existing = new ArrayList(_list);
List hidden = new ArrayList(HIDDEN);
simpleClear();
setUseMetadata(false);
// For stuff in _list, we can just re-add the DataLines as-is.
if(isSorted()) {
for(int i = 0; i < existing.size(); i++) {
addSorted((DataLine)existing.get(i));
}
} else {
for(int i = 0; i < existing.size(); i++) {
add((DataLine)existing.get(i));
}
}
// Merge the hidden TableLines
Map mergeMap = new HashMap();
for(int i = 0; i < hidden.size(); i++) {
TableLine tl = (TableLine)hidden.get(i);
SearchResult sr = (SearchResult)tl.getInitializeObject();
URN urn = sr.getRemoteFileDesc().getSHA1Urn();
TableLine tableLine = (TableLine)mergeMap.get(urn);
if (tableLine == null) {
mergeMap.put(urn, tl); // re-use TableLines
} else {
tableLine.addNewResult(sr, METADATA);
}
}
// And add them
if(isSorted()) {
for(Iterator it = mergeMap.values().iterator(); it.hasNext(); ) {
addSorted((DataLine)it.next());
}
} else {
for(Iterator it = mergeMap.values().iterator(); it.hasNext(); ) {
add((DataLine)it.next());
}
}
setUseMetadata(true);
}
}