/*
* FindBugs - Find Bugs in Java programs
* Copyright (C) 2006, University of Maryland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307, USA
*/
package edu.umd.cs.findbugs.gui2;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import edu.umd.cs.findbugs.AppVersion;
import edu.umd.cs.findbugs.BugCollection;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugPattern;
import edu.umd.cs.findbugs.BugRanker;
import edu.umd.cs.findbugs.Detector;
import edu.umd.cs.findbugs.I18N;
import edu.umd.cs.findbugs.ProjectPackagePrefixes;
import edu.umd.cs.findbugs.cloud.Cloud.Mode;
import edu.umd.cs.findbugs.gui2.BugAspects.SortableValue;
import edu.umd.cs.findbugs.util.ClassName;
/**
* A useful enum for dealing with all the types of filterable and sortable data in BugInstances
* This is the preferred way for getting the information out of a BugInstance and formatting it for display
* It also has the comparators for the different types of data
*
* @author Reuven
*/
public enum Sortables implements Comparator<SortableValue>
{
FIRST_SEEN(edu.umd.cs.findbugs.L10N.getLocalString("sort.first_seen", "First Seen"))
{
@Override
public String getFrom(BugInstance bug)
{
long firstSeen = getFirstSeen(bug);
return Long.toString(firstSeen);
}
/**
* @param bug
* @return
*/
private long getFirstSeen(BugInstance bug) {
BugCollection bugCollection = MainFrame.getInstance().bugCollection;
long firstSeen = bugCollection.getCloud().getFirstSeen(bug);
return firstSeen;
}
@Override
public String formatValue(String value)
{
long when = Long.parseLong(value);
return DateFormat.getDateTimeInstance(DateFormat.SHORT,DateFormat.SHORT).format(when);
}
@Override
public int compare(SortableValue one, SortableValue two)
{
// Numerical (zero is first)
return Long.valueOf(one.value).compareTo(Long.valueOf(two.value));
}
@Override
public boolean isAvailable(MainFrame mainframe) {
BugCollection bugCollection = mainframe.bugCollection;
return bugCollection != null;
}
},
FIRSTVERSION(edu.umd.cs.findbugs.L10N.getLocalString("sort.first_version", "First Version"))
{
@Override
public String getFrom(BugInstance bug)
{
return Long.toString(bug.getFirstVersion());
}
@Override
public String formatValue(String value)
{
int seqNum = Integer.parseInt(value);
BugCollection bugCollection = MainFrame.getInstance().bugCollection;
if (bugCollection == null) return "--";
AppVersion appVersion = bugCollection.getAppVersionFromSequenceNumber(seqNum);
String appendItem = "";
if(appVersion != null)
{
String timestamp = new Timestamp(appVersion.getTimestamp()).toString();
appendItem = appVersion.getReleaseName() + " (" + timestamp.substring(0, timestamp.indexOf(' ')) + ")";
}
if(appendItem == "")
appendItem = "#" +seqNum;
return appendItem;
}
@Override
public int compare(SortableValue one, SortableValue two)
{
// Numerical (zero is first)
return Integer.valueOf(one.value).compareTo(Integer.valueOf(two.value));
}
@Override
public boolean isAvailable(MainFrame mainframe) {
BugCollection bugCollection = mainframe.bugCollection;
if (bugCollection == null) {
return true;
}
long sequenceNumber = bugCollection.getCurrentAppVersion().getSequenceNumber();
return sequenceNumber > 0;
}
},
LASTVERSION(edu.umd.cs.findbugs.L10N.getLocalString("sort.last_version", "Last Version"))
{
@Override
public String getFrom(BugInstance bug)
{
return Long.toString(bug.getLastVersion());
}
@Override
public String formatValue(String value)
{
//System.out.println("Formatting last version value");
if(value.equals("-1"))
return "";
int seqNum = Integer.parseInt(value);
BugCollection bugCollection = MainFrame.getInstance().bugCollection;
if (bugCollection == null) return "--";
AppVersion appVersion = bugCollection.getAppVersionFromSequenceNumber(seqNum);
String appendItem = "";
if(appVersion != null)
{
String timestamp = new Timestamp(appVersion.getTimestamp()).toString();
appendItem = appVersion.getReleaseName() + " (" + timestamp.substring(0, timestamp.indexOf(' ')) + ")";
}
if(appendItem == "")
appendItem = "#" + seqNum;
return appendItem;
}
@Override
public int compare(SortableValue one, SortableValue two)
{
if (one.value.equals(two.value)) return 0;
// Numerical (except that -1 is last)
int first = Integer.valueOf(one.value);
int second = Integer.valueOf(two.value);
if (first == second) return 0;
if (first < 0) return 1;
if (second < 0) return -1;
if (first < second) return -1;
return 1;
}
@Override
public boolean isAvailable(MainFrame mainframe) {
BugCollection bugCollection = mainframe.bugCollection;
if (bugCollection == null)
return true;
return bugCollection.getCurrentAppVersion().getSequenceNumber() > 0;
}
},
PRIORITY(edu.umd.cs.findbugs.L10N.getLocalString("sort.priority", "Priority"))
{
@Override
public String getFrom(BugInstance bug)
{
return String.valueOf(bug.getPriority());
}
@Override
public String formatValue(String value)
{
if (value.equals(String.valueOf(Detector.HIGH_PRIORITY)))
return edu.umd.cs.findbugs.L10N.getLocalString("sort.priority_high", "High");
if (value.equals(String.valueOf(Detector.NORMAL_PRIORITY)))
return edu.umd.cs.findbugs.L10N.getLocalString("sort.priority_normal", "Normal");
if (value.equals(String.valueOf(Detector.LOW_PRIORITY)))
return edu.umd.cs.findbugs.L10N.getLocalString("sort.priority_low", "Low");
if (value.equals(String.valueOf(Detector.EXP_PRIORITY)))
return edu.umd.cs.findbugs.L10N.getLocalString("sort.priority_experimental", "Experimental");
return edu.umd.cs.findbugs.L10N.getLocalString("sort.priority_ignore", "Ignore"); // This probably shouldn't ever happen, but what the hell, let's be complete
}
@Override
public int compare(SortableValue one, SortableValue two)
{
// Numerical
return Integer.valueOf(one.value).compareTo(Integer.valueOf(two.value));
}
},
CLASS(edu.umd.cs.findbugs.L10N.getLocalString("sort.class", "Class"))
{
@Override
public String getFrom(BugInstance bug)
{
return bug.getPrimarySourceLineAnnotation().getClassName();
}
@Override
public int compare(SortableValue one, SortableValue two)
{
// If both have dollar signs and are of the same outer class, compare the numbers after the dollar signs.
try
{
if (one.value.contains("$") && two.value.contains("$")
&& one.value.substring(0, one.value.lastIndexOf("$")).equals(two.value.substring(0, two.value.lastIndexOf("$"))))
return Integer.valueOf(one.value.substring(one.value.lastIndexOf("$"))).compareTo(Integer.valueOf(two.value.substring(two.value.lastIndexOf("$"))));
}
catch (NumberFormatException e) {} // Somebody's playing silly buggers with dollar signs, just do it lexicographically
// Otherwise, lexicographicalify it
return one.value.compareTo(two.value);
}
},
PACKAGE(edu.umd.cs.findbugs.L10N.getLocalString("sort.package", "Package"))
{
@Override
public String getFrom(BugInstance bug)
{
return bug.getPrimarySourceLineAnnotation().getPackageName();
}
@Override
public String formatValue(String value)
{
if (value.equals(""))
return "(Default)";
return value;
}
},
PACKAGE_PREFIX(edu.umd.cs.findbugs.L10N.getLocalString("sort.package_prefix", "Package prefix")) {
@Override
public String getFrom(BugInstance bug)
{
int count = GUISaveState.getInstance().getPackagePrefixSegments();
if (count < 1)
count = 1;
String packageName = bug.getPrimarySourceLineAnnotation().getPackageName();
return ClassName.extractPackagePrefix(packageName, count);
}
@Override
public String formatValue(String value)
{
return value + "...";
}
},
CATEGORY(edu.umd.cs.findbugs.L10N.getLocalString("sort.category", "Category"))
{
@Override
public String getFrom(BugInstance bug)
{
BugPattern bugPattern = bug.getBugPattern();
if (bugPattern == null) {
return "?";
}
return bugPattern.getCategory();
}
@Override
public String formatValue(String value)
{
return I18N.instance().getBugCategoryDescription(value);
}
@Override
public int compare(SortableValue one, SortableValue two)
{
String catOne = one.value;
String catTwo = two.value;
int compare = catOne.compareTo(catTwo);
if (compare == 0)
return 0;
if (catOne.equals("CORRECTNESS"))
return -1;
if (catTwo.equals("CORRECTNESS"))
return 1;
return compare;
}
},
DESIGNATION(edu.umd.cs.findbugs.L10N.getLocalString("sort.designation", "Designation"))
{
@Override
public String getFrom(BugInstance bug)
{
return bug.getUserDesignationKey();
}
/**
* value is the key of the designations.
* @param value
* @return
*/
@Override
public String formatValue(String value)
{
return I18N.instance().getUserDesignation(value);
}
@Override
public String[] getAllSorted()
{//FIXME I think we always want user to see all possible designations, not just the ones he has set in his project, Agreement? -Dan
List<String> sortedDesignations=I18N.instance().getUserDesignationKeys(true);
return sortedDesignations.toArray(new String[sortedDesignations.size()]);
}
},
BUGCODE(edu.umd.cs.findbugs.L10N.getLocalString("sort.bug_kind", "Bug Kind"))
{
@Override
public String getFrom(BugInstance bug)
{
BugPattern bugPattern = bug.getBugPattern();
if (bugPattern == null) return null;
return bugPattern.getAbbrev();
}
@Override
public String formatValue(String value)
{
return I18N.instance().getBugTypeDescription(value);
}
@Override
public int compare(SortableValue one, SortableValue two)
{
return formatValue(one.value).compareTo(formatValue(two.value));
}
},
TYPE(edu.umd.cs.findbugs.L10N.getLocalString("sort.bug_pattern", "Bug Pattern"))
{
@Override
public String getFrom(BugInstance bug)
{
if((bug.getBugPattern()) == null)
return "?";
else return bug.getBugPattern().getType();
}
@Override
public String formatValue(String value)
{
return I18N.instance().getShortMessageWithoutCode(value);
}
},
CONSENSUS(edu.umd.cs.findbugs.L10N.getLocalString("sort.consensus", "Consensus"))
{
@Override
public String getFrom(BugInstance bug)
{
BugCollection bugCollection = MainFrame.getInstance().bugCollection;
return bugCollection.getCloud().getConsensusDesignation(bug)
.name();
}
@Override
public String formatValue(String value)
{
return I18N.instance().getUserDesignation(value);
}
@Override
public boolean isAvailable(MainFrame mf) {
BugCollection bugCollection = mf.bugCollection;
if (bugCollection == null || bugCollection.getCloud() == null)
return false;
return bugCollection.getCloud().getMode() == Mode.COMMUNAL;
}
},
BUG_RANK(edu.umd.cs.findbugs.L10N.getLocalString("sort.bug_bugrank", "Bug Rank"))
{
String [] values;
{ values = new String[40];
for(int i = 0; i < values.length; i++)
values[i] = String.format("%2d", i);
}
@Override
public String getFrom(BugInstance bug)
{
if((bug.getBugPattern()) == null)
return "??";
int rank = BugRanker.findRank(bug);
return values[rank];
}
@Override
public String formatValue(String value)
{
return value;
}
},
PROJECT(edu.umd.cs.findbugs.L10N.getLocalString("sort.bug_project", "Project")) {
@Override
public String getFrom(BugInstance bug) {
ProjectPackagePrefixes p = MainFrame.getInstance().projectPackagePrefixes;
Collection<String> projects = p.getProjects(bug.getPrimaryClass().getClassName());
if (projects.size() == 0)
return "unclassified";
String result = projects.toString();
return result.substring(1, result.length() -1);
}
@Override
public boolean isAvailable(MainFrame mf) {
return mf.projectPackagePrefixes.size() > 0;
}
},
DIVIDER(" ")
{
@Override
public String getFrom(BugInstance bug)
{
throw new UnsupportedOperationException();
}
@Override
public String[] getAll()
{
throw new UnsupportedOperationException();
}
@Override
public String formatValue(String value)
{
throw new UnsupportedOperationException();
}
@Override
public int compare(SortableValue one, SortableValue two)
{
throw new UnsupportedOperationException();
}
};
String prettyName;
Sortables(String prettyName)
{
this.prettyName = prettyName;
}
@Override
public String toString()
{
return prettyName;
}
public abstract String getFrom(BugInstance bug);
public String[] getAll()
{
return getAll(BugSet.getMainBugSet());
}
public String[] getAll(BugSet set)
{
return set.getAll(this);
}
public String formatValue(String value)
{
return value;
}
public int compare(SortableValue one, SortableValue two)
{
// Lexicographical by default
return one.value.compareTo(two.value);
}
public String[] getAllSorted()
{
return getAllSorted(BugSet.getMainBugSet());
}
public String[] getAllSorted(BugSet set)
{
String[] values = getAll(set);
SortableValue[] pairs = new SortableValue[values.length];
for (int i = 0; i < values.length; i++)
pairs[i] = new SortableValue(this, values[i]);
Arrays.sort(pairs, this);
for (int i = 0; i < values.length; i++)
values[i] = pairs[i].value;
return values;
}
private SortableStringComparator comparator = new SortableStringComparator(this);
public SortableStringComparator getComparator() {
return comparator;
}
public Comparator<BugLeafNode> getBugLeafNodeComparator()
{
final Sortables key = this;
return new Comparator<BugLeafNode>()
{
public int compare(BugLeafNode one, BugLeafNode two)
{
return key.compare(new SortableValue(key, key.getFrom(one.getBug())), new SortableValue(key, key.getFrom(two.getBug())));
}
};
}
public boolean isAvailable(MainFrame frame) {
return true;
}
public static Sortables getSortableByPrettyName(String name)
{
for (Sortables s: values())
{
if (s.prettyName.equals(name))
return s;
}
return null;
}
}