1 package jalview.analysis;
3 import jalview.datamodel.AlignmentAnnotation;
4 import jalview.datamodel.AlignmentI;
5 import jalview.datamodel.SequenceI;
7 import java.util.Arrays;
8 import java.util.Comparator;
11 * A helper class to sort all annotations associated with an alignment in
17 public class AnnotationSorter
22 SEQUENCE_AND_TYPE, TYPE_AND_SEQUENCE
25 private final AlignmentI alignment;
27 public AnnotationSorter(AlignmentI alignmentI)
29 this.alignment = alignmentI;
33 * Default comparator sorts as follows by annotation type within sequence
36 * <li>annotations with a reference to a sequence in the alignment are sorted
37 * on sequence ordering</li>
38 * <li>other annotations go 'at the end', with their mutual order unchanged</li>
39 * <li>within the same sequence ref, sort by label (non-case-sensitive)</li>
42 private final Comparator<? super AlignmentAnnotation> bySequenceAndType = new Comparator<AlignmentAnnotation>()
45 public int compare(AlignmentAnnotation o1, AlignmentAnnotation o2)
47 if (o1 == null && o2 == null)
61 * Ignore label (keep existing ordering) for
62 * Conservation/Quality/Consensus etc
64 if (o1.sequenceRef == null && o2.sequenceRef == null)
68 int sequenceOrder = compareSequences(o1, o2);
69 return sequenceOrder == 0 ? compareLabels(o1, o2) : sequenceOrder;
74 * This comparator sorts as follows by sequence order within annotation type
76 * <li>annotations with a reference to a sequence in the alignment are sorted
77 * on label (non-case-sensitive)</li>
78 * <li>other annotations go 'at the end', with their mutual order unchanged</li>
79 * <li>within the same label, sort by order of the related sequences</li>
82 private final Comparator<? super AlignmentAnnotation> byTypeAndSequence = new Comparator<AlignmentAnnotation>()
85 public int compare(AlignmentAnnotation o1, AlignmentAnnotation o2)
87 if (o1 == null && o2 == null)
101 * Ignore label (keep existing ordering) for
102 * Conservation/Quality/Consensus etc
104 if (o1.sequenceRef == null && o2.sequenceRef == null)
110 * Sort non-sequence-related after sequence-related.
112 if (o1.sequenceRef == null)
116 if (o2.sequenceRef == null)
120 int labelOrder = compareLabels(o1, o2);
121 return labelOrder == 0 ? compareSequences(o1, o2) : labelOrder;
125 private final Comparator<? super AlignmentAnnotation> DEFAULT_COMPARATOR = bySequenceAndType;
128 * Sort by the specified order.
130 * @param alignmentAnnotations
133 public void sort(AlignmentAnnotation[] alignmentAnnotations,
136 Comparator<? super AlignmentAnnotation> comparator = getComparator(order);
138 if (alignmentAnnotations != null)
140 synchronized (alignmentAnnotations)
142 Arrays.sort(alignmentAnnotations, comparator);
148 * Get the comparator for the specified sort order.
153 private Comparator<? super AlignmentAnnotation> getComparator(
158 return DEFAULT_COMPARATOR;
162 case SEQUENCE_AND_TYPE:
163 return this.bySequenceAndType;
164 case TYPE_AND_SEQUENCE:
165 return this.byTypeAndSequence;
167 throw new UnsupportedOperationException(order.toString());
172 * Non-case-sensitive comparison of annotation labels. Returns zero if either
179 private int compareLabels(AlignmentAnnotation o1, AlignmentAnnotation o2)
181 if (o1 == null || o2 == null)
185 String label1 = o1.label;
186 String label2 = o2.label;
187 if (label1 == null && label2 == null)
199 return label1.toUpperCase().compareTo(label2.toUpperCase());
203 * Comparison based on position of associated sequence (if any) in the
204 * alignment. Returns zero if either argument is null.
210 private int compareSequences(AlignmentAnnotation o1,
211 AlignmentAnnotation o2)
213 SequenceI seq1 = o1.sequenceRef;
214 SequenceI seq2 = o2.sequenceRef;
215 if (seq1 == null && seq2 == null)
227 // get sequence index - but note -1 means 'at end' so needs special handling
228 int index1 = AlignmentUtils.getSequenceIndex(alignment, seq1);
229 int index2 = AlignmentUtils.getSequenceIndex(alignment, seq2);
230 if (index1 == index2)
242 return Integer.compare(index1, index2);