package org.limewire.ui.swing.search.resultpanel;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import org.jdesktop.swingx.decorator.SortKey;
import org.jdesktop.swingx.decorator.SortOrder;
import org.limewire.friend.api.Friend;
import org.limewire.ui.swing.search.model.BasicDownloadState;
import org.limewire.ui.swing.search.model.VisualSearchResult;
import org.limewire.ui.swing.settings.TablesHandler;
import org.limewire.ui.swing.table.AbstractColumnStateFormat;
import org.limewire.ui.swing.table.ColumnStateInfo;
import org.limewire.ui.swing.table.QualityComparator;
import org.limewire.ui.swing.util.EventListTableSortFormat;
import org.limewire.util.Objects;
/**
* This class is the base class for each of the TableFormat classes
* that describe the various table views of search results.
*/
public abstract class ResultsTableFormat<T> extends AbstractColumnStateFormat<T>
implements EventListTableSortFormat {
protected VisualSearchResult vsr;
private final int nameColumn;
private final int fromColumn;
private final int spamColumn;
private final String sortID;
/**
* Constructs a ResultsTableFormat with the specified array of column
* descriptors.
*/
public ResultsTableFormat(ColumnStateInfo... columnInfo) {
this("", -1, -1, -1, columnInfo);
}
/**
* Constructs a ResultsTableFormat with the specified sort identifier,
* Name/From/Spam column indices, and array of column descriptors.
*/
public ResultsTableFormat(String sortID, int nameColumn, int fromColumn,
int spamColumn, ColumnStateInfo... columnInfo) {
super(columnInfo);
this.sortID = sortID;
this.nameColumn = nameColumn;
this.fromColumn = fromColumn;
this.spamColumn = spamColumn;
}
@Override
public Class getColumnClass(int index) {
return String.class;
}
public VisualSearchResult setColumnValue(
VisualSearchResult vsr, Object value, int index) {
// do nothing with the new value
return vsr;
}
public boolean isEditable(VisualSearchResult vsr, int column) {
return column == fromColumn;
}
public int getNameColumn() {
return nameColumn;
}
@Override
public List<SortKey> getPreSortColumns() {
return Arrays.asList(new SortKey(SortOrder.ASCENDING, spamColumn));
}
@Override
public boolean getSortOrder() {// always descending for search results
return false;
}
@Override
public String getSortOrderID() {
return sortID;
}
@Override
public int getSortedColumn() { // always from column for search results
return fromColumn;
}
@Override
public List<SortKey> getDefaultSortKeys() {
return Arrays.asList(
new SortKey(((TablesHandler.getSortedOrder(getSortOrderID(), getSortOrder()).getValue() == true) ?
SortOrder.ASCENDING : SortOrder.DESCENDING ),
TablesHandler.getSortedColumn(getSortOrderID(), getSortedColumn()).getValue()));
}
/**
* If the FromColumn is sorted, use a custom column sorter
* otherwise it is assumed the column returns a value that
* implements the Comparable interface.
*/
@Override
public Comparator getColumnComparator(int index) {
if(index == fromColumn)
return getFromComparator();
else if(index == nameColumn)
return getNameComparator();
else if(index == spamColumn)
return getSpamComparator();
else
return getLimeComparator();
}
/**
* Returns a comparator for the From column.
*/
public Comparator getFromComparator() {
return new FromComparator();
}
/**
* Returns a comparator for the Name column.
*/
public Comparator getNameComparator() {
return new NameComparator(false);
}
/**
* Returns a comparator for the Quality column.
*/
public Comparator getQualityComparator() {
return new QualityComparator();
}
/**
* Returns a comparator for the Spam column.
*/
public Comparator getSpamComparator() {
return new IsSpamComparator();
}
/**
* Compares the number of files being shared.
*/
public static class FromComparator implements Comparator<VisualSearchResult> {
@Override
public int compare(VisualSearchResult o1, VisualSearchResult o2) {
int size1 = o1.getSources().size();
int size2 = o2.getSources().size();
if(size1 == size2) {
// Special case: if each search result comes from one source,
// use alphabetical order to break the tie.
if(size1 == 1) {
// Get friend names if available.
Collection<Friend> friends1 = o1.getFriends();
String name1 = null;
if(friends1.size() == 1)
name1 = friends1.iterator().next().getRenderName();
Collection<Friend> friends2 = o2.getFriends();
String name2 = null;
if(friends2.size() == 1)
name2 = friends2.iterator().next().getRenderName();
// Compare friend names. Handle null values to keep P2P
// results together.
return Objects.compareToNullIgnoreCase(name1, name2, false);
}
return 0;
} else if(size1 > size2) {
return 1;
} else {
return -1;
}
}
}
/**
* Compares the name column. This is essentially a string compare but
* VSR are returned in this column to also display an icon so we need
* a custom comparator.
*/
public static class NameComparator implements Comparator<VisualSearchResult> {
private final boolean useAudioArtist;
public NameComparator(boolean useAudioArtist) {
this.useAudioArtist = useAudioArtist;
}
@Override
public int compare(VisualSearchResult o1, VisualSearchResult o2) {
String name1 = getName(o1);
String name2 = getName(o2);
return name1.compareToIgnoreCase(name2);
}
private String getName(VisualSearchResult result) {
return result.getNameProperty(useAudioArtist);
}
}
/**
* Compares the Spam Column. This column is never displayed to the user;
* it's used to push spam results and previously downloaded files to the
* bottom in table view.
*/
public static class IsSpamComparator implements Comparator<VisualSearchResult> {
@Override
public int compare(VisualSearchResult o1, VisualSearchResult o2) {
boolean spam1 = o1.isSpam();
boolean spam2 = o2.isSpam();
if(!spam1 && spam2)
return -1;
if(spam1 && !spam2)
return 1;
boolean downloaded1 = o1.getDownloadState() == BasicDownloadState.LIBRARY;
boolean downloaded2 = o2.getDownloadState() == BasicDownloadState.LIBRARY;
if(!downloaded1 && downloaded2)
return -1;
if(downloaded1 && !downloaded2)
return 1;
return 0;
}
}
}