package jalview.datamodel;
import jalview.analysis.AlignmentUtils;
+import jalview.datamodel.AlignedCodonFrame.SequenceToSequenceMapping;
import jalview.io.FastaFile;
import jalview.util.Comparison;
+import jalview.util.LinkedIdentityHashSet;
import jalview.util.MessageManager;
import java.util.ArrayList;
protected char gapCharacter = '-';
- protected int type = NUCLEOTIDE;
-
- public static final int PROTEIN = 0;
-
- public static final int NUCLEOTIDE = 1;
+ private boolean nucleotide = true;
public boolean hasRNAStructure = false;
HiddenSequences hiddenSequences;
+ HiddenColumns hiddenCols;
+
public Hashtable alignmentProperties;
private List<AlignedCodonFrame> codonFrameList;
{
groups = Collections.synchronizedList(new ArrayList<SequenceGroup>());
hiddenSequences = new HiddenSequences(this);
- codonFrameList = new ArrayList<AlignedCodonFrame>();
+ hiddenCols = new HiddenColumns();
+ codonFrameList = new ArrayList<>();
- if (Comparison.isNucleotide(seqs))
- {
- type = NUCLEOTIDE;
- }
- else
- {
- type = PROTEIN;
- }
+ nucleotide = Comparison.isNucleotide(seqs);
sequences = Collections.synchronizedList(new ArrayList<SequenceI>());
public Alignment(SeqCigar[] alseqs)
{
SequenceI[] seqs = SeqCigar.createAlignmentSequences(alseqs,
- gapCharacter, new ColumnSelection(), null);
+ gapCharacter, new HiddenColumns(), null);
initAlignment(seqs);
}
return AlignmentUtils.getSequencesByName(this);
}
- /**
- * DOCUMENT ME!
- *
- * @param i
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
+
@Override
public SequenceI getSequenceAt(int i)
{
return null;
}
+ @Override
+ public SequenceI getSequenceAtAbsoluteIndex(int i)
+ {
+ SequenceI seq = null;
+ if (getHiddenSequences().getSize() > 0)
+ {
+ seq = getHiddenSequences().getHiddenSequence(i);
+ if (seq == null)
+ {
+ // didn't find the sequence in the hidden sequences, get it from the
+ // alignment
+ int index = getHiddenSequences().findIndexWithoutHiddenSeqs(i);
+ seq = getSequenceAt(index);
+ }
+ }
+ else
+ {
+ seq = getSequenceAt(i);
+ }
+ return seq;
+ }
+
/**
- * Adds a sequence to the alignment. Recalculates maxLength and size.
+ * Adds a sequence to the alignment. Recalculates maxLength and size. Note
+ * this currently does not recalculate whether or not the alignment is
+ * nucleotide, so mixed alignments may have undefined behaviour.
*
* @param snew
*/
{
if (dataset != null)
{
+
// maintain dataset integrity
- if (snew.getDatasetSequence() != null)
- {
- getDataset().addSequence(snew.getDatasetSequence());
- }
- else
+ SequenceI dsseq = snew.getDatasetSequence();
+ if (dsseq == null)
{
// derive new sequence
SequenceI adding = snew.deriveSequence();
- getDataset().addSequence(adding.getDatasetSequence());
snew = adding;
+ dsseq = snew.getDatasetSequence();
+ }
+ if (getDataset().findIndex(dsseq) == -1)
+ {
+ getDataset().addSequence(dsseq);
}
+
}
if (sequences == null)
{
}
}
- /**
- * Adds a sequence to the alignment. Recalculates maxLength and size.
- *
- * @param snew
- */
@Override
- public void setSequenceAt(int i, SequenceI snew)
+ public SequenceI replaceSequenceAt(int i, SequenceI snew)
{
synchronized (sequences)
{
- deleteSequence(i);
- sequences.set(i, snew);
+ if (sequences.size() > i)
+ {
+ return sequences.set(i, snew);
+
+ }
+ else
+ {
+ sequences.add(snew);
+ hiddenSequences.adjustHeightSequenceAdded();
+ }
+ return null;
}
}
}
@Override
- public void finalize()
+ public void finalize() throws Throwable
{
if (getDataset() != null)
{
getDataset().removeAlignmentRef();
}
+ nullReferences();
+ super.finalize();
+ }
+
+ /**
+ * Defensively nulls out references in case this object is not garbage
+ * collected
+ */
+ void nullReferences()
+ {
dataset = null;
sequences = null;
groups = null;
}
/**
- * decrement the alignmentRefs counter by one and call finalize if it goes to
- * zero.
+ * decrement the alignmentRefs counter by one and null references if it goes
+ * to zero.
+ *
+ * @throws Throwable
*/
- private void removeAlignmentRef()
+ private void removeAlignmentRef() throws Throwable
{
if (--alignmentRefs == 0)
{
- finalize();
+ nullReferences();
}
}
- /**
- * DOCUMENT ME!
- *
- * @param s
- * DOCUMENT ME!
- */
@Override
public void deleteSequence(SequenceI s)
{
- deleteSequence(findIndex(s));
+ synchronized (sequences)
+ {
+ deleteSequence(findIndex(s));
+ }
}
- /**
- * DOCUMENT ME!
- *
- * @param i
- * DOCUMENT ME!
- */
@Override
public void deleteSequence(int i)
{
- if (i > -1 && i < getHeight())
+ synchronized (sequences)
{
- synchronized (sequences)
+ if (i > -1 && i < getHeight())
{
sequences.remove(i);
hiddenSequences.adjustHeightSequenceDeleted(i);
}
}
+ @Override
+ public void deleteHiddenSequence(int i)
+ {
+ synchronized (sequences)
+ {
+ if (i > -1 && i < getHeight())
+ {
+ sequences.remove(i);
+ }
+ }
+ }
+
/*
* (non-Javadoc)
*
* @see jalview.datamodel.AlignmentI#findGroup(jalview.datamodel.SequenceI)
*/
@Override
- public SequenceGroup findGroup(SequenceI s)
+ public SequenceGroup findGroup(SequenceI seq, int position)
{
synchronized (groups)
{
- for (int i = 0; i < this.groups.size(); i++)
+ for (SequenceGroup sg : groups)
{
- SequenceGroup sg = groups.get(i);
-
- if (sg.getSequences(null).contains(s))
+ if (sg.getSequences(null).contains(seq))
{
- return sg;
+ if (position >= sg.getStartRes() && position <= sg.getEndRes())
+ {
+ return sg;
+ }
}
}
}
@Override
public SequenceGroup[] findAllGroups(SequenceI s)
{
- ArrayList<SequenceGroup> temp = new ArrayList<SequenceGroup>();
+ ArrayList<SequenceGroup> temp = new ArrayList<>();
synchronized (groups)
{
return;
}
}
- sg.setContext(this);
+ sg.setContext(this, true);
groups.add(sg);
}
}
}
for (SequenceGroup sg : groups)
{
- sg.setContext(null);
+ sg.setContext(null, false);
}
groups.clear();
}
{
removeAnnotationForGroup(g);
groups.remove(g);
- g.setContext(null);
+ g.setContext(null, false);
}
}
}
* jalview.datamodel.AlignmentI#findIndex(jalview.datamodel.SearchResults)
*/
@Override
- public int findIndex(SearchResults results)
+ public int findIndex(SearchResultsI results)
{
int i = 0;
return -1;
}
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
+
@Override
public int getHeight()
{
return sequences.size();
}
- /**
- * DOCUMENT ME!
- *
- * @return DOCUMENT ME!
- */
+ @Override
+ public int getAbsoluteHeight()
+ {
+ return sequences.size() + getHiddenSequences().getSize();
+ }
+
@Override
public int getWidth()
{
return true;
}
+ @Override
+ public boolean isHidden(int alignmentIndex)
+ {
+ return (getHiddenSequences().getHiddenSequence(alignmentIndex) != null);
+ }
+
/**
* Delete all annotations, including auto-calculated if the flag is set true.
* Returns true if at least one annotation was deleted, else false.
}
@Override
- public void setNucleotide(boolean b)
- {
- if (b)
- {
- type = NUCLEOTIDE;
- }
- else
- {
- type = PROTEIN;
- }
- }
-
- @Override
public boolean isNucleotide()
{
- if (type == NUCLEOTIDE)
- {
- return true;
- }
- else
- {
- return false;
- }
+ return nucleotide;
}
@Override
}
else if (dataset == null && data != null)
{
+ if (data == this)
+ {
+ throw new IllegalArgumentException("Circular dataset reference");
+ }
if (!(data instanceof Alignment))
{
throw new Error(
}
/**
+ * add dataset sequences to seq for currentSeq and any sequences it references
+ */
+ private void resolveAndAddDatasetSeq(SequenceI currentSeq,
+ Set<SequenceI> seqs, boolean createDatasetSequence)
+ {
+ SequenceI alignedSeq = currentSeq;
+ if (currentSeq.getDatasetSequence() != null)
+ {
+ currentSeq = currentSeq.getDatasetSequence();
+ }
+ else
+ {
+ if (createDatasetSequence)
+ {
+ currentSeq = currentSeq.createDatasetSequence();
+ }
+ }
+ if (seqs.contains(currentSeq))
+ {
+ return;
+ }
+ List<SequenceI> toProcess = new ArrayList<>();
+ toProcess.add(currentSeq);
+ while (toProcess.size() > 0)
+ {
+ // use a queue ?
+ SequenceI curDs = toProcess.remove(0);
+ if (seqs.contains(curDs))
+ {
+ continue;
+ }
+ seqs.add(curDs);
+ // iterate over database references, making sure we add forward referenced
+ // sequences
+ if (curDs.getDBRefs() != null)
+ {
+ for (DBRefEntry dbr : curDs.getDBRefs())
+ {
+ if (dbr.getMap() != null && dbr.getMap().getTo() != null)
+ {
+ if (dbr.getMap().getTo() == alignedSeq)
+ {
+ /*
+ * update mapping to be to the newly created dataset sequence
+ */
+ dbr.getMap().setTo(currentSeq);
+ }
+ if (dbr.getMap().getTo().getDatasetSequence() != null)
+ {
+ throw new Error(
+ "Implementation error: Map.getTo() for dbref " + dbr
+ + " from " + curDs.getName()
+ + " is not a dataset sequence.");
+ }
+ // we recurse to add all forward references to dataset sequences via
+ // DBRefs/etc
+ toProcess.add(dbr.getMap().getTo());
+ }
+ }
+ }
+ }
+ }
+
+ /**
* Creates a new dataset for this alignment. Can only be done once - if
* dataset is not null this will not be performed.
*/
{
return;
}
- SequenceI[] seqs = new SequenceI[getHeight()];
- SequenceI currentSeq;
+ // try to avoid using SequenceI.equals at this stage, it will be expensive
+ Set<SequenceI> seqs = new LinkedIdentityHashSet<>();
+
for (int i = 0; i < getHeight(); i++)
{
- currentSeq = getSequenceAt(i);
- if (currentSeq.getDatasetSequence() != null)
- {
- seqs[i] = currentSeq.getDatasetSequence();
- }
- else
+ SequenceI currentSeq = getSequenceAt(i);
+ resolveAndAddDatasetSeq(currentSeq, seqs, true);
+ }
+
+ // verify all mappings are in dataset
+ for (AlignedCodonFrame cf : codonFrameList)
+ {
+ for (SequenceToSequenceMapping ssm : cf.getMappings())
{
- seqs[i] = currentSeq.createDatasetSequence();
+ if (!seqs.contains(ssm.getFromSeq()))
+ {
+ resolveAndAddDatasetSeq(ssm.getFromSeq(), seqs, false);
+ }
+ if (!seqs.contains(ssm.getMapping().getTo()))
+ {
+ resolveAndAddDatasetSeq(ssm.getMapping().getTo(), seqs, false);
+ }
}
}
-
- dataset = new Alignment(seqs);
+ // finally construct dataset
+ dataset = new Alignment(seqs.toArray(new SequenceI[seqs.size()]));
// move mappings to the dataset alignment
dataset.codonFrameList = this.codonFrameList;
this.codonFrameList = null;
}
@Override
+ public HiddenColumns getHiddenColumns()
+ {
+ return hiddenCols;
+ }
+
+ @Override
public CigarArray getCompactAlignment()
{
synchronized (sequences)
{
return null;
}
- List<AlignedCodonFrame> cframes = new ArrayList<AlignedCodonFrame>();
+ List<AlignedCodonFrame> cframes = new ArrayList<>();
for (AlignedCodonFrame acf : getCodonFrames())
{
if (acf.involvesSequence(seq))
if (sqs != null)
{
// avoid self append deadlock by
- List<SequenceI> toappendsq = new ArrayList<SequenceI>();
+ List<SequenceI> toappendsq = new ArrayList<>();
synchronized (sqs)
{
for (SequenceI addedsq : sqs)
String calcId, boolean autoCalc, SequenceI seqRef,
SequenceGroup groupRef)
{
- assert (name != null);
if (annotations != null)
{
for (AlignmentAnnotation annot : getAlignmentAnnotation())
@Override
public Iterable<AlignmentAnnotation> findAnnotation(String calcId)
{
- ArrayList<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
- for (AlignmentAnnotation a : getAlignmentAnnotation())
+ List<AlignmentAnnotation> aa = new ArrayList<>();
+ AlignmentAnnotation[] alignmentAnnotation = getAlignmentAnnotation();
+ if (alignmentAnnotation != null)
{
- if (a.getCalcId() == calcId
- || (a.getCalcId() != null && calcId != null && a.getCalcId()
- .equals(calcId)))
+ for (AlignmentAnnotation a : alignmentAnnotation)
{
- aa.add(a);
+ if (a.getCalcId() == calcId
+ || (a.getCalcId() != null && calcId != null && a
+ .getCalcId().equals(calcId)))
+ {
+ aa.add(a);
+ }
}
}
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>();
+ ArrayList<AlignmentAnnotation> aa = new ArrayList<>();
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))
+ if ((calcId == null || (ann.getCalcId() != null && ann.getCalcId()
+ .equals(calcId)))
+ && (seq == null || (ann.sequenceRef != null && ann.sequenceRef == seq))
+ && (label == null || (ann.label != null && ann.label
+ .equals(label))))
{
aa.add(ann);
}
@Override
public Set<String> getSequenceNames()
{
- Set<String> names = new HashSet<String>();
+ Set<String> names = new HashSet<>();
for (SequenceI seq : getSequences())
{
names.add(seq.getName());
}
return new int[] { startPos, endPos };
}
+
+ @Override
+ public void setHiddenColumns(HiddenColumns cols)
+ {
+ hiddenCols = cols;
+ }
}