return aa;
}
+ /**
+ * Returns an iterable collection of any annotations that match on given
+ * sequence ref, calcId and label (ignoring null values).
+ */
+ @Override
+ public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
+ String calcId, String label)
+ {
+ ArrayList<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
+ for (AlignmentAnnotation ann : getAlignmentAnnotation())
+ {
+ if (ann.getCalcId() != null && ann.getCalcId().equals(calcId)
+ && ann.sequenceRef != null && ann.sequenceRef == seq
+ && ann.label != null && ann.label.equals(label))
+ {
+ aa.add(ann);
+ }
+ }
+ return aa;
+ }
+
@Override
public void moveSelectedSequencesByOne(SequenceGroup sg,
Map<SequenceI, SequenceCollectionI> map, boolean up)
Iterable<AlignmentAnnotation> findAnnotation(String calcId);
+ Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
+ String calcId, String label);
+
/**
* context for this annotated collection
*
return datasetSequence;
}
+ /**
+ * Returns a new array containing this sequence's annotations, or null.
+ */
public AlignmentAnnotation[] getAnnotation()
{
- if (annotation == null)
- {
- return null;
- }
-
- AlignmentAnnotation[] ret = new AlignmentAnnotation[annotation.size()];
- for (int r = 0; r < ret.length; r++)
- {
- ret[r] = annotation.elementAt(r);
- }
+ return annotation == null ? null : annotation
+ .toArray(new AlignmentAnnotation[annotation.size()]);
+ }
- return ret;
+ /**
+ * Returns true if this sequence has the given annotation (by object
+ * identity).
+ */
+ @Override
+ public boolean hasAnnotation(AlignmentAnnotation ann)
+ {
+ return annotation == null ? false : annotation.contains(ann);
}
+ /**
+ * Add the given annotation, if not already added, and set its sequence ref to
+ * be this sequence. Does nothing if this sequence's annotations already
+ * include this annotation (by identical object reference).
+ */
public void addAlignmentAnnotation(AlignmentAnnotation annotation)
{
if (this.annotation == null)
endRes = seqsel.endRes;
cs = seqsel.cs;
if (seqsel.description != null)
+ {
description = new String(seqsel.description);
+ }
hidecols = seqsel.hidecols;
hidereps = seqsel.hidereps;
idColour = seqsel.idColour;
}
}
if (!found)
+ {
continue;
+ }
}
AlignmentAnnotation newannot = new AlignmentAnnotation(
seq.getAnnotation()[a]);
}
/**
+ * Returns a list of annotations that match the specified sequenceRef, calcId
+ * and label, ignoring null values.
+ *
+ * @return list of AlignmentAnnotation objects
+ */
+ @Override
+ public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
+ String calcId, String label)
+ {
+ ArrayList<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
+ for (AlignmentAnnotation ann : getAlignmentAnnotation())
+ {
+ if (ann.getCalcId() != null && ann.getCalcId().equals(calcId)
+ && ann.sequenceRef != null && ann.sequenceRef == seq
+ && ann.label != null && ann.label.equals(label))
+ {
+ aa.add(ann);
+ }
+ }
+ return aa;
+ }
+
+ /**
* Answer true if any annotation matches the calcId passed in (if not null).
*
* @param calcId
public AlignmentAnnotation[] getAnnotation();
+ public boolean hasAnnotation(AlignmentAnnotation ann);
+
public void addAlignmentAnnotation(AlignmentAnnotation annotation);
public void removeAlignmentAnnotation(AlignmentAnnotation annotation);
import jalview.commands.EditCommand;
import jalview.commands.EditCommand.Action;
import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentI;
import jalview.datamodel.Annotation;
import jalview.datamodel.DBRefEntry;
import jalview.datamodel.PDBEntry;
/**
* Check for any annotations on the underlying dataset sequences (for the
- * current selection group) which are not on the alignment annotations for the
- * sequence. If any are found, enable the option to add them to the alignment.
- * The criteria for 'on the alignment' is finding an alignment annotation on
- * the sequence, that matches on calcId and label. A tooltip is also
- * constructed that displays the source (calcId) and type (label) of the
- * annotations that can be added.
+ * current selection group) which are not 'on the alignment'.If any are found,
+ * enable the option to add them to the alignment. The criteria for 'on the
+ * alignment' is finding an alignment annotation on the alignment, matched on
+ * calcId, label and sequenceRef.
+ *
+ * A tooltip is also constructed that displays the source (calcId) and type
+ * (label) of the annotations that can be added.
*
* @param menuItem
* @param forSequences
/*
* For each sequence selected in the alignment, make a list of any
* annotations on the underlying dataset sequence which are not already on
- * the sequence in the alignment.
+ * the alignment.
*
* Build a map of { alignmentSequence, <List of annotations to add> }
*/
+ AlignmentI al = this.ap.av.getAlignment();
final Map<SequenceI, List<AlignmentAnnotation>> candidates = new LinkedHashMap<SequenceI, List<AlignmentAnnotation>>();
for (SequenceI seq : forSequences)
{
for (AlignmentAnnotation dsann : datasetAnnotations)
{
/*
- * If the sequence has no annotation that matches this one, then add
- * this one to the results list.
+ * Find matching annotations on the alignment.
*/
- if (seq.getAlignmentAnnotations(dsann.getCalcId(), dsann.label)
- .isEmpty())
+ final Iterable<AlignmentAnnotation> matchedAlignmentAnnotations = al
+ .findAnnotations(seq, dsann.getCalcId(),
+ dsann.label);
+ if (!matchedAlignmentAnnotations.iterator().hasNext())
{
result.add(dsann);
tipEntries.put(dsann.getCalcId(), dsann.label);
}
copyAnn.restrict(startRes, endRes);
- // add to the sequence (sets copyAnn.datasetSequence)
- seq.addAlignmentAnnotation(copyAnn);
+ /*
+ * Add to the sequence (sets copyAnn.datasetSequence), unless the
+ * original annotation is already on the sequence.
+ */
+ if (!seq.hasAnnotation(ann))
+ {
+ seq.addAlignmentAnnotation(copyAnn);
+ }
// adjust for gaps
copyAnn.adjustForAlignment();
// add to the alignment and set visible
/**
* Tests for addAlignmentAnnotation. Note this method has the side-effect of
- * setting the sequenceRef on the annotation.
+ * setting the sequenceRef on the annotation. Adding the same annotation twice
+ * should be ignored.
*/
@Test
public void testAddAlignmentAnnotation()
AlignmentAnnotation[] anns = seq.getAnnotation();
assertEquals(1, anns.length);
assertSame(annotation, anns[0]);
+
+ // re-adding does nothing
+ seq.addAlignmentAnnotation(annotation);
+ anns = seq.getAnnotation();
+ assertEquals(1, anns.length);
+ assertSame(annotation, anns[0]);
+
+ // an identical but different annotation can be added
+ final AlignmentAnnotation annotation2 = new AlignmentAnnotation("a",
+ "b", 2d);
+ seq.addAlignmentAnnotation(annotation2);
+ anns = seq.getAnnotation();
+ assertEquals(2, anns.length);
+ assertSame(annotation, anns[0]);
+ assertSame(annotation2, anns[1]);
+
}
}
import jalview.datamodel.AlignmentI;
import jalview.datamodel.SequenceI;
import jalview.io.AppletFormatAdapter;
+import jalview.io.FormatAdapter;
import jalview.util.MessageManager;
import java.awt.Component;
@Before
public void setUp() throws IOException
{
- alignment = new jalview.io.FormatAdapter().readFile(TEST_DATA,
+ alignment = new FormatAdapter().readFile(TEST_DATA,
AppletFormatAdapter.PASTE, "FASTA");
AlignFrame af = new AlignFrame(alignment, 700, 500);
parentPanel = new AlignmentPanel(af, af.getViewport());
public void testConfigureReferenceAnnotationsMenu_noReferenceAnnotations()
{
JMenuItem menu = new JMenuItem();
- List<SequenceI> seqs = new ArrayList<SequenceI>();
/*
* Initial state is that sequences have annotations, and have dataset
* sequences, but the dataset sequences have no annotations. Hence nothing
* to add.
*/
- seqs = parentPanel.getAlignment().getSequences();
+ List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
testee.configureReferenceAnnotationsMenu(menu, seqs);
assertFalse(menu.isEnabled());
public void testConfigureReferenceAnnotationsMenu_alreadyAdded()
{
JMenuItem menu = new JMenuItem();
- List<SequenceI> seqs = new ArrayList<SequenceI>();
+ List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
+
+ // make up new annotations and add to dataset sequences, sequences and
+ // alignment
+ attachReferenceAnnotations(seqs, true, true);
- seqs = parentPanel.getAlignment().getSequences();
- // copy annotation from sequence to dataset
- seqs.get(1).getDatasetSequence()
- .addAlignmentAnnotation(seqs.get(1).getAnnotation()[0]);
testee.configureReferenceAnnotationsMenu(menu, seqs);
assertFalse(menu.isEnabled());
}
{
JMenuItem menu = new JMenuItem();
List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
+
// make up new annotations and add to dataset sequences
+ attachReferenceAnnotations(seqs, false, false);
+
+ testee.configureReferenceAnnotationsMenu(menu, seqs);
+ assertTrue(menu.isEnabled());
+ String expected = "<html><table width=350 border=0><tr><td>Add annotations for<br/>JMOL/secondary structure<br/>PBD/Temp</td></tr></table></html>";
+ assertEquals(expected, menu.getToolTipText());
+ }
+
+ /**
+ * Test building the 'add reference annotations' menu for the case where
+ * several reference annotations are on the dataset and the sequences but not
+ * on the alignment. The menu item should be enabled, and acquire a tooltip
+ * which lists the annotation sources (calcIds) and type (labels).
+ */
+ @Test
+ public void testConfigureReferenceAnnotationsMenu_notOnAlignment()
+ {
+ JMenuItem menu = new JMenuItem();
+ List<SequenceI> seqs = parentPanel.getAlignment().getSequences();
+
+ // make up new annotations and add to dataset sequences and sequences
+ attachReferenceAnnotations(seqs, true, false);
+
+ testee.configureReferenceAnnotationsMenu(menu, seqs);
+ assertTrue(menu.isEnabled());
+ String expected = "<html><table width=350 border=0><tr><td>Add annotations for<br/>JMOL/secondary structure<br/>PBD/Temp</td></tr></table></html>";
+ assertEquals(expected, menu.getToolTipText());
+ }
+ /**
+ * Generate annotations and add to dataset sequences and (optionally)
+ * sequences and/or alignment
+ *
+ * @param seqs
+ * @param addToSequence
+ * @param addToAlignment
+ */
+ private void attachReferenceAnnotations(List<SequenceI> seqs,
+ boolean addToSequence, boolean addToAlignment)
+ {
// PDB.secondary structure on Sequence0
AlignmentAnnotation annotation = new AlignmentAnnotation(
"secondary structure", "", 0);
annotation.setCalcId("PBD");
seqs.get(0).getDatasetSequence().addAlignmentAnnotation(annotation);
+ if (addToSequence)
+ {
+ seqs.get(0).addAlignmentAnnotation(annotation);
+ }
+ if (addToAlignment)
+ {
+ this.alignment.addAnnotation(annotation);
+ }
// PDB.Temp on Sequence1
annotation = new AlignmentAnnotation("Temp", "", 0);
annotation.setCalcId("PBD");
seqs.get(1).getDatasetSequence().addAlignmentAnnotation(annotation);
+ if (addToSequence)
+ {
+ seqs.get(1).addAlignmentAnnotation(annotation);
+ }
+ if (addToAlignment)
+ {
+ this.alignment.addAnnotation(annotation);
+ }
// JMOL.secondary structure on Sequence0
annotation = new AlignmentAnnotation("secondary structure", "", 0);
annotation.setCalcId("JMOL");
seqs.get(0).getDatasetSequence().addAlignmentAnnotation(annotation);
+ if (addToSequence)
+ {
+ seqs.get(0).addAlignmentAnnotation(annotation);
+ }
+ if (addToAlignment)
+ {
+ this.alignment.addAnnotation(annotation);
+ }
+ }
- testee.configureReferenceAnnotationsMenu(menu, seqs);
- assertTrue(menu.isEnabled());
- String expected = "<html><table width=350 border=0><tr><td>Add annotations for<br/>JMOL/secondary structure<br/>PBD/Temp</td></tr></table></html>";
- assertEquals(expected, menu.getToolTipText());
+ /**
+ * Test building the 'add reference annotations' menu for the case where there
+ * are two alignment views:
+ * <ul>
+ * <li>in one view, reference annotations have been added (are on the
+ * datasets, sequences and alignment)</li>
+ * <li>in the current view, reference annotations are on the dataset and
+ * sequence, but not the alignment</li>
+ * </ul>
+ * The menu item should be enabled, and acquire a tooltip which lists the
+ * annotation sources (calcIds) and type (labels).
+ */
+ @Test
+ public void testConfigureReferenceAnnotationsMenu_twoViews()
+ {
}
/**