-/*\r
- * Jalview - A Sequence Alignment Editor and Viewer\r
- * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
- *\r
- * This program is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License\r
- * as published by the Free Software Foundation; either version 2\r
- * of the License, or (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA\r
- */\r
-package jalview.datamodel;\r
-\r
-import jalview.analysis.*;\r
-\r
-import jalview.schemes.*;\r
-\r
-import java.awt.*;\r
-\r
-import java.util.*;\r
-\r
-\r
-/**\r
- * DOCUMENT ME!\r
- *\r
- * @author $author$\r
- * @version $Revision$\r
- */\r
-public class SequenceGroup\r
-{\r
- String groupName;\r
- Conservation conserve;\r
- Vector aaFrequency;\r
- boolean displayBoxes;\r
- boolean displayText;\r
- boolean colourText;\r
- private Vector sequences = new Vector();\r
- int width = -1;\r
-\r
- /** DOCUMENT ME!! */\r
- public ColourSchemeI cs;\r
- int startRes = 0;\r
- int endRes = 0;\r
- Color outlineColour = Color.black;\r
-\r
- /**\r
- * Creates a new SequenceGroup object.\r
- */\r
- public SequenceGroup()\r
- {\r
- groupName = "Group";\r
- this.displayBoxes = true;\r
- this.displayText = true;\r
- this.colourText = false;\r
- cs = null;\r
- }\r
-\r
- /**\r
- * Creates a new SequenceGroup object.\r
- *\r
- * @param sequences DOCUMENT ME!\r
- * @param groupName DOCUMENT ME!\r
- * @param scheme DOCUMENT ME!\r
- * @param displayBoxes DOCUMENT ME!\r
- * @param displayText DOCUMENT ME!\r
- * @param colourText DOCUMENT ME!\r
- * @param start DOCUMENT ME!\r
- * @param end DOCUMENT ME!\r
- */\r
- public SequenceGroup(Vector sequences, String groupName,\r
- ColourSchemeI scheme, boolean displayBoxes, boolean displayText,\r
- boolean colourText, int start, int end)\r
- {\r
- this.sequences = sequences;\r
- this.groupName = groupName;\r
- this.displayBoxes = displayBoxes;\r
- this.displayText = displayText;\r
- this.colourText = colourText;\r
- this.cs = scheme;\r
- startRes = start;\r
- endRes = end;\r
- recalcConservation();\r
- }\r
-\r
- /**\r
- * Creates a new SequenceGroup object.\r
- *\r
- * @param groupName DOCUMENT ME!\r
- * @param scheme DOCUMENT ME!\r
- * @param displayBoxes DOCUMENT ME!\r
- * @param displayText DOCUMENT ME!\r
- * @param colourText DOCUMENT ME!\r
- * @param start DOCUMENT ME!\r
- * @param end DOCUMENT ME!\r
- */\r
- public SequenceGroup(String groupName, ColourSchemeI scheme,\r
- boolean displayBoxes, boolean displayText, boolean colourText,\r
- int start, int end)\r
- {\r
- this.groupName = groupName;\r
- this.displayBoxes = displayBoxes;\r
- this.displayText = displayText;\r
- this.colourText = colourText;\r
- this.cs = scheme;\r
- startRes = start;\r
- endRes = end;\r
- }\r
-\r
- public SequenceI [] getSelectionAsNewSequences(AlignmentI align)\r
- {\r
- int iSize = sequences.size();\r
- SequenceI [] seqs = new SequenceI[iSize];\r
- SequenceI [] inorder = getSequencesInOrder(align);\r
-\r
-\r
- for (int i = 0; i < iSize; i++)\r
- {\r
- SequenceI seq = inorder[i];\r
-\r
- seqs[i] = new Sequence(seq.getName(),\r
- seq.getSequence(startRes, endRes + 1),\r
- seq.findPosition(startRes),\r
- findEndRes(seq));\r
-\r
- seqs[i].setDescription(seq.getDescription());\r
- seqs[i].setDBRef(seq.getDBRef());\r
- seqs[i].setSequenceFeatures(seq.getSequenceFeatures());\r
- if (seq.getDatasetSequence() != null)\r
- seqs[i].setDatasetSequence(seq.getDatasetSequence());\r
-\r
- if(seq.getAnnotation()!=null)\r
- {\r
- for(int a=0; a<seq.getAnnotation().length; a++)\r
- seqs[i].addAlignmentAnnotation(seq.getAnnotation()[a]);\r
- }\r
- }\r
-\r
- return seqs;\r
-\r
- }\r
-\r
- /**\r
- * If sequence ends in gaps, the end residue can\r
- * be correctly calculated here\r
- * @param seq SequenceI\r
- * @return int\r
- */\r
- public int findEndRes(SequenceI seq)\r
- {\r
- int eres = 0;\r
- char ch;\r
-\r
- for (int j = 0; j < endRes + 1 && j < seq.getLength(); j++)\r
- {\r
- ch = seq.getCharAt(j);\r
- if (!jalview.util.Comparison.isGap( (ch)))\r
- {\r
- eres++;\r
- }\r
- }\r
-\r
- if (eres > 0)\r
- {\r
- eres += seq.getStart() - 1;\r
- }\r
-\r
- return eres;\r
- }\r
-\r
- public Vector getSequences(boolean includeHidden)\r
- {\r
- if(!includeHidden)\r
- return sequences;\r
- else\r
- {\r
- Vector allSequences = new Vector();\r
- SequenceI seq;\r
- for (int i = 0; i < sequences.size(); i++)\r
- {\r
- seq = (SequenceI) sequences.elementAt(i);\r
- allSequences.addElement(seq);\r
- if (seq.getHiddenSequences() != null)\r
- {\r
- for (int h = 0; h < seq.getHiddenSequences().getSize(false); h++)\r
- {\r
- allSequences.addElement(\r
- seq.getHiddenSequences().getSequenceAt(h)\r
- );\r
- }\r
- }\r
- }\r
-\r
- return allSequences;\r
- }\r
- }\r
-\r
- public SequenceI[] getSequencesAsArray(boolean includeHidden)\r
- {\r
- Vector tmp = getSequences(includeHidden);\r
- if(tmp==null)\r
- return null;\r
- SequenceI [] result = new SequenceI[tmp.size()];\r
- for(int i=0; i<result.length; i++)\r
- result[i] = (SequenceI)tmp.elementAt(i);\r
-\r
- return result;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param col DOCUMENT ME!\r
- *\r
- * @return DOCUMENT ME!\r
- */\r
- public boolean adjustForRemoveLeft(int col)\r
- {\r
- // return value is true if the group still exists\r
- if (startRes >= col)\r
- {\r
- startRes = startRes - col;\r
- }\r
-\r
- if (endRes >= col)\r
- {\r
- endRes = endRes - col;\r
-\r
- if (startRes > endRes)\r
- {\r
- startRes = 0;\r
- }\r
- }\r
- else\r
- {\r
- // must delete this group!!\r
- return false;\r
- }\r
-\r
- return true;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param col DOCUMENT ME!\r
- *\r
- * @return DOCUMENT ME!\r
- */\r
- public boolean adjustForRemoveRight(int col)\r
- {\r
- if (startRes > col)\r
- {\r
- // delete this group\r
- return false;\r
- }\r
-\r
- if (endRes >= col)\r
- {\r
- endRes = col;\r
- }\r
-\r
- return true;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @return DOCUMENT ME!\r
- */\r
- public String getName()\r
- {\r
- return groupName;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param name DOCUMENT ME!\r
- */\r
- public void setName(String name)\r
- {\r
- groupName = name;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @return DOCUMENT ME!\r
- */\r
- public Conservation getConservation()\r
- {\r
- return conserve;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param c DOCUMENT ME!\r
- */\r
- public void setConservation(Conservation c)\r
- {\r
- conserve = c;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param s DOCUMENT ME!\r
- * @param recalc DOCUMENT ME!\r
- */\r
- public void addSequence(SequenceI s, boolean recalc)\r
- {\r
- if (s!=null && !sequences.contains(s))\r
- {\r
- sequences.addElement(s);\r
- }\r
-\r
- if (recalc)\r
- {\r
- recalcConservation();\r
- }\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- */\r
- public void recalcConservation()\r
- {\r
- if(cs == null)\r
- return;\r
-\r
- try\r
- {\r
- cs.setConsensus(AAFrequency.calculate(sequences, 0, getWidth()));\r
-\r
- if (cs instanceof ClustalxColourScheme)\r
- {\r
- ( (ClustalxColourScheme) cs).resetClustalX(sequences, getWidth());\r
- }\r
-\r
- if (cs.conservationApplied())\r
- {\r
- Conservation c = new Conservation(groupName,\r
- ResidueProperties.propHash, 3, sequences,\r
- 0, getWidth());\r
- c.calculate();\r
- c.verdict(false, 25);\r
-\r
- cs.setConservation(c);\r
-\r
- if (cs instanceof ClustalxColourScheme)\r
- {\r
- ( (ClustalxColourScheme) cs).resetClustalX(sequences,\r
- getWidth());\r
- }\r
- }\r
- }\r
- catch (java.lang.OutOfMemoryError err)\r
- {\r
- System.out.println("Out of memory loading groups: " + err);\r
- }\r
-\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param s DOCUMENT ME!\r
- * @param recalc DOCUMENT ME!\r
- */\r
- public void addOrRemove(SequenceI s, boolean recalc)\r
- {\r
- if (sequences.contains(s))\r
- {\r
- deleteSequence(s, recalc);\r
- }\r
- else\r
- {\r
- addSequence(s, recalc);\r
- }\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param s DOCUMENT ME!\r
- * @param recalc DOCUMENT ME!\r
- */\r
- public void deleteSequence(SequenceI s, boolean recalc)\r
- {\r
- sequences.removeElement(s);\r
-\r
- if (recalc)\r
- {\r
- recalcConservation();\r
- }\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @return DOCUMENT ME!\r
- */\r
- public int getStartRes()\r
- {\r
- return startRes;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @return DOCUMENT ME!\r
- */\r
- public int getEndRes()\r
- {\r
- return endRes;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param i DOCUMENT ME!\r
- */\r
- public void setStartRes(int i)\r
- {\r
- startRes = i;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param i DOCUMENT ME!\r
- */\r
- public void setEndRes(int i)\r
- {\r
- endRes = i;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @return DOCUMENT ME!\r
- */\r
- public int getSize(boolean includeHidden)\r
- {\r
- if(!includeHidden)\r
- return sequences.size();\r
- else\r
- {\r
- int total = sequences.size();\r
- SequenceI seq;\r
- for (int i = 0; i < sequences.size(); i++)\r
- {\r
- seq = (SequenceI) sequences.elementAt(i);\r
- if (seq.getHiddenSequences() != null)\r
- {\r
- total += seq.getHiddenSequences().getSize(false);\r
- }\r
- }\r
- return total;\r
- }\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param i DOCUMENT ME!\r
- *\r
- * @return DOCUMENT ME!\r
- */\r
- public SequenceI getSequenceAt(int i)\r
- {\r
- return (SequenceI) sequences.elementAt(i);\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param state DOCUMENT ME!\r
- */\r
- public void setColourText(boolean state)\r
- {\r
- colourText = state;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @return DOCUMENT ME!\r
- */\r
- public boolean getColourText()\r
- {\r
- return colourText;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param state DOCUMENT ME!\r
- */\r
- public void setDisplayText(boolean state)\r
- {\r
- displayText = state;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @return DOCUMENT ME!\r
- */\r
- public boolean getDisplayText()\r
- {\r
- return displayText;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param state DOCUMENT ME!\r
- */\r
- public void setDisplayBoxes(boolean state)\r
- {\r
- displayBoxes = state;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @return DOCUMENT ME!\r
- */\r
- public boolean getDisplayBoxes()\r
- {\r
- return displayBoxes;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @return DOCUMENT ME!\r
- */\r
- public int getWidth()\r
- {\r
- // MC This needs to get reset when characters are inserted and deleted\r
- if (sequences.size() > 0)\r
- {\r
- width = ((SequenceI) sequences.elementAt(0)).getLength();\r
- }\r
-\r
- for (int i = 1; i < sequences.size(); i++)\r
- {\r
- SequenceI seq = (SequenceI) sequences.elementAt(i);\r
-\r
- if (seq.getLength() > width)\r
- {\r
- width = seq.getLength();\r
- }\r
- }\r
-\r
- return width;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @param c DOCUMENT ME!\r
- */\r
- public void setOutlineColour(Color c)\r
- {\r
- outlineColour = c;\r
- }\r
-\r
- /**\r
- * DOCUMENT ME!\r
- *\r
- * @return DOCUMENT ME!\r
- */\r
- public Color getOutlineColour()\r
- {\r
- return outlineColour;\r
- }\r
-\r
- /**\r
- *\r
- * returns the sequences in the group ordered by the ordering given by al\r
- *\r
- * @param al Alignment\r
- * @return SequenceI[]\r
- */\r
- public SequenceI[] getSequencesInOrder(AlignmentI al)\r
- {\r
- int sSize = sequences.size();\r
- int alHeight = al.getHeight();\r
-\r
- SequenceI[] seqs = new SequenceI[sSize];\r
-\r
- int index = 0;\r
- for (int i = 0; i < alHeight && index<sSize; i++)\r
- {\r
- if(sequences.contains( al.getSequenceAt(i) ) )\r
- seqs[index++] = al.getSequenceAt(i);\r
- }\r
-\r
- return seqs;\r
- }\r
-}\r
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ *
+ * This file is part of Jalview.
+ *
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * Jalview 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.datamodel;
+
+import jalview.analysis.AAFrequency;
+import jalview.analysis.Conservation;
+import jalview.renderer.ResidueShader;
+import jalview.renderer.ResidueShaderI;
+import jalview.schemes.ColourSchemeI;
+import jalview.util.MessageManager;
+import jalview.workers.InformationThread;
+
+import java.awt.Color;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Collects a set contiguous ranges on a set of sequences
+ *
+ * @author $author$
+ * @version $Revision$
+ */
+public class SequenceGroup implements AnnotatedCollectionI
+{
+ // TODO ideally this event notification functionality should be separated into
+ // a subclass of ViewportProperties similarly to ViewportRanges.
+ // Done here as a quick fix for JAL-2665
+ public static final String SEQ_GROUP_CHANGED = "Sequence group changed";
+
+ protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(
+ this);
+
+ public void addPropertyChangeListener(PropertyChangeListener listener)
+ {
+ changeSupport.addPropertyChangeListener(listener);
+ }
+
+ public void removePropertyChangeListener(PropertyChangeListener listener)
+ {
+ changeSupport.removePropertyChangeListener(listener);
+ }
+ // end of event notification functionality initialisation
+
+ String groupName;
+
+ String description;
+
+ Conservation conserve;
+
+ Conservation conservationData;
+
+ ProfilesI consensusProfiles;
+
+ ProfilesI hmmProfiles;
+
+ boolean displayBoxes = true;
+
+ boolean displayText = true;
+
+ boolean colourText = false;
+
+ /*
+ * true if the group is defined as a group on the alignment, false if it is
+ * just a selection
+ */
+ boolean isDefined = false;
+
+ /*
+ * after Olivier's non-conserved only character display
+ */
+ boolean showNonconserved = false;
+
+ /*
+ * sequences in the group
+ */
+ private List<SequenceI> sequences;
+
+ /*
+ * representative sequence for this group (if any)
+ */
+ private SequenceI seqrep = null;
+
+ int width = -1;
+
+ /*
+ * colour scheme applied to group if any
+ */
+ public ResidueShaderI cs;
+
+ /**
+ * start column (base 0)
+ */
+ private int startRes = 0;
+
+ /**
+ * end column (base 0)
+ */
+ private int endRes = 0;
+
+ public Color outlineColour = Color.black;
+
+ public Color idColour = null;
+
+ public int thresholdTextColour = 0;
+
+ public Color textColour = Color.black;
+
+ public Color textColour2 = Color.white;
+
+ /*
+ * properties for consensus annotation
+ */
+ private boolean ignoreGapsInConsensus = true;
+
+ private boolean showSequenceLogo = false;
+
+ private boolean normaliseSequenceLogo;
+
+ /*
+ * properties for HMM information annotation
+ */
+ private boolean hmmIgnoreBelowBackground = true;
+
+ private boolean hmmUseInfoLetterHeight;
+
+ private boolean hmmShowSequenceLogo;
+
+ private boolean hmmNormaliseSequenceLogo;
+
+ private boolean hmmShowHistogram;
+
+ /*
+ * visibility of rows or represented rows covered by group
+ */
+ private boolean hidereps = false;
+
+ /*
+ * visibility of columns intersecting this group
+ */
+ private boolean hidecols;
+
+ AlignmentAnnotation consensus = null;
+
+ AlignmentAnnotation conservation = null;
+
+ private AlignmentAnnotation hmmInformation;
+
+ private boolean showConsensusHistogram;
+
+ private AnnotatedCollectionI context;
+
+
+ /**
+ * Constructor, assigning a generated default name of "JGroup:" with object
+ * hashcode appended
+ */
+ public SequenceGroup()
+ {
+ groupName = "JGroup:" + this.hashCode();
+ cs = new ResidueShader();
+ sequences = new ArrayList<>();
+ }
+
+ /**
+ * Creates a new SequenceGroup object.
+ *
+ * @param sequences
+ * @param groupName
+ * @param scheme
+ * @param displayBoxes
+ * @param displayText
+ * @param colourText
+ * @param start
+ * first column of group
+ * @param end
+ * last column of group
+ */
+ public SequenceGroup(List<SequenceI> sequences, String groupName,
+ ColourSchemeI scheme, boolean displayBoxes, boolean displayText,
+ boolean colourText, int start, int end)
+ {
+ this();
+ this.sequences = sequences;
+ this.groupName = groupName;
+ this.displayBoxes = displayBoxes;
+ this.displayText = displayText;
+ this.colourText = colourText;
+ this.cs = new ResidueShader(scheme);
+ startRes = start;
+ endRes = end;
+ recalcConservation();
+ }
+
+ /**
+ * copy constructor
+ *
+ * @param seqsel
+ * @param keepsequences
+ * if false do not add sequences from seqsel to new instance
+ */
+ public SequenceGroup(SequenceGroup seqsel)
+ {
+ this();
+
+ if (seqsel != null)
+ {
+ sequences = new ArrayList<>();
+ sequences.addAll(seqsel.sequences);
+ if (seqsel.groupName != null)
+ {
+ groupName = new String(seqsel.groupName);
+ }
+ displayBoxes = seqsel.displayBoxes;
+ displayText = seqsel.displayText;
+ colourText = seqsel.colourText;
+
+ startRes = seqsel.startRes;
+ endRes = seqsel.endRes;
+ cs = new ResidueShader((ResidueShader) seqsel.cs);
+ if (seqsel.description != null)
+ {
+ description = new String(seqsel.description);
+ }
+ hidecols = seqsel.hidecols;
+ hidereps = seqsel.hidereps;
+ showNonconserved = seqsel.showNonconserved;
+ showSequenceLogo = seqsel.showSequenceLogo;
+ normaliseSequenceLogo = seqsel.normaliseSequenceLogo;
+ showConsensusHistogram = seqsel.showConsensusHistogram;
+ hmmShowSequenceLogo = seqsel.hmmShowSequenceLogo;
+ hmmNormaliseSequenceLogo = seqsel.hmmNormaliseSequenceLogo;
+ hmmShowHistogram = seqsel.hmmShowHistogram;
+ idColour = seqsel.idColour;
+ outlineColour = seqsel.outlineColour;
+ seqrep = seqsel.seqrep;
+ textColour = seqsel.textColour;
+ textColour2 = seqsel.textColour2;
+ thresholdTextColour = seqsel.thresholdTextColour;
+ width = seqsel.width;
+ ignoreGapsInConsensus = seqsel.ignoreGapsInConsensus;
+ hmmIgnoreBelowBackground = seqsel.hmmIgnoreBelowBackground;
+ hmmUseInfoLetterHeight = seqsel.hmmUseInfoLetterHeight;
+ if (seqsel.conserve != null)
+ {
+ // todo avoid doing this if we don't actually want derived calculations
+ // !
+ recalcConservation(); // safer than
+ // aaFrequency = (Vector) seqsel.aaFrequency.clone(); // ??
+ }
+ }
+ }
+
+ /**
+ * Constructor that copies the given list of sequences
+ *
+ * @param seqs
+ */
+ public SequenceGroup(List<SequenceI> seqs)
+ {
+ this();
+ this.sequences.addAll(seqs);
+ }
+
+ public boolean isShowSequenceLogo()
+ {
+ return showSequenceLogo;
+ }
+
+ public SequenceI[] getSelectionAsNewSequences(AlignmentI align)
+ {
+ int iSize = sequences.size();
+ SequenceI[] seqs = new SequenceI[iSize];
+ SequenceI[] inorder = getSequencesInOrder(align);
+
+ for (int i = 0, ipos = 0; i < inorder.length; i++)
+ {
+ SequenceI seq = inorder[i];
+
+ seqs[ipos] = seq.getSubSequence(startRes, endRes + 1);
+ if (seqs[ipos] != null)
+ {
+ seqs[ipos].setDescription(seq.getDescription());
+ seqs[ipos].setDBRefs(seq.getDBRefs());
+ seqs[ipos].setSequenceFeatures(seq.getSequenceFeatures());
+ if (seq.getDatasetSequence() != null)
+ {
+ seqs[ipos].setDatasetSequence(seq.getDatasetSequence());
+ }
+
+ if (seq.getAnnotation() != null)
+ {
+ AlignmentAnnotation[] alann = align.getAlignmentAnnotation();
+ // Only copy annotation that is either a score or referenced by the
+ // alignment's annotation vector
+ for (int a = 0; a < seq.getAnnotation().length; a++)
+ {
+ AlignmentAnnotation tocopy = seq.getAnnotation()[a];
+ if (alann != null)
+ {
+ boolean found = false;
+ for (int pos = 0; pos < alann.length; pos++)
+ {
+ if (alann[pos] == tocopy)
+ {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ continue;
+ }
+ }
+ AlignmentAnnotation newannot = new AlignmentAnnotation(
+ seq.getAnnotation()[a]);
+ newannot.restrict(startRes, endRes);
+ newannot.setSequenceRef(seqs[ipos]);
+ newannot.adjustForAlignment();
+ seqs[ipos].addAlignmentAnnotation(newannot);
+ }
+ }
+ ipos++;
+ }
+ else
+ {
+ iSize--;
+ }
+ }
+ if (iSize != inorder.length)
+ {
+ SequenceI[] nseqs = new SequenceI[iSize];
+ System.arraycopy(seqs, 0, nseqs, 0, iSize);
+ seqs = nseqs;
+ }
+ return seqs;
+
+ }
+
+ /**
+ * If sequence ends in gaps, the end residue can be correctly calculated here
+ *
+ * @param seq
+ * SequenceI
+ * @return int
+ */
+ public int findEndRes(SequenceI seq)
+ {
+ int eres = 0;
+ char ch;
+
+ for (int j = 0; j < endRes + 1 && j < seq.getLength(); j++)
+ {
+ ch = seq.getCharAt(j);
+ if (!jalview.util.Comparison.isGap((ch)))
+ {
+ eres++;
+ }
+ }
+
+ if (eres > 0)
+ {
+ eres += seq.getStart() - 1;
+ }
+
+ return eres;
+ }
+
+ @Override
+ public List<SequenceI> getSequences()
+ {
+ return sequences;
+ }
+
+ @Override
+ public List<SequenceI> getSequences(
+ Map<SequenceI, SequenceCollectionI> hiddenReps)
+ {
+ if (hiddenReps == null)
+ {
+ // TODO: need a synchronizedCollection here ?
+ return sequences;
+ }
+ else
+ {
+ List<SequenceI> allSequences = new ArrayList<>();
+ for (SequenceI seq : sequences)
+ {
+ allSequences.add(seq);
+ if (hiddenReps.containsKey(seq))
+ {
+ SequenceCollectionI hsg = hiddenReps.get(seq);
+ for (SequenceI seq2 : hsg.getSequences())
+ {
+ if (seq2 != seq && !allSequences.contains(seq2))
+ {
+ allSequences.add(seq2);
+ }
+ }
+ }
+ }
+
+ return allSequences;
+ }
+ }
+
+ public SequenceI[] getSequencesAsArray(
+ Map<SequenceI, SequenceCollectionI> map)
+ {
+ List<SequenceI> tmp = getSequences(map);
+ if (tmp == null)
+ {
+ return null;
+ }
+ return tmp.toArray(new SequenceI[tmp.size()]);
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param col
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public boolean adjustForRemoveLeft(int col)
+ {
+ // return value is true if the group still exists
+ if (startRes >= col)
+ {
+ startRes = startRes - col;
+ }
+
+ if (endRes >= col)
+ {
+ endRes = endRes - col;
+
+ if (startRes > endRes)
+ {
+ startRes = 0;
+ }
+ }
+ else
+ {
+ // must delete this group!!
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param col
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public boolean adjustForRemoveRight(int col)
+ {
+ if (startRes > col)
+ {
+ // delete this group
+ return false;
+ }
+
+ if (endRes >= col)
+ {
+ endRes = col;
+ }
+
+ return true;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public String getName()
+ {
+ return groupName;
+ }
+
+ public String getDescription()
+ {
+ return description;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param name
+ * DOCUMENT ME!
+ */
+ public void setName(String name)
+ {
+ groupName = name;
+ // TODO: URGENT: update dependent objects (annotation row)
+ }
+
+ public void setDescription(String desc)
+ {
+ description = desc;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public Conservation getConservation()
+ {
+ return conserve;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param c
+ * DOCUMENT ME!
+ */
+ public void setConservation(Conservation c)
+ {
+ conserve = c;
+ }
+
+ /**
+ * Add s to this sequence group. If aligment sequence is already contained in
+ * group, it will not be added again, but recalculation may happen if the flag
+ * is set.
+ *
+ * @param s
+ * alignment sequence to be added
+ * @param recalc
+ * true means Group's conservation should be recalculated
+ */
+ public void addSequence(SequenceI s, boolean recalc)
+ {
+ synchronized (sequences)
+ {
+ if (s != null && !sequences.contains(s))
+ {
+ sequences.add(s);
+ changeSupport.firePropertyChange(SEQ_GROUP_CHANGED,
+ sequences.size() - 1, sequences.size());
+ }
+
+ if (recalc)
+ {
+ recalcConservation();
+ }
+ }
+ }
+
+ /**
+ * Max Gaps Threshold (percent) for performing a conservation calculation
+ */
+ private int consPercGaps = 25;
+
+ /**
+ * @return Max Gaps Threshold for performing a conservation calculation
+ */
+ public int getConsPercGaps()
+ {
+ return consPercGaps;
+ }
+
+ /**
+ * set Max Gaps Threshold (percent) for performing a conservation calculation
+ *
+ * @param consPercGaps
+ */
+ public void setConsPercGaps(int consPercGaps)
+ {
+ this.consPercGaps = consPercGaps;
+ }
+
+ /**
+ * calculate residue conservation and colourschemes for group - but only if
+ * necessary. returns true if the calculation resulted in a visible change to
+ * group
+ */
+ public boolean recalcConservation()
+ {
+ return recalcConservation(false);
+ }
+
+ /**
+ * Recalculates column consensus, conservation, and HMM annotation for the
+ * group (as applicable). Returns true if the calculation resulted in a
+ * visible change to group.
+ *
+ * @param defer
+ * when set, colourschemes for this group are not refreshed after
+ * recalculation
+ */
+ public boolean recalcConservation(boolean defer)
+ {
+ if (cs == null && consensus == null && conservation == null
+ && hmmInformation == null)
+ {
+ return false;
+ }
+ // TODO: try harder to detect changes in state in order to minimise
+ // recalculation effort
+ boolean upd = false;
+ try
+ {
+ ProfilesI cnsns = AAFrequency.calculate(sequences, startRes,
+ endRes + 1, showSequenceLogo);
+ if (hmmInformation != null)
+ {
+ HiddenMarkovModel hmm = hmmInformation.sequenceRef.getHMM();
+
+ ProfilesI info = AAFrequency.calculateHMMProfiles(hmm,
+ (endRes + 1) - startRes, startRes, endRes + 1,
+ hmmIgnoreBelowBackground, hmmUseInfoLetterHeight);
+ _updateInformationRow(info);
+ upd = true;
+ }
+ if (consensus != null)
+ {
+ _updateConsensusRow(cnsns, sequences.size());
+ upd = true;
+ }
+ if (cs != null)
+ {
+ cs.setConsensus(cnsns);
+ upd = true;
+ }
+
+ if ((conservation != null)
+ || (cs != null && cs.conservationApplied()))
+ {
+ Conservation c = new Conservation(groupName, sequences, startRes,
+ endRes + 1);
+ c.calculate();
+ c.verdict(false, consPercGaps);
+ if (conservation != null)
+ {
+ _updateConservationRow(c);
+ }
+ if (cs != null)
+ {
+ if (cs.conservationApplied())
+ {
+ cs.setConservation(c);
+ }
+ }
+ // eager update - will cause a refresh of overview regardless
+ upd = true;
+ }
+ if (cs != null && !defer)
+ {
+ // TODO: JAL-2034 should cs.alignmentChanged modify return state
+ cs.alignmentChanged(context != null ? context : this, null);
+ return true;
+ }
+ else
+ {
+ return upd;
+ }
+ } catch (java.lang.OutOfMemoryError err)
+ {
+ // TODO: catch OOM
+ System.out.println("Out of memory loading groups: " + err);
+ }
+ return upd;
+ }
+
+ private void _updateConservationRow(Conservation c)
+ {
+ if (conservation == null)
+ {
+ getConservation();
+ }
+ // update Labels
+ conservation.label = "Conservation for " + getName();
+ conservation.description = "Conservation for group " + getName()
+ + " less than " + consPercGaps + "% gaps";
+ // preserve width if already set
+ int aWidth = (conservation.annotations != null)
+ ? (endRes < conservation.annotations.length
+ ? conservation.annotations.length
+ : endRes + 1)
+ : endRes + 1;
+ conservation.annotations = null;
+ conservation.annotations = new Annotation[aWidth]; // should be alignment
+ // width
+ c.completeAnnotations(conservation, null, startRes, endRes + 1);
+ }
+
+ public ProfilesI consensusData = null;
+
+ private void _updateConsensusRow(ProfilesI cnsns, long nseq)
+ {
+ if (consensus == null)
+ {
+ getConsensus();
+ }
+ consensus.label = "Consensus for " + getName();
+ consensus.description = "Percent Identity";
+ consensusData = cnsns;
+ // preserve width if already set
+ int aWidth = (consensus.annotations != null)
+ ? (endRes < consensus.annotations.length
+ ? consensus.annotations.length
+ : endRes + 1)
+ : endRes + 1;
+ consensus.annotations = null;
+ consensus.annotations = new Annotation[aWidth]; // should be alignment width
+
+ AAFrequency.completeConsensus(consensus, cnsns, startRes, endRes + 1,
+ ignoreGapsInConsensus, showSequenceLogo, nseq); // TODO: setting
+ // container
+ // for
+ // ignoreGapsInConsensusCalculation);
+ }
+
+ /**
+ * Recalculates the information content on the HMM annotation
+ *
+ * @param cnsns
+ */
+ private void _updateInformationRow(ProfilesI cnsns)
+ {
+ if (hmmInformation == null)
+ {
+ createInformationAnnotation();
+ }
+ hmmInformation.description = MessageManager
+ .getString("label.information_description");
+ setHmmProfiles(cnsns);
+ // preserve width if already set
+ int aWidth = (hmmInformation.annotations != null)
+ ? (endRes < hmmInformation.annotations.length
+ ? hmmInformation.annotations.length : endRes + 1)
+ : endRes + 1;
+ hmmInformation.annotations = null;
+ hmmInformation.annotations = new Annotation[aWidth]; // should be alignment
+ // width
+ hmmInformation.setCalcId(InformationThread.HMM_CALC_ID);
+ AAFrequency.completeInformation(hmmInformation, cnsns, startRes,
+ endRes + 1);
+ }
+
+ /**
+ * @param s
+ * sequence to either add or remove from group
+ * @param recalc
+ * flag passed to delete/addSequence to indicate if group properties
+ * should be recalculated
+ */
+ public void addOrRemove(SequenceI s, boolean recalc)
+ {
+ synchronized (sequences)
+ {
+ if (sequences.contains(s))
+ {
+ deleteSequence(s, recalc);
+ }
+ else
+ {
+ addSequence(s, recalc);
+ }
+ }
+ }
+
+ /**
+ * remove
+ *
+ * @param s
+ * to be removed
+ * @param recalc
+ * true means recalculate conservation
+ */
+ public void deleteSequence(SequenceI s, boolean recalc)
+ {
+ synchronized (sequences)
+ {
+ sequences.remove(s);
+ changeSupport.firePropertyChange(SEQ_GROUP_CHANGED,
+ sequences.size() + 1, sequences.size());
+
+ if (recalc)
+ {
+ recalcConservation();
+ }
+ }
+ }
+
+ /**
+ *
+ *
+ * @return the first column selected by this group. Runs from 0<=i<N_cols
+ */
+ @Override
+ public int getStartRes()
+ {
+ return startRes;
+ }
+
+ /**
+ *
+ * @return the groups last selected column. Runs from 0<=i<N_cols
+ */
+ @Override
+ public int getEndRes()
+ {
+ return endRes;
+ }
+
+ /**
+ * Set the first column selected by this group. Runs from 0<=i<N_cols
+ *
+ * @param newStart
+ */
+ public void setStartRes(int newStart)
+ {
+ int before = startRes;
+ startRes= Math.max(0,newStart); // sanity check for negative start column positions
+ changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, startRes);
+
+
+
+ }
+
+ /**
+ * Set the groups last selected column. Runs from 0<=i<N_cols
+ *
+ * @param i
+ */
+ public void setEndRes(int i)
+ {
+ int before = endRes;
+ endRes = i;
+ changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, endRes);
+ }
+
+ /**
+ * @return number of sequences in group
+ */
+ public int getSize()
+ {
+ return sequences.size();
+ }
+
+ /**
+ * @param i
+ * @return the ith sequence
+ */
+ public SequenceI getSequenceAt(int i)
+ {
+ return sequences.get(i);
+ }
+
+ /**
+ * @param state
+ * colourText
+ */
+ public void setColourText(boolean state)
+ {
+ colourText = state;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public boolean getColourText()
+ {
+ return colourText;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param state
+ * DOCUMENT ME!
+ */
+ public void setDisplayText(boolean state)
+ {
+ displayText = state;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public boolean getDisplayText()
+ {
+ return displayText;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param state
+ * DOCUMENT ME!
+ */
+ public void setDisplayBoxes(boolean state)
+ {
+ displayBoxes = state;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public boolean getDisplayBoxes()
+ {
+ return displayBoxes;
+ }
+
+ /**
+ * computes the width of current set of sequences and returns it
+ *
+ * @return DOCUMENT ME!
+ */
+ @Override
+ public int getWidth()
+ {
+ synchronized (sequences)
+ {
+ // MC This needs to get reset when characters are inserted and deleted
+ boolean first = true;
+ for (SequenceI seq : sequences)
+ {
+ if (first || seq.getLength() > width)
+ {
+ width = seq.getLength();
+ first = false;
+ }
+ }
+ return width;
+ }
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @param c
+ * DOCUMENT ME!
+ */
+ public void setOutlineColour(Color c)
+ {
+ outlineColour = c;
+ }
+
+ /**
+ * DOCUMENT ME!
+ *
+ * @return DOCUMENT ME!
+ */
+ public Color getOutlineColour()
+ {
+ return outlineColour;
+ }
+
+ /**
+ *
+ * returns the sequences in the group ordered by the ordering given by al.
+ * this used to return an array with null entries regardless, new behaviour is
+ * below. TODO: verify that this does not affect use in applet or application
+ *
+ * @param al
+ * Alignment
+ * @return SequenceI[] intersection of sequences in group with al, ordered by
+ * al, or null if group does not intersect with al
+ */
+ public SequenceI[] getSequencesInOrder(AlignmentI al)
+ {
+ return getSequencesInOrder(al, true);
+ }
+
+ /**
+ * return an array representing the intersection of the group with al,
+ * optionally returning an array the size of al.getHeight() where nulls mark
+ * the non-intersected sequences
+ *
+ * @param al
+ * @param trim
+ * @return null or array
+ */
+ public SequenceI[] getSequencesInOrder(AlignmentI al, boolean trim)
+ {
+ synchronized (sequences)
+ {
+ int sSize = sequences.size();
+ int alHeight = al.getHeight();
+
+ SequenceI[] seqs = new SequenceI[(trim) ? sSize : alHeight];
+
+ int index = 0;
+ for (int i = 0; i < alHeight && index < sSize; i++)
+ {
+ if (sequences.contains(al.getSequenceAt(i)))
+ {
+ seqs[(trim) ? index : i] = al.getSequenceAt(i);
+ index++;
+ }
+ }
+ if (index == 0)
+ {
+ return null;
+ }
+ if (!trim)
+ {
+ return seqs;
+ }
+ if (index < seqs.length)
+ {
+ SequenceI[] dummy = seqs;
+ seqs = new SequenceI[index];
+ while (--index >= 0)
+ {
+ seqs[index] = dummy[index];
+ dummy[index] = null;
+ }
+ }
+ return seqs;
+ }
+ }
+
+ /**
+ * @return the idColour
+ */
+ public Color getIdColour()
+ {
+ return idColour;
+ }
+
+ /**
+ * @param idColour
+ * the idColour to set
+ */
+ public void setIdColour(Color idColour)
+ {
+ this.idColour = idColour;
+ }
+
+ /**
+ * @return the representative sequence for this group
+ */
+ @Override
+ public SequenceI getSeqrep()
+ {
+ return seqrep;
+ }
+
+ /**
+ * set the representative sequence for this group. Note - this affects the
+ * interpretation of the Hidereps attribute.
+ *
+ * @param seqrep
+ * the seqrep to set (null means no sequence representative)
+ */
+ @Override
+ public void setSeqrep(SequenceI seqrep)
+ {
+ this.seqrep = seqrep;
+ }
+
+ /**
+ *
+ * @return true if group has a sequence representative
+ */
+ @Override
+ public boolean hasSeqrep()
+ {
+ return seqrep != null;
+ }
+
+ /**
+ * set visibility of sequences covered by (if no sequence representative is
+ * defined) or represented by this group.
+ *
+ * @param visibility
+ */
+ public void setHidereps(boolean visibility)
+ {
+ hidereps = visibility;
+ }
+
+ /**
+ *
+ * @return true if sequences represented (or covered) by this group should be
+ * hidden
+ */
+ public boolean isHidereps()
+ {
+ return hidereps;
+ }
+
+ /**
+ * set intended visibility of columns covered by this group
+ *
+ * @param visibility
+ */
+ public void setHideCols(boolean visibility)
+ {
+ hidecols = visibility;
+ }
+
+ /**
+ *
+ * @return true if columns covered by group should be hidden
+ */
+ public boolean isHideCols()
+ {
+ return hidecols;
+ }
+
+ /**
+ * create a new sequence group from the intersection of this group with an
+ * alignment Hashtable of hidden representatives
+ *
+ * @param alignment
+ * (may not be null)
+ * @param map
+ * (may be null)
+ * @return new group containing sequences common to this group and alignment
+ */
+ public SequenceGroup intersect(AlignmentI alignment,
+ Map<SequenceI, SequenceCollectionI> map)
+ {
+ SequenceGroup sgroup = new SequenceGroup(this);
+ SequenceI[] insect = getSequencesInOrder(alignment);
+ sgroup.sequences = new ArrayList<>();
+ for (int s = 0; insect != null && s < insect.length; s++)
+ {
+ if (map == null || map.containsKey(insect[s]))
+ {
+ sgroup.sequences.add(insect[s]);
+ }
+ }
+ return sgroup;
+ }
+
+ /**
+ * @return the showUnconserved
+ */
+ public boolean getShowNonconserved()
+ {
+ return showNonconserved;
+ }
+
+ /**
+ * @param showNonconserved
+ * the showUnconserved to set
+ */
+ public void setShowNonconserved(boolean displayNonconserved)
+ {
+ this.showNonconserved = displayNonconserved;
+ }
+
+ /**
+ * set this alignmentAnnotation object as the one used to render consensus
+ * annotation
+ *
+ * @param aan
+ */
+ public void setConsensus(AlignmentAnnotation aan)
+ {
+ if (consensus == null)
+ {
+ consensus = aan;
+ }
+ }
+
+ /**
+ *
+ * @return automatically calculated consensus row note: the row is a stub if a
+ * consensus calculation has not yet been performed on the group
+ */
+ public AlignmentAnnotation getConsensus()
+ {
+ // TODO get or calculate and get consensus annotation row for this group
+ int aWidth = this.getWidth();
+ // pointer
+ // possibility
+ // here.
+ if (aWidth < 0)
+ {
+ return null;
+ }
+ if (consensus == null)
+ {
+ consensus = new AlignmentAnnotation("", "", new Annotation[1], 0f,
+ 100f, AlignmentAnnotation.BAR_GRAPH);
+ consensus.hasText = true;
+ consensus.autoCalculated = true;
+ consensus.groupRef = this;
+ consensus.label = "Consensus for " + getName();
+ consensus.description = "Percent Identity";
+ }
+ return consensus;
+ }
+
+ /**
+ * Creates the Hidden Markov Model annotation for this group
+ */
+ void createInformationAnnotation()
+ {
+ hmmInformation = new AlignmentAnnotation("", "", new Annotation[1], 0f,
+ 6.25f, AlignmentAnnotation.BAR_GRAPH);
+ hmmInformation.hasText = true;
+ hmmInformation.autoCalculated = false;
+ hmmInformation.groupRef = this;
+ hmmInformation.label = getName();
+ hmmInformation.description = MessageManager
+ .getString("label.information_description");
+ hmmInformation.setCalcId(InformationThread.HMM_CALC_ID);
+ }
+
+ /**
+ * set this alignmentAnnotation object as the one used to render consensus
+ * annotation
+ *
+ * @param aan
+ */
+ public void setConservationRow(AlignmentAnnotation aan)
+ {
+ if (conservation == null)
+ {
+ conservation = aan;
+ }
+ }
+
+ /**
+ * get the conservation annotation row for this group
+ *
+ * @return autoCalculated annotation row
+ */
+ public AlignmentAnnotation getConservationRow()
+ {
+ if (conservation == null)
+ {
+ conservation = new AlignmentAnnotation("", "", new Annotation[1], 0f,
+ 11f, AlignmentAnnotation.BAR_GRAPH);
+ }
+
+ conservation.hasText = true;
+ conservation.autoCalculated = true;
+ conservation.groupRef = this;
+ conservation.label = "Conservation for " + getName();
+ conservation.description = "Conservation for group " + getName()
+ + " less than " + consPercGaps + "% gaps";
+ return conservation;
+ }
+
+ /**
+ *
+ * @return true if annotation rows have been instantiated for this group
+ */
+ public boolean hasAnnotationRows()
+ {
+ return consensus != null || conservation != null;
+ }
+
+ public SequenceI getConsensusSeq()
+ {
+ getConsensus();
+ StringBuffer seqs = new StringBuffer();
+ for (int i = 0; i < consensus.annotations.length; i++)
+ {
+ if (consensus.annotations[i] != null)
+ {
+ String desc = consensus.annotations[i].description;
+ if (desc.length() > 1 && desc.charAt(0) == '[')
+ {
+ seqs.append(desc.charAt(1));
+ }
+ else
+ {
+ seqs.append(consensus.annotations[i].displayCharacter);
+ }
+ }
+ }
+
+ SequenceI sq = new Sequence("Group" + getName() + " Consensus",
+ seqs.toString());
+ sq.setDescription("Percentage Identity Consensus "
+ + ((ignoreGapsInConsensus) ? " without gaps" : ""));
+ return sq;
+ }
+
+ public void setIgnoreGapsConsensus(boolean state)
+ {
+ if (this.ignoreGapsInConsensus != state && consensus != null)
+ {
+ ignoreGapsInConsensus = state;
+ recalcConservation();
+ }
+ ignoreGapsInConsensus = state;
+ }
+
+ public boolean getIgnoreGapsConsensus()
+ {
+ return ignoreGapsInConsensus;
+ }
+
+ public void setIgnoreBelowBackground(boolean state)
+ {
+ hmmIgnoreBelowBackground = state;
+ }
+
+ public boolean isIgnoreBelowBackground()
+ {
+ return hmmIgnoreBelowBackground;
+ }
+
+ public void setInfoLetterHeight(boolean state)
+ {
+ hmmUseInfoLetterHeight = state;
+ }
+
+ public boolean isUseInfoLetterHeight()
+ {
+ return hmmUseInfoLetterHeight;
+ }
+
+ /**
+ * @param showSequenceLogo
+ * indicates if a sequence logo is shown for consensus annotation
+ */
+ public void setshowSequenceLogo(boolean showSequenceLogo)
+ {
+ // TODO: decouple calculation from settings update
+ if (this.showSequenceLogo != showSequenceLogo && consensus != null)
+ {
+ this.showSequenceLogo = showSequenceLogo;
+ recalcConservation();
+ }
+ this.showSequenceLogo = showSequenceLogo;
+ }
+
+ /**
+ *
+ * @param showConsHist
+ * flag indicating if the consensus histogram for this group should
+ * be rendered
+ */
+ public void setShowConsensusHistogram(boolean showConsHist)
+ {
+
+ if (showConsensusHistogram != showConsHist && consensus != null)
+ {
+ this.showConsensusHistogram = showConsHist;
+ recalcConservation();
+ }
+ this.showConsensusHistogram = showConsHist;
+ }
+
+ /**
+ * @return the showConsensusHistogram
+ */
+ public boolean isShowConsensusHistogram()
+ {
+ return showConsensusHistogram;
+ }
+
+ /**
+ * set flag indicating if logo should be normalised when rendered
+ *
+ * @param norm
+ */
+ public void setNormaliseSequenceLogo(boolean norm)
+ {
+ normaliseSequenceLogo = norm;
+ }
+
+ public boolean isNormaliseSequenceLogo()
+ {
+ return normaliseSequenceLogo;
+ }
+
+ @Override
+ /**
+ * returns a new array with all annotation involving this group
+ */
+ public AlignmentAnnotation[] getAlignmentAnnotation()
+ {
+ // TODO add in other methods like 'getAlignmentAnnotation(String label),
+ // etc'
+ ArrayList<AlignmentAnnotation> annot = new ArrayList<>();
+ synchronized (sequences)
+ {
+ for (SequenceI seq : sequences)
+ {
+ AlignmentAnnotation[] aa = seq.getAnnotation();
+ if (aa != null)
+ {
+ for (AlignmentAnnotation al : aa)
+ {
+ if (al.groupRef == this)
+ {
+ annot.add(al);
+ }
+ }
+ }
+ }
+ if (consensus != null)
+ {
+ annot.add(consensus);
+ }
+ if (conservation != null)
+ {
+ annot.add(conservation);
+ }
+ }
+ return annot.toArray(new AlignmentAnnotation[0]);
+ }
+
+ @Override
+ public Iterable<AlignmentAnnotation> findAnnotation(String calcId)
+ {
+ return AlignmentAnnotation.findAnnotation(
+ Arrays.asList(getAlignmentAnnotation()), calcId);
+ }
+
+ @Override
+ public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
+ String calcId, String label)
+ {
+ return AlignmentAnnotation.findAnnotations(
+ Arrays.asList(getAlignmentAnnotation()), seq, calcId, label);
+ }
+
+ /**
+ * Answer true if any annotation matches the calcId passed in (if not null).
+ *
+ * @param calcId
+ * @return
+ */
+ public boolean hasAnnotation(String calcId)
+ {
+ return AlignmentAnnotation
+ .hasAnnotation(Arrays.asList(getAlignmentAnnotation()), calcId);
+ }
+
+ /**
+ * Remove all sequences from the group (leaving other properties unchanged).
+ */
+ public void clear()
+ {
+ synchronized (sequences)
+ {
+ int before = sequences.size();
+ sequences.clear();
+ changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before,
+ sequences.size());
+ }
+ }
+
+ /**
+ * Sets the alignment or group context for this group, and whether it is
+ * defined as a group
+ *
+ * @param ctx
+ * the context for the group
+ * @param defined
+ * whether the group is defined on the alignment or is just a
+ * selection
+ * @throws IllegalArgumentException
+ * if setting the context would result in a circular reference chain
+ */
+ public void setContext(AnnotatedCollectionI ctx, boolean defined)
+ {
+ setContext(ctx);
+ this.isDefined = defined;
+ }
+
+ /**
+ * Sets the alignment or group context for this group
+ *
+ * @param ctx
+ * the context for the group
+ * @throws IllegalArgumentException
+ * if setting the context would result in a circular reference chain
+ */
+ public void setContext(AnnotatedCollectionI ctx)
+ {
+ AnnotatedCollectionI ref = ctx;
+ while (ref != null)
+ {
+ if (ref == this || ref.getContext() == ctx)
+ {
+ throw new IllegalArgumentException(
+ "Circular reference in SequenceGroup.context");
+ }
+ ref = ref.getContext();
+ }
+ this.context = ctx;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see jalview.datamodel.AnnotatedCollectionI#getContext()
+ */
+ @Override
+ public AnnotatedCollectionI getContext()
+ {
+ return context;
+ }
+
+ public boolean isDefined()
+ {
+ return isDefined;
+ }
+
+ public void setColourScheme(ColourSchemeI scheme)
+ {
+ if (cs == null)
+ {
+ cs = new ResidueShader();
+ }
+ cs.setColourScheme(scheme);
+ }
+
+ public void setGroupColourScheme(ResidueShaderI scheme)
+ {
+ cs = scheme;
+ }
+
+ public ColourSchemeI getColourScheme()
+ {
+ return cs == null ? null : cs.getColourScheme();
+ }
+
+ public ResidueShaderI getGroupColourScheme()
+ {
+ return cs;
+ }
+
+ @Override
+ public boolean isNucleotide()
+ {
+ if (context != null)
+ {
+ return context.isNucleotide();
+ }
+ return false;
+ }
+
+ /**
+ * @param seq
+ * @return true if seq is a member of the group
+ */
+
+ public boolean contains(SequenceI seq1)
+ {
+ return sequences.contains(seq1);
+ }
+
+ /**
+ * @param seq
+ * @param apos
+ * @return true if startRes<=apos and endRes>=apos and seq is in the group
+ */
+ public boolean contains(SequenceI seq, int apos)
+ {
+ return (startRes <= apos && endRes >= apos) && sequences.contains(seq);
+ }
+
+ public boolean isShowInformationHistogram()
+ {
+ return hmmShowHistogram;
+ }
+
+ public void setShowInformationHistogram(boolean state)
+ {
+ if (hmmShowHistogram != state && hmmInformation != null)
+ {
+ this.hmmShowHistogram = state;
+ // recalcConservation(); TODO don't know what to do here next
+ }
+ this.hmmShowHistogram = state;
+ }
+
+ public boolean isShowHMMSequenceLogo()
+ {
+ return hmmShowSequenceLogo;
+ }
+
+ public void setShowHMMSequenceLogo(boolean state)
+ {
+ hmmShowSequenceLogo = state;
+ }
+
+ public boolean isNormaliseHMMSequenceLogo()
+ {
+ return hmmNormaliseSequenceLogo;
+ }
+
+ public void setNormaliseHMMSequenceLogo(boolean state)
+ {
+ hmmNormaliseSequenceLogo = state;
+ }
+
+ public ProfilesI getConsensusData()
+ {
+ return consensusProfiles;
+ }
+
+ public ProfilesI getHmmProfiles()
+ {
+ return hmmProfiles;
+ }
+
+ public void setHmmProfiles(ProfilesI hmmProfiles)
+ {
+ this.hmmProfiles = hmmProfiles;
+ }
+
+ @Override
+ public List<SequenceI> getHmmSequences()
+ {
+ List<SequenceI> result = new ArrayList<>();
+ for (int i = 0; i < sequences.size(); i++)
+ {
+ SequenceI seq = sequences.get(i);
+ if (seq.hasHMMProfile())
+ {
+ result.add(seq);
+ }
+ }
+ return result;
+ }
+
+}