+ @Override
+ public AlignCalcManagerI getCalcManager()
+ {
+ return calculator;
+ }
+
+ /**
+ * should conservation rows be shown for groups
+ */
+ protected boolean showGroupConservation = false;
+
+ /**
+ * should consensus rows be shown for groups
+ */
+ protected boolean showGroupConsensus = false;
+
+ /**
+ * should consensus profile be rendered by default
+ */
+ protected boolean showSequenceLogo = false;
+
+ /**
+ * should consensus profile be rendered normalised to row height
+ */
+ protected boolean normaliseSequenceLogo = false;
+
+ /**
+ * should consensus histograms be rendered by default
+ */
+ protected boolean showConsensusHistogram = true;
+
+ /**
+ * @return the showConsensusProfile
+ */
+ @Override
+ public boolean isShowSequenceLogo()
+ {
+ return showSequenceLogo;
+ }
+
+ /**
+ * @param showSequenceLogo
+ * the new value
+ */
+ public void setShowSequenceLogo(boolean showSequenceLogo)
+ {
+ if (showSequenceLogo != this.showSequenceLogo)
+ {
+ // TODO: decouple settings setting from calculation when refactoring
+ // annotation update method from alignframe to viewport
+ this.showSequenceLogo = showSequenceLogo;
+ calculator.updateAnnotationFor(ConsensusThread.class);
+ calculator.updateAnnotationFor(ComplementConsensusThread.class);
+ calculator.updateAnnotationFor(StrucConsensusThread.class);
+ }
+ this.showSequenceLogo = showSequenceLogo;
+ }
+
+ /**
+ * @param showConsensusHistogram
+ * the showConsensusHistogram to set
+ */
+ public void setShowConsensusHistogram(boolean showConsensusHistogram)
+ {
+ this.showConsensusHistogram = showConsensusHistogram;
+ }
+
+ /**
+ * @return the showGroupConservation
+ */
+ public boolean isShowGroupConservation()
+ {
+ return showGroupConservation;
+ }
+
+ /**
+ * @param showGroupConservation
+ * the showGroupConservation to set
+ */
+ public void setShowGroupConservation(boolean showGroupConservation)
+ {
+ this.showGroupConservation = showGroupConservation;
+ }
+
+ /**
+ * @return the showGroupConsensus
+ */
+ public boolean isShowGroupConsensus()
+ {
+ return showGroupConsensus;
+ }
+
+ /**
+ * @param showGroupConsensus
+ * the showGroupConsensus to set
+ */
+ public void setShowGroupConsensus(boolean showGroupConsensus)
+ {
+ this.showGroupConsensus = showGroupConsensus;
+ }
+
+ /**
+ *
+ * @return flag to indicate if the consensus histogram should be rendered by
+ * default
+ */
+ @Override
+ public boolean isShowConsensusHistogram()
+ {
+ return this.showConsensusHistogram;
+ }
+
+ /**
+ * when set, updateAlignment will always ensure sequences are of equal length
+ */
+ private boolean padGaps = false;
+
+ /**
+ * when set, alignment should be reordered according to a newly opened tree
+ */
+ public boolean sortByTree = false;
+
+ /**
+ *
+ *
+ * @return null or the currently selected sequence region
+ */
+ @Override
+ public SequenceGroup getSelectionGroup()
+ {
+ return selectionGroup;
+ }
+
+ /**
+ * Set the selection group for this window. Also sets the current alignment as
+ * the context for the group, if it does not already have one.
+ *
+ * @param sg
+ * - group holding references to sequences in this alignment view
+ *
+ */
+ @Override
+ public void setSelectionGroup(SequenceGroup sg)
+ {
+ selectionGroup = sg;
+ if (sg != null && sg.getContext() == null)
+ {
+ sg.setContext(alignment);
+ }
+ }
+
+ public void setHiddenColumns(HiddenColumns hidden)
+ {
+ this.alignment.setHiddenColumns(hidden);
+ }
+
+ @Override
+ public ColumnSelection getColumnSelection()
+ {
+ return colSel;
+ }
+
+ @Override
+ public void setColumnSelection(ColumnSelection colSel)
+ {
+ this.colSel = colSel;
+ if (colSel != null)
+ {
+ updateHiddenColumns();
+ }
+ isColSelChanged(true);
+ }
+
+ /**
+ *
+ * @return
+ */
+ @Override
+ public Map<SequenceI, SequenceCollectionI> getHiddenRepSequences()
+ {
+ return hiddenRepSequences;
+ }
+
+ @Override
+ public void setHiddenRepSequences(
+ Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
+ {
+ this.hiddenRepSequences = hiddenRepSequences;
+ }
+
+ @Override
+ public boolean hasSelectedColumns()
+ {
+ ColumnSelection columnSelection = getColumnSelection();
+ return columnSelection != null && columnSelection.hasSelectedColumns();
+ }
+
+ @Override
+ public boolean hasHiddenColumns()
+ {
+ return alignment.getHiddenColumns() != null
+ && alignment.getHiddenColumns().hasHiddenColumns();
+ }
+
+ public void updateHiddenColumns()
+ {
+ // this method doesn't really do anything now. But - it could, since a
+ // column Selection could be in the process of modification
+ // hasHiddenColumns = colSel.hasHiddenColumns();
+ }
+
+ @Override
+ public boolean hasHiddenRows()
+ {
+ return alignment.getHiddenSequences().getSize() > 0;
+ }
+
+ protected SequenceGroup selectionGroup;
+
+ public void setSequenceSetId(String newid)
+ {
+ if (sequenceSetID != null)
+ {
+ System.err.println(
+ "Warning - overwriting a sequenceSetId for a viewport!");
+ }
+ sequenceSetID = new String(newid);
+ }
+
+ @Override
+ public String getSequenceSetId()
+ {
+ if (sequenceSetID == null)
+ {
+ sequenceSetID = alignment.hashCode() + "";
+ }
+
+ return sequenceSetID;
+ }
+
+ /**
+ * unique viewId for synchronizing state (e.g. with stored Jalview Project)
+ *
+ */
+ protected String viewId = null;
+
+ @Override
+ public String getViewId()
+ {
+ if (viewId == null)
+ {
+ viewId = this.getSequenceSetId() + "." + this.hashCode() + "";
+ }
+ return viewId;
+ }
+
+ public void setIgnoreGapsConsensus(boolean b, AlignmentViewPanel ap)
+ {
+ ignoreGapsInConsensusCalculation = b;
+ if (ap != null)
+ {
+ updateConsensus(ap);
+ if (residueShading != null)
+ {
+ residueShading.setThreshold(residueShading.getThreshold(),
+ ignoreGapsInConsensusCalculation);
+ }
+ }
+
+ }
+
+ private long sgrouphash = -1, colselhash = -1;
+
+ /**
+ * checks current SelectionGroup against record of last hash value, and
+ * updates record.
+ *
+ * @param b
+ * update the record of last hash value
+ *
+ * @return true if SelectionGroup changed since last call (when b is true)
+ */
+ public boolean isSelectionGroupChanged(boolean b)
+ {
+ int hc = (selectionGroup == null || selectionGroup.getSize() == 0) ? -1
+ : selectionGroup.hashCode();
+ if (hc != -1 && hc != sgrouphash)
+ {
+ if (b)
+ {
+ sgrouphash = hc;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * checks current colsel against record of last hash value, and optionally
+ * updates record.
+ *
+ * @param b
+ * update the record of last hash value
+ * @return true if colsel changed since last call (when b is true)
+ */
+ public boolean isColSelChanged(boolean b)
+ {
+ int hc = (colSel == null || colSel.isEmpty()) ? -1 : colSel.hashCode();
+ if (hc != -1 && hc != colselhash)
+ {
+ if (b)
+ {
+ colselhash = hc;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isIgnoreGapsConsensus()
+ {
+ return ignoreGapsInConsensusCalculation;
+ }
+
+ // property change stuff
+ // JBPNote Prolly only need this in the applet version.
+ private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
+ this);
+
+ protected boolean showConservation = true;
+
+ protected boolean showQuality = true;
+
+ protected boolean showConsensus = true;
+
+ protected boolean showOccupancy = true;
+
+ private Map<SequenceI, Color> sequenceColours = new HashMap<>();
+
+ protected SequenceAnnotationOrder sortAnnotationsBy = null;
+
+ protected boolean showAutocalculatedAbove;
+
+ /**
+ * when set, view will scroll to show the highlighted position
+ */
+ private boolean followHighlight = true;
+
+ /**
+ * Property change listener for changes in alignment
+ *
+ * @param listener
+ * DOCUMENT ME!
+ */
+ public void addPropertyChangeListener(
+ java.beans.PropertyChangeListener listener)
+ {
+ changeSupport.addPropertyChangeListener(listener);
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param listener
+ * DOCUMENT ME!
+ */
+ public void removePropertyChangeListener(
+ java.beans.PropertyChangeListener listener)
+ {
+ if (changeSupport != null)
+ {
+ changeSupport.removePropertyChangeListener(listener);
+ }
+ }
+
+ /**
+ * Property change listener for changes in alignment
+ *
+ * @param prop
+ * DOCUMENT ME!
+ * @param oldvalue
+ * DOCUMENT ME!
+ * @param newvalue
+ * DOCUMENT ME!
+ */
+ public void firePropertyChange(String prop, Object oldvalue,
+ Object newvalue)
+ {
+ changeSupport.firePropertyChange(prop, oldvalue, newvalue);
+ }
+
+ // common hide/show column stuff
+
+ public void hideSelectedColumns()
+ {
+ if (colSel.isEmpty())
+ {
+ return;
+ }
+
+ colSel.hideSelectedColumns(alignment);
+ setSelectionGroup(null);
+ isColSelChanged(true);
+ }
+
+ public void hideColumns(int start, int end)
+ {
+ if (start == end)
+ {
+ colSel.hideSelectedColumns(start, alignment.getHiddenColumns());
+ }
+ else
+ {
+ alignment.getHiddenColumns().hideColumns(start, end);
+ }
+ isColSelChanged(true);
+ }
+
+ public void showColumn(int col)
+ {
+ alignment.getHiddenColumns().revealHiddenColumns(col, colSel);
+ isColSelChanged(true);
+ }
+
+ public void showAllHiddenColumns()
+ {
+ alignment.getHiddenColumns().revealAllHiddenColumns(colSel);
+ isColSelChanged(true);
+ }
+
+ // common hide/show seq stuff
+ public void showAllHiddenSeqs()
+ {
+ int startSeq = ranges.getStartSeq();
+ int endSeq = ranges.getEndSeq();
+
+ if (alignment.getHiddenSequences().getSize() > 0)
+ {
+ if (selectionGroup == null)
+ {
+ selectionGroup = new SequenceGroup();
+ selectionGroup.setEndRes(alignment.getWidth() - 1);
+ }
+ List<SequenceI> tmp = alignment.getHiddenSequences()
+ .showAll(hiddenRepSequences);
+ for (SequenceI seq : tmp)
+ {
+ selectionGroup.addSequence(seq, false);
+ setSequenceAnnotationsVisible(seq, true);
+ }
+
+ hiddenRepSequences = null;
+
+ ranges.setStartEndSeq(startSeq, endSeq + tmp.size());
+
+ firePropertyChange("alignment", null, alignment.getSequences());
+ // used to set hasHiddenRows/hiddenRepSequences here, after the property
+ // changed event
+ sendSelection();
+ }
+ }
+
+ public void showSequence(int index)
+ {
+ int startSeq = ranges.getStartSeq();
+ int endSeq = ranges.getEndSeq();
+
+ List<SequenceI> tmp = alignment.getHiddenSequences().showSequence(index,
+ hiddenRepSequences);
+ if (tmp.size() > 0)
+ {
+ if (selectionGroup == null)
+ {
+ selectionGroup = new SequenceGroup();
+ selectionGroup.setEndRes(alignment.getWidth() - 1);
+ }
+
+ for (SequenceI seq : tmp)
+ {
+ selectionGroup.addSequence(seq, false);
+ setSequenceAnnotationsVisible(seq, true);
+ }
+
+ ranges.setStartEndSeq(startSeq, endSeq + tmp.size());
+
+ firePropertyChange("alignment", null, alignment.getSequences());
+ sendSelection();
+ }
+ }
+
+ public void hideAllSelectedSeqs()
+ {
+ if (selectionGroup == null || selectionGroup.getSize() < 1)
+ {
+ return;
+ }
+
+ SequenceI[] seqs = selectionGroup.getSequencesInOrder(alignment);
+
+ hideSequence(seqs);
+
+ setSelectionGroup(null);
+ }
+
+ public void hideSequence(SequenceI[] seq)
+ {
+ /*
+ * cache offset to first visible sequence
+ */
+ int startSeq = ranges.getStartSeq();
+
+ if (seq != null)
+ {
+ for (int i = 0; i < seq.length; i++)
+ {
+ alignment.getHiddenSequences().hideSequence(seq[i]);
+ setSequenceAnnotationsVisible(seq[i], false);
+ }
+ ranges.setStartSeq(startSeq);
+ firePropertyChange("alignment", null, alignment.getSequences());
+ }
+ }
+
+ /**
+ * Hides the specified sequence, or the sequences it represents
+ *
+ * @param sequence
+ * the sequence to hide, or keep as representative
+ * @param representGroup
+ * if true, hide the current selection group except for the
+ * representative sequence
+ */
+ public void hideSequences(SequenceI sequence, boolean representGroup)
+ {
+ if (selectionGroup == null || selectionGroup.getSize() < 1)
+ {
+ hideSequence(new SequenceI[] { sequence });
+ return;
+ }
+
+ if (representGroup)
+ {
+ hideRepSequences(sequence, selectionGroup);
+ setSelectionGroup(null);
+ return;
+ }
+
+ int gsize = selectionGroup.getSize();
+ SequenceI[] hseqs = selectionGroup.getSequences()
+ .toArray(new SequenceI[gsize]);
+
+ hideSequence(hseqs);
+ setSelectionGroup(null);
+ sendSelection();
+ }
+
+ /**
+ * Set visibility for any annotations for the given sequence.
+ *
+ * @param sequenceI
+ */
+ protected void setSequenceAnnotationsVisible(SequenceI sequenceI,
+ boolean visible)
+ {
+ AlignmentAnnotation[] anns = alignment.getAlignmentAnnotation();
+ if (anns != null)
+ {
+ for (AlignmentAnnotation ann : anns)
+ {
+ if (ann.sequenceRef == sequenceI)
+ {
+ ann.visible = visible;
+ }
+ }
+ }
+ }
+
+ public void hideRepSequences(SequenceI repSequence, SequenceGroup sg)
+ {
+ int sSize = sg.getSize();
+ if (sSize < 2)
+ {
+ return;
+ }
+
+ if (hiddenRepSequences == null)
+ {
+ hiddenRepSequences = new Hashtable<>();
+ }
+
+ hiddenRepSequences.put(repSequence, sg);
+
+ // Hide all sequences except the repSequence
+ SequenceI[] seqs = new SequenceI[sSize - 1];
+ int index = 0;
+ for (int i = 0; i < sSize; i++)
+ {
+ if (sg.getSequenceAt(i) != repSequence)
+ {
+ if (index == sSize - 1)
+ {
+ return;
+ }
+
+ seqs[index++] = sg.getSequenceAt(i);
+ }
+ }
+ sg.setSeqrep(repSequence); // note: not done in 2.7applet
+ sg.setHidereps(true); // note: not done in 2.7applet
+ hideSequence(seqs);
+
+ }
+
+ /**
+ *
+ * @return null or the current reference sequence
+ */
+ public SequenceI getReferenceSeq()
+ {
+ return alignment.getSeqrep();
+ }
+
+ /**
+ * @param seq
+ * @return true iff seq is the reference for the alignment
+ */
+ public boolean isReferenceSeq(SequenceI seq)
+ {
+ return alignment.getSeqrep() == seq;
+ }
+
+ /**
+ *
+ * @param seq
+ * @return true if there are sequences represented by this sequence that are
+ * currently hidden
+ */
+ public boolean isHiddenRepSequence(SequenceI seq)
+ {
+ return (hiddenRepSequences != null
+ && hiddenRepSequences.containsKey(seq));
+ }
+
+ /**
+ *
+ * @param seq
+ * @return null or a sequence group containing the sequences that seq
+ * represents
+ */
+ public SequenceGroup getRepresentedSequences(SequenceI seq)
+ {
+ return (SequenceGroup) (hiddenRepSequences == null ? null
+ : hiddenRepSequences.get(seq));
+ }
+
+ @Override
+ public int adjustForHiddenSeqs(int alignmentIndex)
+ {
+ return alignment.getHiddenSequences()
+ .adjustForHiddenSeqs(alignmentIndex);
+ }
+
+ @Override
+ public void invertColumnSelection()
+ {
+ colSel.invertColumnSelection(0, alignment.getWidth(), alignment);
+ isColSelChanged(true);
+ }
+
+ @Override
+ public SequenceI[] getSelectionAsNewSequence()
+ {
+ SequenceI[] sequences;
+ // JBPNote: Need to test jalviewLite.getSelectedSequencesAsAlignmentFrom -
+ // this was the only caller in the applet for this method
+ // JBPNote: in applet, this method returned references to the alignment
+ // sequences, and it did not honour the presence/absence of annotation
+ // attached to the alignment (probably!)
+ if (selectionGroup == null || selectionGroup.getSize() == 0)
+ {
+ sequences = alignment.getSequencesArray();
+ AlignmentAnnotation[] annots = alignment.getAlignmentAnnotation();
+ for (int i = 0; i < sequences.length; i++)
+ {
+ // construct new sequence with subset of visible annotation
+ sequences[i] = new Sequence(sequences[i], annots);
+ }
+ }
+ else
+ {
+ sequences = selectionGroup.getSelectionAsNewSequences(alignment);
+ }
+
+ return sequences;
+ }
+
+ @Override
+ public SequenceI[] getSequenceSelection()
+ {
+ SequenceI[] sequences = null;
+ if (selectionGroup != null)
+ {
+ sequences = selectionGroup.getSequencesInOrder(alignment);
+ }
+ if (sequences == null)
+ {
+ sequences = alignment.getSequencesArray();
+ }
+ return sequences;
+ }
+
+ @Override
+ public jalview.datamodel.AlignmentView getAlignmentView(
+ boolean selectedOnly)
+ {
+ return getAlignmentView(selectedOnly, false);
+ }
+
+ @Override
+ public jalview.datamodel.AlignmentView getAlignmentView(
+ boolean selectedOnly, boolean markGroups)
+ {
+ return new AlignmentView(alignment, alignment.getHiddenColumns(),
+ selectionGroup,
+ alignment.getHiddenColumns() != null
+ && alignment.getHiddenColumns().hasHiddenColumns(),
+ selectedOnly, markGroups);
+ }
+
+ @Override
+ public String[] getViewAsString(boolean selectedRegionOnly)
+ {
+ return getViewAsString(selectedRegionOnly, true);
+ }
+
+ @Override
+ public String[] getViewAsString(boolean selectedRegionOnly,
+ boolean exportHiddenSeqs)
+ {
+ String[] selection = null;
+ SequenceI[] seqs = null;
+ int i, iSize;
+ int start = 0, end = 0;
+ if (selectedRegionOnly && selectionGroup != null)
+ {
+ iSize = selectionGroup.getSize();
+ seqs = selectionGroup.getSequencesInOrder(alignment);
+ start = selectionGroup.getStartRes();
+ end = selectionGroup.getEndRes() + 1;
+ }
+ else
+ {
+ if (hasHiddenRows() && exportHiddenSeqs)
+ {
+ AlignmentI fullAlignment = alignment.getHiddenSequences()
+ .getFullAlignment();
+ iSize = fullAlignment.getHeight();
+ seqs = fullAlignment.getSequencesArray();
+ end = fullAlignment.getWidth();
+ }
+ else
+ {
+ iSize = alignment.getHeight();
+ seqs = alignment.getSequencesArray();
+ end = alignment.getWidth();
+ }
+ }
+
+ selection = new String[iSize];
+ if (alignment.getHiddenColumns() != null
+ && alignment.getHiddenColumns().hasHiddenColumns())
+ {
+ for (i = 0; i < iSize; i++)
+ {
+ Iterator<int[]> blocks = alignment.getHiddenColumns()
+ .getVisContigsIterator(start, end + 1, false);
+ selection[i] = seqs[i].getSequenceStringFromIterator(blocks);
+ }
+ }
+ else
+ {
+ for (i = 0; i < iSize; i++)
+ {
+ selection[i] = seqs[i].getSequenceAsString(start, end);
+ }
+
+ }
+ return selection;
+ }
+
+ @Override
+ public List<int[]> getVisibleRegionBoundaries(int min, int max)
+ {
+ ArrayList<int[]> regions = new ArrayList<>();
+ int start = min;
+ int end = max;
+
+ do
+ {
+ HiddenColumns hidden = alignment.getHiddenColumns();
+ if (hidden != null && hidden.hasHiddenColumns())
+ {
+ if (start == 0)
+ {
+ start = hidden.visibleToAbsoluteColumn(start);
+ }
+
+ end = hidden.getNextHiddenBoundary(false, start);
+ if (start == end)
+ {
+ end = max;
+ }
+ if (end > max)
+ {
+ end = max;
+ }
+ }
+
+ regions.add(new int[] { start, end });
+
+ if (hidden != null && hidden.hasHiddenColumns())
+ {
+ start = hidden.visibleToAbsoluteColumn(end);
+ start = hidden.getNextHiddenBoundary(true, start) + 1;
+ }
+ } while (end < max);
+
+ // int[][] startEnd = new int[regions.size()][2];
+
+ return regions;
+ }
+
+ @Override
+ public List<AlignmentAnnotation> getVisibleAlignmentAnnotation(
+ boolean selectedOnly)
+ {
+ ArrayList<AlignmentAnnotation> ala = new ArrayList<>();
+ AlignmentAnnotation[] aa;
+ if ((aa = alignment.getAlignmentAnnotation()) != null)
+ {
+ for (AlignmentAnnotation annot : aa)
+ {
+ AlignmentAnnotation clone = new AlignmentAnnotation(annot);
+ if (selectedOnly && selectionGroup != null)
+ {
+ clone.makeVisibleAnnotation(
+ selectionGroup.getStartRes(), selectionGroup.getEndRes(),
+ alignment.getHiddenColumns());
+ }
+ else
+ {
+ clone.makeVisibleAnnotation(alignment.getHiddenColumns());
+ }
+ ala.add(clone);
+ }
+ }
+ return ala;
+ }
+
+ @Override
+ public boolean isPadGaps()
+ {
+ return padGaps;
+ }
+
+ @Override
+ public void setPadGaps(boolean padGaps)
+ {
+ this.padGaps = padGaps;
+ }
+
+ /**
+ * apply any post-edit constraints and trigger any calculations needed after
+ * an edit has been performed on the alignment
+ *
+ * @param ap
+ */
+ @Override
+ public void alignmentChanged(AlignmentViewPanel ap)
+ {
+ if (isPadGaps())
+ {
+ alignment.padGaps();
+ }
+ if (autoCalculateConsensus)
+ {
+ updateConsensus(ap);
+ }
+ if (hconsensus != null && autoCalculateConsensus)
+ {
+ updateConservation(ap);
+ }
+ if (autoCalculateStrucConsensus)
+ {
+ updateStrucConsensus(ap);
+ }
+
+ // Reset endRes of groups if beyond alignment width
+ int alWidth = alignment.getWidth();
+ List<SequenceGroup> groups = alignment.getGroups();
+ if (groups != null)
+ {
+ for (SequenceGroup sg : groups)
+ {
+ if (sg.getEndRes() > alWidth)
+ {
+ sg.setEndRes(alWidth - 1);
+ }
+ }
+ }
+
+ if (selectionGroup != null && selectionGroup.getEndRes() > alWidth)
+ {
+ selectionGroup.setEndRes(alWidth - 1);
+ }
+
+ updateAllColourSchemes();
+ calculator.restartWorkers();
+ // alignment.adjustSequenceAnnotations();
+ }
+
+ /**
+ * reset scope and do calculations for all applied colourschemes on alignment
+ */
+ void updateAllColourSchemes()
+ {
+ ResidueShaderI rs = residueShading;
+ if (rs != null)
+ {
+ rs.alignmentChanged(alignment, hiddenRepSequences);
+
+ rs.setConsensus(hconsensus);
+ if (rs.conservationApplied())
+ {
+ rs.setConservation(Conservation.calculateConservation("All",
+ alignment.getSequences(), 0, alignment.getWidth(), false,
+ getConsPercGaps(), false));
+ }
+ }
+
+ for (SequenceGroup sg : alignment.getGroups())
+ {
+ if (sg.cs != null)
+ {
+ sg.cs.alignmentChanged(sg, hiddenRepSequences);
+ }
+ sg.recalcConservation();
+ }
+ }
+
+ protected void initAutoAnnotation()
+ {
+ // TODO: add menu option action that nulls or creates consensus object
+ // depending on if the user wants to see the annotation or not in a
+ // specific alignment
+
+ if (hconsensus == null && !isDataset)
+ {
+ if (!alignment.isNucleotide())
+ {
+ initConservation();
+ initQuality();
+ }
+ else
+ {
+ initRNAStructure();
+ }
+ consensus = new AlignmentAnnotation("Consensus",
+ MessageManager.getString("label.consensus_descr"),
+ new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
+ initConsensus(consensus);
+ initGapCounts();
+
+ initComplementConsensus();
+ }
+ }
+
+ /**
+ * If this is a protein alignment and there are mappings to cDNA, adds the
+ * cDNA consensus annotation and returns true, else returns false.
+ */
+ public boolean initComplementConsensus()
+ {
+ if (!alignment.isNucleotide())
+ {
+ final List<AlignedCodonFrame> codonMappings = alignment
+ .getCodonFrames();
+ if (codonMappings != null && !codonMappings.isEmpty())
+ {
+ boolean doConsensus = false;
+ for (AlignedCodonFrame mapping : codonMappings)
+ {
+ // TODO hold mapping type e.g. dna-to-protein in AlignedCodonFrame?
+ MapList[] mapLists = mapping.getdnaToProt();
+ // mapLists can be empty if project load has not finished resolving
+ // seqs
+ if (mapLists.length > 0 && mapLists[0].getFromRatio() == 3)
+ {
+ doConsensus = true;
+ break;
+ }
+ }
+ if (doConsensus)
+ {
+ complementConsensus = new AlignmentAnnotation("cDNA Consensus",
+ MessageManager
+ .getString("label.complement_consensus_descr"),
+ new Annotation[1], 0f, 100f,
+ AlignmentAnnotation.BAR_GRAPH);
+ initConsensus(complementConsensus);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void initConsensus(AlignmentAnnotation aa)
+ {
+ aa.hasText = true;
+ aa.autoCalculated = true;
+
+ if (showConsensus)
+ {
+ alignment.addAnnotation(aa);
+ }
+ }
+
+ // these should be extracted from the view model - style and settings for
+ // derived annotation
+ private void initGapCounts()
+ {
+ if (showOccupancy)
+ {
+ gapcounts = new AlignmentAnnotation("Occupancy",
+ MessageManager.getString("label.occupancy_descr"),
+ new Annotation[1], 0f, alignment.getHeight(),
+ AlignmentAnnotation.BAR_GRAPH);
+ gapcounts.hasText = true;
+ gapcounts.autoCalculated = true;
+ gapcounts.scaleColLabel = true;
+ gapcounts.graph = AlignmentAnnotation.BAR_GRAPH;
+
+ alignment.addAnnotation(gapcounts);
+ }
+ }
+
+ private void initConservation()
+ {
+ if (showConservation)
+ {
+ if (conservation == null)
+ {
+ conservation = new AlignmentAnnotation("Conservation",
+ MessageManager.formatMessage("label.conservation_descr",
+ getConsPercGaps()),
+ new Annotation[1], 0f, 11f, AlignmentAnnotation.BAR_GRAPH);
+ conservation.hasText = true;
+ conservation.autoCalculated = true;
+ alignment.addAnnotation(conservation);
+ }
+ }
+ }
+
+ private void initQuality()
+ {
+ if (showQuality)
+ {
+ if (quality == null)
+ {
+ quality = new AlignmentAnnotation("Quality",
+ MessageManager.getString("label.quality_descr"),
+ new Annotation[1], 0f, 11f, AlignmentAnnotation.BAR_GRAPH);
+ quality.hasText = true;
+ quality.autoCalculated = true;
+ alignment.addAnnotation(quality);
+ }
+ }
+ }
+
+ private void initRNAStructure()
+ {
+ if (alignment.hasRNAStructure() && strucConsensus == null)
+ {
+ strucConsensus = new AlignmentAnnotation("StrucConsensus",
+ MessageManager.getString("label.strucconsensus_descr"),
+ new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
+ strucConsensus.hasText = true;
+ strucConsensus.autoCalculated = true;
+
+ if (showConsensus)
+ {
+ alignment.addAnnotation(strucConsensus);
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see jalview.api.AlignViewportI#calcPanelHeight()
+ */
+ @Override
+ public int calcPanelHeight()
+ {
+ // setHeight of panels
+ AlignmentAnnotation[] anns = getAlignment().getAlignmentAnnotation();
+ int height = 0;
+ int charHeight = getCharHeight();
+ if (anns != null)
+ {
+ BitSet graphgrp = new BitSet();
+ for (AlignmentAnnotation aa : anns)
+ {
+ if (aa == null)
+ {
+ System.err.println("Null annotation row: ignoring.");
+ continue;
+ }
+ if (!aa.visible)
+ {
+ continue;
+ }
+ if (aa.graphGroup > -1)
+ {
+ if (graphgrp.get(aa.graphGroup))
+ {
+ continue;
+ }
+ else
+ {
+ graphgrp.set(aa.graphGroup);
+ }
+ }
+ aa.height = 0;
+
+ if (aa.hasText)
+ {
+ aa.height += charHeight;
+ }
+
+ if (aa.hasIcons)
+ {
+ aa.height += 16;
+ }
+
+ if (aa.graph > 0)
+ {
+ aa.height += aa.graphHeight;
+ }
+
+ if (aa.height == 0)
+ {
+ aa.height = 20;
+ }
+
+ height += aa.height;
+ }
+ }
+ if (height == 0)
+ {
+ // set minimum
+ height = 20;
+ }
+ return height;
+ }
+
+ @Override
+ public void updateGroupAnnotationSettings(boolean applyGlobalSettings,
+ boolean preserveNewGroupSettings)
+ {
+ boolean updateCalcs = false;
+ boolean conv = isShowGroupConservation();
+ boolean cons = isShowGroupConsensus();
+ boolean showprf = isShowSequenceLogo();
+ boolean showConsHist = isShowConsensusHistogram();
+ boolean normLogo = isNormaliseSequenceLogo();
+
+ /**
+ * TODO reorder the annotation rows according to group/sequence ordering on
+ * alignment
+ */
+ // boolean sortg = true;
+
+ // remove old automatic annotation
+ // add any new annotation
+
+ // intersect alignment annotation with alignment groups
+
+ AlignmentAnnotation[] aan = alignment.getAlignmentAnnotation();
+ List<SequenceGroup> oldrfs = new ArrayList<>();
+ if (aan != null)
+ {
+ for (int an = 0; an < aan.length; an++)
+ {
+ if (aan[an].autoCalculated && aan[an].groupRef != null)
+ {
+ oldrfs.add(aan[an].groupRef);
+ alignment.deleteAnnotation(aan[an], false);
+ }
+ }
+ }
+ if (alignment.getGroups() != null)
+ {
+ for (SequenceGroup sg : alignment.getGroups())
+ {
+ updateCalcs = false;
+ if (applyGlobalSettings
+ || (!preserveNewGroupSettings && !oldrfs.contains(sg)))
+ {
+ // set defaults for this group's conservation/consensus
+ sg.setshowSequenceLogo(showprf);
+ sg.setShowConsensusHistogram(showConsHist);
+ sg.setNormaliseSequenceLogo(normLogo);
+ }
+ if (conv)
+ {
+ updateCalcs = true;
+ alignment.addAnnotation(sg.getConservationRow(), 0);
+ }
+ if (cons)
+ {
+ updateCalcs = true;
+ alignment.addAnnotation(sg.getConsensus(), 0);
+ }
+ // refresh the annotation rows
+ if (updateCalcs)
+ {
+ sg.recalcConservation();
+ }
+ }
+ }
+ oldrfs.clear();
+ }
+
+ @Override
+ public boolean isDisplayReferenceSeq()
+ {
+ return alignment.hasSeqrep() && viewStyle.isDisplayReferenceSeq();
+ }
+
+ @Override
+ public void setDisplayReferenceSeq(boolean displayReferenceSeq)
+ {
+ viewStyle.setDisplayReferenceSeq(displayReferenceSeq);
+ }
+
+ @Override
+ public boolean isColourByReferenceSeq()
+ {
+ return alignment.hasSeqrep() && viewStyle.isColourByReferenceSeq();
+ }
+
+ @Override
+ public Color getSequenceColour(SequenceI seq)
+ {
+ Color sqc = sequenceColours.get(seq);
+ return (sqc == null ? Color.white : sqc);
+ }
+
+ @Override
+ public void setSequenceColour(SequenceI seq, Color col)
+ {
+ if (col == null)
+ {
+ sequenceColours.remove(seq);
+ }
+ else
+ {
+ sequenceColours.put(seq, col);
+ }
+ }
+
+ @Override
+ public void updateSequenceIdColours()
+ {
+ for (SequenceGroup sg : alignment.getGroups())
+ {
+ if (sg.idColour != null)
+ {
+ for (SequenceI s : sg.getSequences(getHiddenRepSequences()))
+ {
+ sequenceColours.put(s, sg.idColour);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void clearSequenceColours()
+ {
+ sequenceColours.clear();
+ }
+
+ @Override
+ public AlignViewportI getCodingComplement()
+ {
+ return this.codingComplement;
+ }
+
+ /**
+ * Set this as the (cDna/protein) complement of the given viewport. Also
+ * ensures the reverse relationship is set on the given viewport.
+ */
+ @Override
+ public void setCodingComplement(AlignViewportI av)
+ {
+ if (this == av)
+ {
+ System.err.println("Ignoring recursive setCodingComplement request");
+ }
+ else
+ {
+ this.codingComplement = av;
+ // avoid infinite recursion!
+ if (av.getCodingComplement() != this)
+ {
+ av.setCodingComplement(this);
+ }
+ }
+ }
+
+ @Override
+ public boolean isNucleotide()
+ {
+ return getAlignment() == null ? false : getAlignment().isNucleotide();
+ }
+
+ @Override
+ public FeaturesDisplayedI getFeaturesDisplayed()
+ {
+ return featuresDisplayed;
+ }
+
+ @Override
+ public void setFeaturesDisplayed(FeaturesDisplayedI featuresDisplayedI)
+ {
+ featuresDisplayed = featuresDisplayedI;
+ }
+
+ @Override
+ public boolean areFeaturesDisplayed()
+ {
+ return featuresDisplayed != null
+ && featuresDisplayed.getRegisteredFeaturesCount() > 0;
+ }
+
+ /**
+ * set the flag
+ *
+ * @param b
+ * features are displayed if true
+ */
+ @Override
+ public void setShowSequenceFeatures(boolean b)
+ {
+ viewStyle.setShowSequenceFeatures(b);
+ }
+
+ @Override
+ public boolean isShowSequenceFeatures()
+ {
+ return viewStyle.isShowSequenceFeatures();
+ }
+
+ @Override
+ public void setShowSequenceFeaturesHeight(boolean selected)
+ {
+ viewStyle.setShowSequenceFeaturesHeight(selected);
+ }
+
+ @Override
+ public boolean isShowSequenceFeaturesHeight()
+ {
+ return viewStyle.isShowSequenceFeaturesHeight();
+ }
+
+ @Override
+ public void setShowAnnotation(boolean b)
+ {
+ viewStyle.setShowAnnotation(b);
+ }
+
+ @Override
+ public boolean isShowAnnotation()
+ {
+ return viewStyle.isShowAnnotation();
+ }
+
+ @Override
+ public boolean isRightAlignIds()
+ {
+ return viewStyle.isRightAlignIds();
+ }
+
+ @Override
+ public void setRightAlignIds(boolean rightAlignIds)
+ {
+ viewStyle.setRightAlignIds(rightAlignIds);
+ }
+
+ @Override
+ public boolean getConservationSelected()
+ {
+ return viewStyle.getConservationSelected();
+ }
+
+ @Override
+ public void setShowBoxes(boolean state)
+ {
+ viewStyle.setShowBoxes(state);
+ }
+
+ /**
+ * @return
+ * @see jalview.api.ViewStyleI#getTextColour()
+ */
+ @Override
+ public Color getTextColour()
+ {
+ return viewStyle.getTextColour();
+ }
+
+ /**
+ * @return
+ * @see jalview.api.ViewStyleI#getTextColour2()
+ */
+ @Override
+ public Color getTextColour2()
+ {
+ return viewStyle.getTextColour2();
+ }
+
+ /**
+ * @return
+ * @see jalview.api.ViewStyleI#getThresholdTextColour()
+ */
+ @Override
+ public int getThresholdTextColour()
+ {
+ return viewStyle.getThresholdTextColour();
+ }
+
+ /**
+ * @return
+ * @see jalview.api.ViewStyleI#isConservationColourSelected()
+ */
+ @Override
+ public boolean isConservationColourSelected()
+ {
+ return viewStyle.isConservationColourSelected();